Skip to content

feat: chapter detection from silence structure (FFMETADATA/JSON export)#187

Open
seonghobae wants to merge 1 commit into
mainfrom
feat/chapter-detection
Open

feat: chapter detection from silence structure (FFMETADATA/JSON export)#187
seonghobae wants to merge 1 commit into
mainfrom
feat/chapter-detection

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

New module chapters.py: proposes chapter markers for long recordings (lectures, meetings) from the silence structure that the existing silencedetect machinery already produces. Players show chapter navigation when the FFMETADATA output is embedded via ffmpeg.

  • detect_chapters(silences, total_duration, min_chapter_seconds=60.0, min_gap_seconds=3.0) — a silence lasting at least min_gap_seconds ends a chapter at its midpoint; chapters shorter than min_chapter_seconds merge into the previous chapter (first merges forward); output always covers [0, total_duration]; no silences → single chapter.
  • to_ffmetadata(chapters);FFMETADATA1 header + [CHAPTER] blocks with TIMEBASE=1/1000 and START/END in integer milliseconds, ready for ffmpeg -i input -i chapters.txt -map_metadata 1 -codec copy output.
  • to_json(chapters) — simple JSON listing.

Design

  • Stdlib-only, fully independent: no import of media_shrinker. Accepts any object with start_seconds/end_seconds (duck-type contract matching SilenceInterval), declared as a Protocol.
  • Edge cases: zero/negative duration raises ValueError; silences beyond the duration are clamped; unsorted/overlapping silences are sorted and merged first.
  • No existing files modified.

Testing

  • python3.14 -m unittest discover -s tests: 128 tests, no new failures (baseline exactly 5 macOS os.listxattr mock errors).
  • python3.14 -m interrogate -c pyproject.toml chapters.py: 100% docstring coverage.
  • New tests in tests/test_chapters.py (15 cases): midpoint boundaries, short-chapter merging (trailing and leading), single chapter with no silences, exact FFMETADATA format, clamping, unsorted/overlapping input, invalid duration.

🤖 Generated with Claude Code

Add chapters.py, a stdlib-only module that turns detected silence
intervals plus total duration into proposed chapter markers for long
recordings (lectures, meetings). Silences of at least min_gap_seconds
end a chapter at their midpoint; chapters shorter than
min_chapter_seconds merge into the previous chapter; output always
covers [0, total_duration].

The module is independent of media_shrinker: it accepts any object
with start_seconds/end_seconds attributes (same duck-type shape as
SilenceInterval), so it pairs with the existing silencedetect
machinery without a hard import.

Exports:
- to_ffmetadata(): ffmpeg ;FFMETADATA1 chapters (TIMEBASE=1/1000,
  START/END in ms) for embedding player chapter navigation
- to_json(): simple JSON listing

Edge cases covered: zero/negative duration raises ValueError,
out-of-range silences clamped, unsorted/overlapping silences sorted
and merged, empty silences yield a single chapter.

Tests: tests/test_chapters.py (15 cases). Interrogate 100%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJRVbDrp1vGYkJgNHMGPpG
@seonghobae seonghobae enabled auto-merge (squash) July 6, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant