fix(player): carry a picked subtitle language across episodes with sparse tags
The cross-item subtitle intent required declared languages on both sides, and a null on either side counted as a contradiction. Any untagged track - common when a title like "Swedish" is the only signal - declined on every episode advance, fell to the server's per-item priority, and turned the viewer's subtitles off (a 2.11.0 regression from the #1716/#1717 hard gates). A unique real title match now vouches for a row when language evidence is missing on either side. Declared languages that disagree still decline no matter what the title says, forced-class parity is untouched, codec and external parity only break ties within the title-matched set, and a residual tie declines rather than guesses, so the wrong-track class of #1716 stays closed. A decline is also no longer laundered into a viewer decision: the resolver keeps the unserved preference on the selection, the open flow hands it to the track manager instead of a navigation-priority off (late native tracks may carry the container tags the server rows lack), the next episode boundary re-carries it instead of hardening it into an explicit off, and progress reports withhold the -1 subtitle index that would otherwise come back as the item's server-side default forever. A pick the screen could not map to a source row (no subtitle catalog, or an identity-matcher miss) previously never reached the committed session selection at all, so the next episode carried the stale off while the picked track was visibly on screen. Such picks now commit the raw native track without source ids and demote to a semantic intent at the boundary. close #1785
This commit is contained in:
@@ -548,6 +548,65 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('issue #1785 declined-carry surfacing', () {
|
||||
const swedishIntent = SubtitlePreference.intent(
|
||||
SubtitleIntent(language: 'swe', forced: false, title: 'Swedish', codec: 'srt'),
|
||||
);
|
||||
|
||||
MediaSubtitleTrack untaggedRow(int id, {String? title, String codec = 'srt'}) =>
|
||||
MediaSubtitleTrack(id: id, title: title, codec: codec, selected: false, forced: false);
|
||||
|
||||
test('an untagged catalog row with the matching title still serves the carry', () {
|
||||
final result = PlaybackSubtitleResolver.resolve(
|
||||
metadata: metadata,
|
||||
mediaInfo: _mediaInfo([untaggedRow(3, title: 'English'), untaggedRow(4, title: 'Swedish')]),
|
||||
sidecars: const [],
|
||||
preferredSubtitleTrack: swedishIntent,
|
||||
preserveSourceIdentity: false,
|
||||
);
|
||||
|
||||
expect(result.primarySourceStreamId, 4);
|
||||
expect(result.declinedPreference, isNull);
|
||||
});
|
||||
|
||||
test('a carry no row can serve is kept as declined, not converted to off', () {
|
||||
final result = PlaybackSubtitleResolver.resolve(
|
||||
metadata: metadata,
|
||||
mediaInfo: _mediaInfo([_sourceSubtitle(3, language: 'eng')]),
|
||||
sidecars: const [],
|
||||
preferredSubtitleTrack: swedishIntent,
|
||||
preserveSourceIdentity: false,
|
||||
);
|
||||
|
||||
expect(result.isOff, isTrue);
|
||||
expect(result.declinedPreference, swedishIntent);
|
||||
});
|
||||
|
||||
test('an explicit off carry is a decision, never a decline', () {
|
||||
final result = PlaybackSubtitleResolver.resolve(
|
||||
metadata: metadata,
|
||||
mediaInfo: _mediaInfo([_sourceSubtitle(3, language: 'eng')]),
|
||||
sidecars: const [],
|
||||
preferredSubtitleTrack: const SubtitlePreference.off(),
|
||||
preserveSourceIdentity: false,
|
||||
);
|
||||
|
||||
expect(result.isOff, isTrue);
|
||||
expect(result.declinedPreference, isNull);
|
||||
});
|
||||
|
||||
test('a ladder off with no carry at all is a decision, never a decline', () {
|
||||
final result = PlaybackSubtitleResolver.resolve(
|
||||
metadata: metadata,
|
||||
mediaInfo: _mediaInfo([_sourceSubtitle(3, language: 'eng')]),
|
||||
sidecars: const [],
|
||||
);
|
||||
|
||||
expect(result.isOff, isTrue);
|
||||
expect(result.declinedPreference, isNull);
|
||||
});
|
||||
});
|
||||
|
||||
test('selected embedded subtitle keeps sidecars out of the open', () {
|
||||
final result = PlaybackSubtitleResolver.resolve(
|
||||
metadata: metadata,
|
||||
|
||||
Reference in New Issue
Block a user