Ved ny versjon av lydfil: flytt has_media-edge til ny fil, derived_from-edge bevarer historikk, gammel fil mister aktive edges og prunes etter 30 dager (konfigurerbart for RSS-cache). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.7 KiB
Feature: Podcast-hosting — komplett, uten ekstern avhengighet
Konsept
Synops hoster podcast selv — ingen castopod, ingen ekstern tjeneste. Podcasten er noder med riktige edges og en RSS-feed med riktige tags. Vi har 80% allerede.
Hva vi har
| Funksjon | Status | Komponent |
|---|---|---|
| RSS-feed | ✓ | synops-rss |
| Mediefiler med byte-range | ✓ | CAS + Caddy |
| HTML-sider per episode | ✓ | synops-render + Tera |
| Metadata | ✓ | Noder med edges |
| Transkripsjoner | ✓ | synops-transcribe + segmenter |
| Kapitler | ✓ | chapter-edges |
| Show notes | ✓ | show_notes-edge |
| Lydprosessering | ✓ | synops-audio |
Hva vi mangler
1. Podcast-spesifikke RSS-tags
Utvid synops-rss med iTunes og Podcasting 2.0 namespace:
<itunes:author>Sidelinja</itunes:author>
<itunes:category text="News & Politics"/>
<itunes:explicit>false</itunes:explicit>
<itunes:image href="https://synops.no/media/artwork.jpg"/>
<podcast:locked>no</podcast:locked>
<podcast:transcript url="https://synops.no/pub/sidelinja/ep42.srt"
type="application/srt"/>
<podcast:chapters url="https://synops.no/pub/sidelinja/ep42-chapters.json"
type="application/json+chapters"/>
Metadata fra samlingens podcast-trait:
{
"traits": {
"podcast": {
"itunes_category": "News & Politics",
"itunes_author": "Sidelinja",
"explicit": false,
"language": "no",
"redirect_feed": null
}
}
}
2. Nedlastingsstatistikk
Caddy logger allerede alle requests. synops-stats parser
loggene og aggregerer:
synops-stats --collection-id <uuid> --period 30d
→ Nedlastinger per episode per dag
→ Unike lyttere (IP + user-agent per 24t, IAB-regler)
→ Geografi (fra IP, valgfritt)
→ Klienter (Apple Podcasts, Spotify, etc. fra user-agent)
Lagres i PG — visbart i admin-dashboard.
3. Embed-spiller
Liten Svelte-komponent for å embedde episoder på nettsider:
<iframe src="https://synops.no/pub/sidelinja/ep42/player"
width="100%" height="180" frameborder="0"></iframe>
Viser: artwork, tittel, play/pause, progress, waveform, kapittelmerkering. Responsivt. Fungerer uten JavaScript (fallback til lydfil-lenke).
4. Katalog-distribusjon
Apple Podcasts, Spotify, Google Podcasts trenger bare RSS-URL-en. Submit én gang manuelt, de poller feeden.
Admin-UI: felt for å lime inn RSS-URL og se status per katalog (submitted/live/pending).
Import fra annen host
synops-import-podcast
CLI-verktøy som importerer en eksisterende podcast fra RSS-feed:
synops-import-podcast --feed-url https://gammel-host.no/feed.xml \
--collection-id <uuid> \
[--dry-run] \
[--write]
For hver episode:
- Parse metadata fra RSS (tittel, beskrivelse, pubDate, etc.)
- Last ned MP3 → CAS (deduplisering gratis)
- Last ned artwork → CAS
- Last ned transkripsjon/kapitler hvis tilgjengelig
- Opprett content-node med all metadata
- Opprett media-node + has_media-edge
- Opprett belongs_to-edge → samling
- Sett published_at fra pubDate
Podcast-metadata (author, category, artwork) → samlingens podcast-trait.
Prøveimport-flyten
Import er ikke alt-eller-ingenting. Den støtter en gradvis migrasjon:
Uke 1: Prøveimport
synops-import-podcast --feed-url https://gammel.no/feed.xml \
--collection-id <uuid> --write
→ Alle episoder importert
→ Sjekk at alt ser riktig ut i Synops
→ Prøvepubliser RSS-feed: synops.no/pub/sidelinja/feed.xml
→ Sammenlign med original feed
→ Hør på noen episoder, sjekk metadata
→ Ikke fornøyd? Slett samlingen, start på nytt
Uke 2: Test med lyttere
→ Del den nye feed-URL-en med noen testlyttere
→ Sjekk at spillere (Apple, Spotify) håndterer den
→ Publiser en ny episode direkte i Synops
Uke 3: Restimorter + cutover
synops-import-podcast --feed-url https://gammel.no/feed.xml \
--collection-id <uuid> --write
→ Idempotent: eksisterende episoder skippes (duplikatdeteksjon via guid)
→ Nye episoder siden sist importeres
→ Slå på 301 redirect på gammel host
→ Apple/Spotify oppdaterer automatisk innen noen dager
→ Ferdig — podcasten lever nå i Synops
Duplikatdeteksjon
Import bruker <guid> fra RSS for å identifisere episoder.
Kjørt to ganger = ingen duplikater. Bare nye episoder
importeres.
Hva importeres
| RSS-felt | Synops |
|---|---|
<title> |
node.title |
<description> |
node.content |
<enclosure url> |
media-node i CAS |
<pubDate> |
metadata.published_at |
<itunes:duration> |
metadata.duration |
<itunes:episode> |
metadata.episode_number |
<itunes:season> |
metadata.season_number |
<itunes:image> |
media-node + og_image-edge |
<podcast:transcript> |
last ned → synops-transcribe parsing |
<podcast:chapters> |
chapter-edges |
<guid> |
metadata.guid (for duplikatdeteksjon) |
Erstatning av lydfiler (re-publisering)
Når en episode re-publiseres med ny lydfil (f.eks. etter redigering i lydstudioet):
1. Opprett ny media-node i CAS
2. Opprett derived_from-edge (ny → gammel)
3. Flytt has_media-edge fra gammel fil → ny fil
4. Gammel fil: ingen aktive edges → pruning-kandidat
5. Grace period: 30 dager (konfigurerbart)
→ RSS-cacher hos Apple/Spotify trenger tid til å oppdatere
6. Etter grace period: gammel fil prunes fra CAS
Den gamle filen har derived_from-edge innover (ny peker
på gammel) men ingen has_media-edge utover. Den er
historikk, ikke aktiv innhold.
Noden lever videre som tombstone — metadata bevares,
binærfilen slettes fra disk. Historikken er sporbar via
derived_from-kjeden.
Eksport / flytte bort
Brukeren eier dataene sine. Flytte bort er enkelt:
// I podcast-trait:
{
"redirect_feed": "https://ny-host.no/feed.xml"
}
Når satt: Caddy returnerer 301 for feed-URL. Apple/Spotify oppdaterer automatisk.
Brukeren kan også eksportere all data:
- RSS-feed med alle episoder
- Lydfiler fra CAS
- Transkripsjoner, kapitler, show notes
Alt er noder → alt er eksporterbart.
Komponenter
| Feature | Rolle |
|---|---|
| synops-rss | RSS-generering med iTunes/Podcasting 2.0 tags |
| synops-import-podcast | Import fra eksisterende RSS-feed |
| synops-stats | Nedlastingsstatistikk fra Caddy-logger |
| CAS + Caddy | Mediaserving med byte-range |
| synops-render | Episode-sider og embed-spiller |
| Admin-UI | Katalogstatus, statistikk, redirect-konfig |
Bygger på
docs/concepts/podcastfabrikken.md— produksjonspipelinedocs/concepts/studioet.md— innspillingdocs/proposals/podcasting_2_0.md— Podcasting 2.0 tagsdocs/features/lydstudio.md— postproduksjon