- Feeds liefern jetzt Podlove-Kapitel (psc:chapters), Podcasting-2.0-Kapitel (podcast:chapters, JSON-URL) und Transkripte (podcast:transcript, auch mehrere); als Beschreibung wird content:encoded bevorzugt. - Bekannte Folgen werden beim Aktualisieren nachgezogen, aber nur die Zeilen, die sich wirklich geändert haben. - Neuer Endpunkt GET /podcasts/episodes/<id>/ mit bereinigten Shownotes, Zeitmarken, Kapiteln, Transkripten und Fortschritt. JSON-Kapitel werden einmal serverseitig geholt (nur öffentliche Adressen, max. 1 MB) und an der Folge gespeichert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
43 lines
1.7 KiB
Python
43 lines
1.7 KiB
Python
"""Teach feedparser the Podcasting 2.0 tags we read.
|
|
|
|
feedparser 6 doesn't know the podcast namespace. Unknown tags still come
|
|
through, but only under whatever prefix the feed happened to declare, and an
|
|
unknown tag with attributes is stored as a single dict, so a second
|
|
<podcast:transcript> overwrites the first. Registering the namespace fixes the
|
|
prefix ("podcast_…" for every feed); the handler below keeps every
|
|
transcript in a list, entry["podcast_transcripts"].
|
|
|
|
podcast:chapters is left to feedparser's default handling, which gives
|
|
entry["podcast_chapters"] = {"url": …, "type": …} (one per item, as the spec
|
|
says).
|
|
"""
|
|
|
|
from feedparser.mixin import _FeedParserMixin as FeedParserMixin
|
|
from feedparser.util import FeedParserDict
|
|
|
|
PODCAST_NAMESPACES = (
|
|
'https://podcastindex.org/namespace/1.0',
|
|
# The URL the namespace was announced under; some early feeds still use it.
|
|
'https://github.com/podcastindex-org/podcast-namespace/blob/main/docs/1.0.md',
|
|
)
|
|
|
|
|
|
def _start_podcast_transcript(self, attrs_d):
|
|
context = self._get_context()
|
|
context.setdefault('podcast_transcripts', []).append(FeedParserDict(attrs_d))
|
|
|
|
|
|
def _end_podcast_transcript(self):
|
|
pass
|
|
|
|
|
|
def install():
|
|
"""Idempotent; called when podcasts.views is imported."""
|
|
for uri in PODCAST_NAMESPACES:
|
|
FeedParserMixin.namespaces.setdefault(uri, 'podcast')
|
|
# Filled lazily from `namespaces` by the first parser; once it has
|
|
# been, later additions have to go in here directly.
|
|
if FeedParserMixin._matchnamespaces:
|
|
FeedParserMixin._matchnamespaces.setdefault(uri.lower(), 'podcast')
|
|
FeedParserMixin._start_podcast_transcript = _start_podcast_transcript
|
|
FeedParserMixin._end_podcast_transcript = _end_podcast_transcript
|