fix(jellyfin): subtitle timing, resume progress, and overlay sync

- Add per-stream subtitle delay persistence and auto timeline-offset correction
- Strip server-selected subtitle stream from mpv load URL; suppress plugin subtitle rearm and auto-start during app-managed preload
- Fix resume position lost when mpv resets on stop; use last known position for final progress/stopped reports
- Keep Play vs Resume distinct to avoid early seek race on normal play
- Fix discovery resume when remote play sends StartPositionTicks=0 despite saved progress
- Deduplicate show/hide overlay commands using recorded visibility state
- Rewrite docs-site Jellyfin page around cast-to-device UX
This commit is contained in:
2026-05-24 02:49:47 -07:00
parent dc9d7b77bb
commit 127e1ea88e
42 changed files with 2113 additions and 298 deletions
+2 -1
View File
@@ -229,6 +229,7 @@ test('resolvePlaybackPlan chooses direct play when allowed', async () => {
assert.equal(plan.mode, 'direct');
assert.match(plan.url, /Videos\/movie-1\/stream\?/);
assert.doesNotMatch(plan.url, /SubtitleStreamIndex=/);
assert.equal(new URL(plan.url).searchParams.get('StartTimeTicks'), null);
assert.equal(plan.subtitleStreamIndex, null);
assert.equal(ticksToSeconds(plan.startTimeTicks), 2);
} finally {
@@ -570,7 +571,7 @@ test('resolvePlaybackPlan preserves episode metadata, stream selection, and resu
const url = new URL(plan.url);
assert.equal(url.searchParams.get('AudioStreamIndex'), '6');
assert.equal(url.searchParams.get('SubtitleStreamIndex'), '9');
assert.equal(url.searchParams.get('StartTimeTicks'), '35000000');
assert.equal(url.searchParams.get('StartTimeTicks'), null);
} finally {
globalThis.fetch = originalFetch;
}