Skip to content

Gallery metadata describes audio and video - #64

Merged
dkackman merged 5 commits into
masterfrom
field-report-media-info
Sep 11, 2026
Merged

Gallery metadata describes audio and video#64
dkackman merged 5 commits into
masterfrom
field-report-media-info

Conversation

@dkackman

Copy link
Copy Markdown
Owner

Items #6 and #6a of the 2026-09-10 MCP field report, executed from docs/superpowers/plans/2026-09-10-mcp-field-report-followups.md (PR-3 section). Independent of #63.

An agent cannot listen. A generated mp3 answered metadata: null from get_gallery_metadata, so every duration, peak and seam check in a session was done by fetching the file and running ffprobe by hand.

  • dw/media_info.py probe_media(path): PyAV probe returning kind, duration_seconds, sample_rate, channels, peak_dbfs, mean_dbfs, and for video fps, frame_count, width, height. One decode pass over the streams it needs — video only when the container stores no frame count (mkv) — levels from the decoded waveform, -120 dBFS floor. A file that opens but fails mid-decode still answers its header fields rather than raising, so a damaged output never 500s the route.
  • GET /api/gallery/{name}/metadata carries the result as a media block for audio/video extensions (null for images); the path is _output_file's validated return, no new filesystem access.
  • MCP get_gallery_metadata passes media through with a next hint; docs/MCP.md row; the minimax-music3 skill states the rule the report had to rediscover: a track landing within 0.2 s of its audio_duration ceiling was cut off, one well short of it finished.

Not in this PR (plan's Deferred): a per-second level envelope, behind an opt-in parameter.

Full suite: 3313 passed, 5 skipped. black --check is clean on every file this branch touches; the two pre-existing master failures are fixed in #63.

🤖 Generated with Claude Code

dkackman and others added 5 commits September 10, 2026 23:34
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- probe_media now wraps the decode loop in try/except: a track that opens
  fine but fails mid-decode (damage past the header) falls back to the
  header-level fields already gathered (kind, fps, width, height,
  duration_seconds, sample_rate, channels) instead of 500ing the gallery
  metadata route, matching read_embedded_metadata's precedent of degrading
  rather than raising.
- Only decode the video stream when a frame count still needs counting;
  a container with an upfront frame count no longer pays for a video decode
  it doesn't need.
- duration_seconds is now wrapped in float() - older PyAV exposed
  time_base as a Fraction, which JSON can't serialize.
- Unsigned 8-bit PCM is offset-binary (silence = 128): recenter before
  scaling instead of dividing raw samples by iinfo.max, which reported
  silence as -6 dBFS.
- write_mp4's test fixture now writes a real 220 Hz tone instead of a DC
  signal, letting the mp4 peak_dbfs tolerance tighten from ±1.5 to ±1.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dkackman
dkackman merged commit 0d0ecfc into master Sep 11, 2026
8 of 9 checks passed
@dkackman
dkackman deleted the field-report-media-info branch September 11, 2026 13:34
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