Skip to main content

podcast-chapter-tools

Lint and Test Ruff Checked with mypy twitter

Extract and transform podcast chapter information between PodcastIndex (PCI) chapters, Podlove Simple Chapters (PSC), description embeds (timestamps in show notes), and ID3v2 CHAP frames.

Installation

pip install podcast-chapter-tools

# with ID3 chapter support (mutagen)
pip install 'podcast-chapter-tools[id3]'

Usage

Command line

# Show-notes timestamps -> PodcastIndex chapters JSON
podcast-chapters from-description shownotes.txt --to pci

# PSC chapters from a feed (file or URL) -> description text
podcast-chapters from-psc feed.xml --guid "episode-guid" --to description

# PodcastIndex chapters JSON (file or URL) -> PSC XML
podcast-chapters from-pci https://example.com/chapters.json --to psc

# ID3 CHAP frames from an MP3 (requires the [id3] extra)
podcast-chapters from-id3 episode.mp3

All subcommands accept --to {pci,psc,description}, --normalize (sort, dedupe, strip HTML from titles), and --output FILE.

Library

Every extractor returns list[Chapter] | None, where Chapter is a named tuple of (start, title, url, image) with the start time in seconds:

from podcast_chapter_tools import (
    extract_description_chapters,
    extract_psc_chapters_from_file,
    get_and_extract_pci_chapters,
    chapters_to_pci_json,
    normalize_chapters,
)
from pathlib import Path

# From show notes (plain text or HTML)
chapters = extract_description_chapters("0:00 Intro\n2:30 Interview\n")
# [Chapter(start=0, title='Intro', ...), Chapter(start=150, title='Interview', ...)]

# From a feed's Podlove Simple Chapters
chapters = extract_psc_chapters_from_file(Path("feed.xml"), guid="episode-guid")

# From a PodcastIndex chapters URL
chapters = get_and_extract_pci_chapters("https://example.com/chapters.json")

# Clean up and convert
chapters = normalize_chapters(chapters, strip_titles=True)
print(chapters_to_pci_json(chapters, indent=2))

Other useful entry points:

  • extract_all_psc_chapters_from_file(feed) - chapters for every episode, keyed by GUID
  • extract_psc_chapters_from_url(feed_url, guid) - fetch the feed for you
  • find_pci_chapters_url(feed, guid) - discover the <podcast:chapters> URL declared in a feed
  • extract_id3_chapters(Path("episode.mp3")) - ID3v2 CHAP frames (requires the [id3] extra)
  • chapters_to_psc_xml(chapters) / chapters_to_description(chapters) - other writers
  • ts_to_secs("1:02:03") / secs_to_ts(3723) - timestamp helpers

Development

git clone git@github.com:hbmartin/podcast-chapter-tools.git
cd podcast-chapter-tools
python3 -m venv venv
source venv/bin/activate
pip install -e '.[lint,test]'

pytest
ruff check .
ruff format --check .
mypy podcast_chapter_tools

The ai/ directory contains experimental scripts for generating chapters from transcripts with LLMs; its dependencies live in ai/requirements.txt and are not part of the published package.

See also

Authors

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

podcast_chapter_tools-0.2.0.tar.gz (27.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

podcast_chapter_tools-0.2.0-py3-none-any.whl (21.6 kB view details)

Uploaded Python 3

File details

Details for the file podcast_chapter_tools-0.2.0.tar.gz.

File metadata

  • Download URL: podcast_chapter_tools-0.2.0.tar.gz
  • Upload date:
  • Size: 27.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for podcast_chapter_tools-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b74074fc27e7c32b5d34c4486b0742ae3dd000c682e5c25a46414642e4cda157
MD5 b9bc474bc51c866ba00c41fbfef5c9f0
BLAKE2b-256 c03c6749fd6affff8067369e2b7063b771ceaa37f771ad48ee923a1cc3416f40

See more details on using hashes here.

Provenance

The following attestation bundles were made for podcast_chapter_tools-0.2.0.tar.gz:

Publisher: publish.yml on hbmartin/podcast-chapter-tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file podcast_chapter_tools-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for podcast_chapter_tools-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4c817624e16917e4a46de5e08949a7c5490992d7516d5f1149a075f66eef2cd6
MD5 13338fa43453d33db956bf189e3ee752
BLAKE2b-256 a7d4f0b1077f2f9d2798821473c368c4343dc51ccd95291d3de40def6a71b6d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for podcast_chapter_tools-0.2.0-py3-none-any.whl:

Publisher: publish.yml on hbmartin/podcast-chapter-tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page