Skip to content

Player controls + recognising subtitles a video arrives with - #32

Merged
TN019 merged 2 commits into
mainfrom
player-and-existing-subtitles
Aug 6, 2026
Merged

Player controls + recognising subtitles a video arrives with#32
TN019 merged 2 commits into
mainfrom
player-and-existing-subtitles

Conversation

@TN019

@TN019 TN019 commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Two things reported from actually using the player.

Player controls

Skipping stalled. Every 10s click called setPosition() straight away, and a seek is a full decode restart in the media backend — hammer the button and the seeks queue up behind each other, leaving the dialog stuck on the last one's buffering. Position changes (buttons, arrow keys, clicking or dragging the bar) now accumulate into one pending target: the UI moves immediately, the backend is seeked once the burst stops. Positions the backend reports while a seek is in flight are ignored so the bar never snaps back, with a settle-timeout backstop in case a seek never reports its target.

Measured against a real 60s file: 12 clicks in 193ms produced 0 seeks during the burst, then one seek to the right place.

Icons. ⏪ 10 / 10 ⏩ rendered differently on every platform and matched nothing else in the app. gui_qt/icons.py draws them instead — circular arrow with the skip amount inside, plus play/pause — from theme tokens, at device pixel ratio.

Seek bar. A stock QSlider page-steps when you click the groove, so you could not seek by clicking. It is now self-painted: click anywhere to jump there, drag to scrub with live subtitle/time preview, hover for the time under the cursor, and the bar thickens on hover so a 5px target is easy to hit. Self-painted rather than styled because a QSS ::sub-page ignores the groove height and floods the whole widget rect — and this way the painted geometry is the same arithmetic that maps clicks to positions.

Subtitle bug. Setting both track selectors to "no subtitle" left the text on screen. _sync_tracks reset the cache to ["", ""] and then _update_subtitles saw new text "" equal to cached "", called it unchanged, and skipped the hide(). The cache now starts as None, which is distinct from "no text". Selectors also show whenever there is at least one track — with a single track they were hidden, so there was no way to turn subtitles off at all.

Subtitles a video arrives with

A video usually comes with its own .srt files, named the way everyone names them. output.sibling_transcripts() scans the source's directory for same-stem transcripts and reads the language off the second-level suffix: .zh → zh, aliases like .cn / .chs / .zh-Hans / .eng mapped to their language, no suffix at all → English, a well-formed unregistered tag → itself (the mirror of how unknown codes are written), and .part2 / .final → not a language.

Two consequences:

  • existing_transcript() now recognises a suffix-less lecture.srt, which it could not see before, so an already subtitled video is skipped rather than transcribed again. overwrite still forces a re-run.
  • Skipped files land in history at all. They never did — the skip branch had no _record() call, so a video that already had subtitles produced no history row and there was no way to reach its subtitles from the app. It is recorded now, and the entry lists every language found on disk, not just the one this run touched. A failed job does not pick up sibling files, so a failure row cannot look like it produced something.

End to end, Lecture 01.mp4 beside .srt / .zh.srt / .ja.srt / .part2.srt:

job: skipped
history card: Lecture 01.mp4
  languages : {'en': 'Lecture 01.srt', 'zh': 'Lecture 01.zh.srt', 'ja': 'Lecture 01.ja.srt'}
  missing   : ['ko'] | deleted: False

All three reach the player as selectable tracks; .part2.srt is correctly ignored.

Tests

13 new: seek-burst coalescing, bound clamping, stale positions not snapping the bar, settle backstop, click-to-position mapping, subtitle slots hiding; suffix parsing, sibling scanning, suffix-less detection, skipped-file history, sibling merge on a transcribed file, failed job staying empty. Suite is 186 passed / 5 skipped.

Worth a look before merging

The skip behaviour changes: a bare lecture.srt next to a video now counts as an existing English transcript, where before it was invisible and the file got transcribed again. That is the requested rule, but it is a behaviour change for anyone relying on the old blindness — say the word if suffix-less files should inform history only and stay out of the skip decision.

TN019 added 2 commits August 7, 2026 02:46
… backend seek instead of one per click (twelve clicks used to mean twelve decode restarts and a frozen dialog), drawn transport icons and a click-anywhere seek bar replace the emoji and the stock slider, and switching both subtitle tracks off finally hides them.
…scanned and named by their second-level suffix (no suffix means English, aliases like .cn and .zh-Hans included, .part2 is not a language), so an already subtitled file is skipped instead of re-transcribed and lands in history with every language it has — not silently absent, which is what skipped files were until now.
@TN019
TN019 merged commit eb269af into main Aug 6, 2026
1 check failed
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