Skip to content

feat(video): honor URL t=/start= timestamp as a playback start offset#37

Merged
kfox merged 1 commit into
mainfrom
feat/url-timestamp-start-offset
Jun 23, 2026
Merged

feat(video): honor URL t=/start= timestamp as a playback start offset#37
kfox merged 1 commit into
mainfrom
feat/url-timestamp-start-offset

Conversation

@kfox

@kfox kfox commented Jun 23, 2026

Copy link
Copy Markdown
Owner

What

Playing a URL with a timestamp previously ignored it and started at 0:00. Now a
quick-playback URL begins at its own timestamp, with no new CLI flag — the
lowest-friction path stays low-friction:

c64cast 'https://youtu.be/<id>?t=1m30s'

?t= / &start= / #t= are honored, accepting 90, 90s, 1m30s, 1h2m3s.

How

  • quickcast._parse_start_offset parses the timestamp off the original URL
    (the resolved stream URL doesn't carry it) and sets the scene's start offset.
  • New SceneCfg.start_s (video-only; negative rejected, set-on-non-video
    rejected) threads through VideoScene into AVFileSource.
  • AVFileSource seeks the container to the keyframe at/just-before start_s
    (whole-container seek in AV_TIME_BASE microseconds, backward) before the
    demux thread starts; the audio peak-scan container seeks too so normalization
    reflects the played portion.
  • The demux loop rebases every video frame's PTS by the first decoded frame so
    playback restarts at ~0 and tracks the from-0 audio/wall clock. The no-seek
    path is unchanged (offset ≈ 0).

Applied as a PyAV seek, not a yt-dlp download-section: no temp download, and
it also covers direct media URLs and config-driven [[scenes]] videos
(start_s = N). Accuracy is keyframe-granular (start lands within one GOP);
A/V stay aligned. Exact-to-the-second start (decode-and-discard) is left as a
future refinement.

Docs + schema

CLAUDE.md, docs/usage.md, and the example TOML document start_s; the JSON
schema is regenerated.

Tests

  • Timestamp parsers (_parse_timestr / _parse_start_offset): query params,
    fragment, h/m/s forms, garbage → None.
  • classify_url sets start_s from a URL timestamp.
  • start_s validation: accepted on video, negative rejected, rejected on
    non-video.
  • A fake-container demux unit test asserting the PTS rebase (no PyAV).

Full suite green; schema in sync.

Quick playback (`c64cast MEDIA…`) now starts a URL at its own timestamp with
no new flag: `?t=`/`&start=`/`#t=` (accepting 90, 90s, 1m30s, 1h2m3s) is parsed
by quickcast._parse_start_offset and sets the scene's start offset.

- SceneCfg.start_s (video-only; negative rejected, non-video rejected) threads
  through VideoScene into AVFileSource.
- AVFileSource seeks the container to the keyframe at/just-before start_s (whole
  -container seek, AV_TIME_BASE microseconds, backward) before demux starts, and
  the peak-scan container seeks too so normalization covers the played portion.
- The demux loop rebases every video frame's PTS by the first decoded frame so
  playback restarts at ~0 and tracks the from-0 audio/wall clock; the no-seek
  path is unchanged. Accuracy is keyframe-granular; A/V stay aligned.

Applied as a PyAV seek (not a yt-dlp download-section) so it also covers direct
media URLs and config-driven [[scenes]] videos, with no temp download.

Docs (CLAUDE.md, usage.md, example TOML) + schema regenerated. Tests: timestamp
parsers, start_s validation, and a fake-container demux PTS-rebase unit test.
@kfox kfox merged commit e37cbee into main Jun 23, 2026
6 checks passed
@kfox kfox deleted the feat/url-timestamp-start-offset branch June 23, 2026 21:53
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.41667% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.54%. Comparing base (9855456) to head (77771cb).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
c64cast/video.py 30.00% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #37      +/-   ##
==========================================
+ Coverage   79.43%   79.54%   +0.10%     
==========================================
  Files          68       68              
  Lines       12770    12817      +47     
  Branches     1877     1889      +12     
==========================================
+ Hits        10144    10195      +51     
+ Misses       2193     2185       -8     
- Partials      433      437       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

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