@@ -150,10 +150,11 @@ extension _VideoPlayerEpisodeNavigationMethods on VideoPlayerScreenState {
|
||||
// Read the client before any await — context across an async gap. A
|
||||
// missing client leaves this null and the guard below reports it.
|
||||
final serverId = _currentMetadata.serverId;
|
||||
PlexClient? subtitleClient;
|
||||
if (isSubtitleChange && serverId != null) {
|
||||
final isPlexBacked = _currentMetadata.backend == MediaBackend.plex;
|
||||
PlexClient? streamSelectClient;
|
||||
if ((isSubtitleChange || (isAudioChange && isPlexBacked)) && serverId != null) {
|
||||
try {
|
||||
subtitleClient = context.getPlexClientForServer(ServerId(serverId));
|
||||
streamSelectClient = context.getPlexClientForServer(ServerId(serverId));
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
@@ -162,18 +163,19 @@ extension _VideoPlayerEpisodeNavigationMethods on VideoPlayerScreenState {
|
||||
await saveMediaVersionIndexFor(_currentMetadata, effectiveMediaIndex);
|
||||
}
|
||||
|
||||
if (isSubtitleChange) {
|
||||
if (isSubtitleChange || (isAudioChange && isPlexBacked)) {
|
||||
final partId = _currentMediaInfo?.partId;
|
||||
if (subtitleClient == null || partId == null || effectiveSubtitleStreamId == null) {
|
||||
throw StateError('No Plex part available for subtitle stream selection');
|
||||
if (streamSelectClient == null || partId == null) {
|
||||
throw StateError('No Plex part available for stream selection');
|
||||
}
|
||||
final saved = await subtitleClient.selectStreams(
|
||||
final saved = await streamSelectClient.selectStreams(
|
||||
partId,
|
||||
subtitleStreamID: effectiveSubtitleStreamId,
|
||||
audioStreamID: isAudioChange ? effectiveAudioStreamId : null,
|
||||
subtitleStreamID: isSubtitleChange ? effectiveSubtitleStreamId : null,
|
||||
allParts: true,
|
||||
);
|
||||
if (!saved) {
|
||||
throw StateError('Failed to select subtitle stream');
|
||||
throw StateError('Failed to select streams');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1237,6 +1237,7 @@ class PlexClient
|
||||
if (queryParams.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
queryParams['allParts'] = 1;
|
||||
|
||||
// Use PUT request on /library/parts/{partId}
|
||||
return _wrapBoolApiCall(
|
||||
|
||||
@@ -56,6 +56,24 @@ void main() {
|
||||
return client.buildTranscodeSidecarSubtitlesForTesting(mediaInfoWithSubtitles(subtitleTracks));
|
||||
}
|
||||
|
||||
test('selectStreams sends audio stream selection with allParts', () async {
|
||||
final requests = <http.Request>[];
|
||||
final client = makeClient((request) async {
|
||||
requests.add(request);
|
||||
return http.Response('', 200);
|
||||
});
|
||||
addTearDown(client.close);
|
||||
|
||||
final saved = await client.selectStreams(99, audioStreamID: 301, allParts: true);
|
||||
|
||||
expect(saved, isTrue);
|
||||
expect(requests, hasLength(1));
|
||||
expect(requests.single.method, 'PUT');
|
||||
expect(requests.single.url.path, '/library/parts/99');
|
||||
expect(requests.single.url.queryParameters['audioStreamID'], '301');
|
||||
expect(requests.single.url.queryParameters['allParts'], '1');
|
||||
});
|
||||
|
||||
test('playback metadata request includes streams for transcode sidecar subtitles', () async {
|
||||
final requests = <Uri>[];
|
||||
final client = makeClient((request) async {
|
||||
|
||||
Reference in New Issue
Block a user