Skip to content

feat: Add subtitle sync ui for easy alignment - #6735

Open
armanckeser wants to merge 3 commits into
jellyfin:masterfrom
armanckeser:armanc/add-subtitle-sync-ui
Open

feat: Add subtitle sync ui for easy alignment#6735
armanckeser wants to merge 3 commits into
jellyfin:masterfrom
armanckeser:armanc/add-subtitle-sync-ui

Conversation

@armanckeser

@armanckeser armanckeser commented Apr 10, 2025

Copy link
Copy Markdown

Changes

  • Chrome reactive change
chrome_reactive.mp4
  • Firefox before and after (pressed playback and stopped for the actual subtitles to re-render)

Screenshot 2025-04-17 204703
Screenshot 2025-04-17 204719

  • WebOS Browser

webos-dev-tmp-674d30ba-3ec7-4d78-bad5-42802e6794d3

  • Adds a dynamic subtitle sync rendering. Users can now stop where they would like a subtitle to start, align the time with the view and continue
  • Adds api from the html player and playback manager to get the subtitles.

Issues

#4364

@armanckeser
armanckeser requested a review from a team as a code owner April 10, 2025 00:26
@jellyfin-bot

jellyfin-bot commented Apr 10, 2025

Copy link
Copy Markdown
Collaborator

Cloudflare Pages deployment

Latest commit 0e51ddc
Status ✅ Deployed!
Preview URL https://a2bfc78d.jellyfin-web.pages.dev
Type 🔀 Preview

View build logs

