mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 12:36:15 -08:00
fix(playback): harden external-subtitle handling from PR #1471 review
Addresses the confirmed code-review findings: - Deselect the hls.js engine track BEFORE activating an external subtitle track: hls.js reacts to subtitleTrack=-1 by disabling every subtitle-kind TextTrack, which undid the just-selected external track. - Track ownership of every TextTrack the session ever created (addTextTrack tracks cannot leave the element), so stale or attach-failed tracks stay excluded from the native enumeration instead of reappearing as ghost engine tracks after source changes; failed attaches are silenced and their partial cues removed. - Guard the file pick with a source generation so a pick that outlives a stream change (Up Next, zapping, failover) is discarded instead of attaching the previous stream's subtitles to the next one. - Decode picked files encoding-aware (UTF-16 BOMs, strict UTF-8, then a Windows-1251/1252 heuristic) instead of Blob.text()'s silent UTF-8 substitution that rendered legacy-encoded SRT files as mojibake. - Gate the delay row on an external track being SELECTED, not merely loaded, so it can no longer sit enabled while visually inert. - Keep real (possibly negative) cue times under a negative delay instead of clamping pre-roll cues into a simultaneous stack at t=0. - Fix subtitleDelayLabel returning a signed negative zero for sub-tenth values. - Hoist the canonical PlayerSubtitleStyle shape plus clamp/normalize rules into @iptvnator/shared/interfaces (subtitle-style.util.ts); the renderer and the Electron main process now share one implementation, removing the triplicated literals and the toLowerCase divergence. Adds regression coverage for each fix; updates the player-controls contract doc and CLAUDE.md accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
404deb92b0
commit
10bd5acd6f
16 files changed
+481
-119
No files matched your search
@@ -27,6 +27,8 @@ import {
|
||||
EMBEDDED_MPV_FRAME_SOURCE_CHANGED,
|
||||
EMBEDDED_MPV_SESSION_UPDATE,
|
||||
ResolvedPortalPlayback,
|
||||
clampSubtitleDelay,
|
||||
normalizeSubtitleStyle,
|
||||
} from '@iptvnator/shared/interfaces';
|
||||
import { toNativeViewBounds } from './embedded-mpv-bounds.util';
|
||||
import { EmbeddedMpvFrameCopyAdapter } from './embedded-mpv-frame-copy.adapter';
|
||||
@@ -598,10 +600,9 @@ export class EmbeddedMpvNativeService {
|
||||
'Embedded MPV addon does not support subtitle delay. Rebuild the native addon to enable this feature.'
|
||||
);
|
||||
}
|
||||
const clamped = Number.isFinite(seconds)
|
||||
? Math.max(-60, Math.min(60, seconds))
|
||||
: 0;
|
||||
addon.setSubtitleDelay(sessionId, clamped);
|
||||
// Same rules as the renderer, same implementation: the shared helper
|
||||
// is the one place the limits are defined.
|
||||
addon.setSubtitleDelay(sessionId, clampSubtitleDelay(seconds));
|
||||
return this.refreshSession(sessionId);
|
||||
}
|
||||
|
||||
@@ -616,17 +617,8 @@ export class EmbeddedMpvNativeService {
|
||||
'Embedded MPV addon does not support subtitle styling. Rebuild the native addon to enable this feature.'
|
||||
);
|
||||
}
|
||||
const sizePercent =
|
||||
typeof style?.sizePercent === 'number' &&
|
||||
Number.isFinite(style.sizePercent)
|
||||
? Math.max(25, Math.min(400, Math.round(style.sizePercent)))
|
||||
: 100;
|
||||
const color =
|
||||
typeof style?.color === 'string' &&
|
||||
/^#[0-9a-f]{6}$/i.test(style.color)
|
||||
? style.color
|
||||
: null;
|
||||
addon.setSubtitleStyle(sessionId, { sizePercent, color });
|
||||
// Re-validate untrusted IPC input with the exact renderer rules.
|
||||
addon.setSubtitleStyle(sessionId, normalizeSubtitleStyle(style));
|
||||
return this.refreshSession(sessionId);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user