/podcast viser familiens podcasts (Slægtens Stemmer) med afspiller og en abonnér-knap til Apple Podcasts, Overcast, Pocket Casts og AntennaPod. Podcast- apps kan ikke logge ind med Authentik, så hver lytter får sin egen hemmelige nøgle i adressen (/podcast/<nøgle>/<show>.xml); mp3-filer og omslag ligger under samme nøgle. En nøgle kan trækkes tilbage i /admin/podcast uden at de andre mærker det, og admin ser hvem der henter hvad. Episoder kan ligge som kladde: så ses de kun af administratorer, også i deres eget feed, indtil de udgives fra admin-siden. Adgang: gruppen PODCAST_GROUP (standard Familie) og admins. Forsiden får et kort, når der er episoder. Data ligger i DATA/podcast/ og kommer aldrig i git. mutagen læser varigheden. Claude-Session: https://claude.ai/code/session_012LCTmU2ewo8tnM1dByYAoG
70 lines
3.5 KiB
HTML
70 lines
3.5 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Admin — podcast{% endblock %}
|
||
{% block body %}
|
||
<p><a href="/admin" class="wt-muted">← Admin</a></p>
|
||
<h1>Podcast</h1>
|
||
<p class="wt-lead">Kladder ses kun af administratorer, også i deres podcast-app. Udgiv en episode, når den er klar til familien. Lytternes adresser er personlige; trækker du en tilbage, holder den op med at virke, og de andre mærker intet. Personen får en ny adresse næste gang de åbner siden, så længe de er i gruppen Familie; skal nogen helt ud, så fjern dem fra gruppen i Authentik. Siden for familien er <a href="/podcast">/podcast</a>.</p>
|
||
{% if saved %}<div class="wt-flash">{{ saved }}</div>{% endif %}
|
||
|
||
{% for u in udsendelser %}
|
||
<h2 style="font-size:1.15rem;margin-top:1.6rem">{{ u.titel }}</h2>
|
||
<table class="wt-table">
|
||
<thead><tr><th>Nr</th><th>Titel</th><th>Varighed</th><th>Status</th><th></th></tr></thead>
|
||
<tbody>
|
||
{% for e in u.episoder %}
|
||
<tr>
|
||
<td>{{ e.nr }}</td>
|
||
<td>{{ e.titel }}<div class="wt-muted" style="font-size:.8rem">{{ e.slug }}.mp3 · {{ (e.bytes / 1048576) | round(1) }} MB</div></td>
|
||
<td>{{ (e.varighed // 60) }}:{{ '%02d' % (e.varighed % 60) }}</td>
|
||
<td>{% if e.kladde %}Kladde{% else %}Udgivet {{ (e.udgivet or '')[:10] }}{% endif %}</td>
|
||
<td>
|
||
<form method="post" action="/admin/podcast/{{ u.slug }}/{{ e.slug }}/udgiv" style="margin:0">
|
||
{% if e.kladde %}
|
||
<button class="wt-btn wt-btn--primary" type="submit">Udgiv</button>
|
||
{% else %}
|
||
<input type="hidden" name="kladde" value="1"><button class="wt-btn" type="submit">Gør til kladde</button>
|
||
{% endif %}
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
{% else %}
|
||
<tr><td colspan="5" class="wt-muted">Ingen episoder. Udgiv med publish.py i skillen slaegtens-stemmer.</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
{% endfor %}
|
||
|
||
<h2 style="font-size:1.15rem;margin-top:2rem">Lytternes adresser</h2>
|
||
<table class="wt-table">
|
||
<thead><tr><th>Bruger</th><th>Oprettet</th><th>Sidst hentet</th><th>Hentninger</th><th>App</th><th></th></tr></thead>
|
||
<tbody>
|
||
{% for k in noegler %}
|
||
<tr{% if k.tilbagekaldt %} style="opacity:.55"{% endif %}>
|
||
<td>{{ k.user }}{% if k.admin %} <span class="wt-muted">(admin)</span>{% endif %}</td>
|
||
<td data-ts="{{ k.oprettet }}"></td>
|
||
<td data-ts="{{ k.sidst or '' }}"></td>
|
||
<td title="{% for h, n in (k.hentet or {}).items() %}{{ h }}: {{ n }} {% endfor %}">{{ k.hentninger or 0 }}</td>
|
||
<td class="wt-muted" style="font-size:.8rem;max-width:16rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ k.sidst_ua or '' }}</td>
|
||
<td>
|
||
<form method="post" action="/admin/podcast/noegle/{{ k.key }}" style="margin:0">
|
||
{% if k.tilbagekaldt %}
|
||
<input type="hidden" name="aktiv" value="1"><button class="wt-btn" type="submit">Genaktivér</button>
|
||
{% else %}
|
||
<button class="wt-btn" type="submit" onclick="return confirm('Træk {{ k.user }}s adresse tilbage?')">Træk tilbage</button>
|
||
{% endif %}
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
{% else %}
|
||
<tr><td colspan="6" class="wt-muted">Ingen endnu. En lytter får sin adresse første gang de åbner /podcast.</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
<script>
|
||
document.querySelectorAll('[data-ts]').forEach(function (td) {
|
||
var t = parseInt(td.dataset.ts, 10);
|
||
td.textContent = t ? new Date(t * 1000).toLocaleString('da-DK', { dateStyle: 'short', timeStyle: 'short' }) : '–';
|
||
});
|
||
</script>
|
||
{% endblock %}
|