@dmitrylyzo dmitrylyzo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This only works with "custom subtitle element" (doesn't work in Chrome) and obviously only for text (SRT) subtitles.
  2. We probably should update the subtitles timeline on timeupdate.
  3. IMO, the timeline is too close to the offset slider, which makes you think they are tied.
  4. Too long for mobile.

Comment thread src/components/subtitlesync/subtitlesync.js Outdated
Comment thread src/components/subtitlesync/subtitlesync.js Outdated
Comment thread src/components/subtitlesync/subtitlesync.js Outdated
@armanckeser

Copy link
Copy Markdown
Author

Do you have recommendations for 1?

I am also open to some guidance on 2. I tried a bunch of things, but I feel like there is an efficient solution my lack of FE knowledge eludes me from.

@dmitrylyzo

Copy link
Copy Markdown
Contributor

Do you have recommendations for 1?

When we use native API: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/textTracks
I think for SSA/ASS and PGS we should hide the timeline.

I am also open to some guidance on 2. I tried a bunch of things, but I feel like there is an efficient solution my lack of FE knowledge eludes me from.

Ideally, we should use PlaybackSubscriber.
But something like this could work:

function bindToPlayer(player) {
if (player === currentPlayer) {
return;
}
releaseCurrentPlayer();
currentPlayer = player;
if (!player) {
return;
}
Events.on(player, 'timeupdate', onTimeUpdate);
Events.on(player, 'playbackstart', onPlaybackStart);
Events.on(player, 'playbackstop', onPlaybackStop);
}
function releaseCurrentPlayer() {
const player = currentPlayer;
if (player) {
Events.off(player, 'timeupdate', onTimeUpdate);
Events.off(player, 'playbackstart', onPlaybackStart);
Events.off(player, 'playbackstop', onPlaybackStop);
currentPlayer = null;
}
}

@armanckeser armanckeser left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does this mean that platforms like WebOS wouldn't be able to use this implementation? I presume WebOS uses a chromiom browser.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ESLint doesn't pass. Please fix all ESLint issues.

Comment thread src/components/subtitlesync/subtitlesync.js Outdated
@armanckeser

Copy link
Copy Markdown
Author

Still have to think a bit about the realtime updates, the problem is getting a smooth timeline. Updating current implementation on every timeupdate results in the timeline moving choppily every second. I need to increase the resolution for the percentage calculations or add a css transition or something, but I am not sure yet

@armanckeser

Copy link
Copy Markdown
Author

I tried to implement a smooth scroll, but I just give up. I think this provides the value I would like it to provide. And even though the playback rendering is a bit janky, probably better than not having it at all.

@armanckeser

Copy link
Copy Markdown
Author

@dmitrylyzo thoughts?

@Gauvino

Gauvino commented Apr 15, 2025

Copy link
Copy Markdown

Absolutely incredible

@armanckeser

armanckeser commented Apr 18, 2025

Copy link
Copy Markdown
Author

@dmitrylyzo Added screenshots from Firefox, Chrome, WebOS browser. Added realtime update ability and a video from Chrome showing that the changes are accurate with the realtime rendering. Changed the styling to better match Jellyfin Web style. I believe with SSA/ASS and PGS, the subtitle offset menu does not even show up (I tried with PGS and DVD SUB, neither showed the menu), but if it did, the timeline would be hidden.

@armanckeser

Copy link
Copy Markdown
Author

@dmitrylyzo Would love to learn what types of tests or proof I could add to make this easier to review for the team.

@dmitrylyzo dmitrylyzo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. As before, I think the timeline is too close to the offset slider, which makes you think they are tied.
    Close:
    timeline-old
    Split:
    timeline

  2. My biggest concern right now is intermediate refactoring. I prefer to do refactoring first and then add the feature. Ideally, we should make commits atomic. If no one has any objections to the current commit sequence, so be it.

Comment thread src/components/subtitlesync/subtitlesync.js Outdated
Comment thread src/components/subtitlesync/subtitlesync.js Outdated
@armanckeser

armanckeser commented Apr 28, 2025

Copy link
Copy Markdown
Author

As before, I think the timeline is too close to the offset slider, which makes you think they are tied.

Ah, thanks for the clarification. I thought you meant that the current time marker itself was too close to the button (which it was), but "split" looks much better

My biggest concern right now is intermediate refactoring. I prefer to do refactoring first and then add the feature. Ideally, we should make commits atomic. If no one has any objections to the current commit sequence, so be it.

I see. Let me try a stacked approach, I am thinking a PR (or commit?) to refactor the original into OffsetController and the SubtitleSync object, and another one to add the timeline view. Does that sound good to you?

@sonarqubecloud

Copy link
Copy Markdown

soultaco83 pushed a commit to soultaco83/jellyfin-web-unstable that referenced this pull request Jul 13, 2025
@sonarqubecloud

Copy link
Copy Markdown

@sonarqubecloud

Copy link
Copy Markdown

@sonarqubecloud

Copy link
Copy Markdown

@armanckeser

Copy link
Copy Markdown
Author

A bit sad that a year has passed since I opened this PR. I don't think it should take over a year to add a nice feature

@jellyfin-bot jellyfin-bot added the merge conflict Conflicts prevent merging label May 13, 2026
@jellyfin-bot

Copy link
Copy Markdown
Collaborator

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@jellyfin-bot jellyfin-bot added the stale No activity for an extended length of time label May 14, 2026
@Lothyriel

This comment has been minimized.

@jellyfin-bot jellyfin-bot added stale No activity for an extended length of time and removed stale No activity for an extended length of time labels Jun 9, 2026
@armanckeser
armanckeser force-pushed the armanc/add-subtitle-sync-ui branch from e95f674 to ec5b3ce Compare June 27, 2026 03:16
Armanc added 3 commits June 26, 2026 23:22
Extract offset state and interaction handling from SubtitleSync into a
dedicated OffsetController class. Use real private methods, a currentOffset
getter/setter, and a shared slider bubble helper. No user-facing behavior
changes. Paves the way for the subtitle sync timeline feature.

Add Armanc to CONTRIBUTORS.
Expose the current subtitle track events from the HTML video player and
the playback manager in a normalized seconds-based format. This allows the
subtitle sync UI to render a timeline of upcoming subtitle events.
Render a scrolling timeline of subtitle events around the current playback
position below the offset slider, so users can visually align subtitles with
the video. Dragging the offset shifts the subtitle blocks against a fixed time
ruler, making the correct alignment easy to find.

The timeline reuses pooled DOM nodes and updates their positions on each player
time update, keeping it cheap enough to run during playback on mobile. It is
only shown for text subtitle tracks whose events can be read back from the
player.
@armanckeser
armanckeser force-pushed the armanc/add-subtitle-sync-ui branch from ec5b3ce to 1096cbd Compare June 27, 2026 03:24
@sonarqubecloud

Copy link
Copy Markdown

@jellyfin-bot jellyfin-bot added merge conflict Conflicts prevent merging and removed merge conflict Conflicts prevent merging labels Jun 27, 2026
@jellyfin-bot

Copy link
Copy Markdown
Collaborator

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@jellyfin-bot jellyfin-bot added stale No activity for an extended length of time and removed stale No activity for an extended length of time labels Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge conflict Conflicts prevent merging stale No activity for an extended length of time

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants