mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
feat: Videoplayer remember subtitle and audio selection(#339)
This commit is contained in:
parent
93a38a0b6b
commit
b1491b0ada
10 changed files with 247 additions and 39 deletions
|
|
@ -34,6 +34,7 @@ class AccountModel with _$AccountModel {
|
|||
@Default([]) List<LibraryFiltersModel> savedFilters,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false) UserPolicy? policy,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false) ServerConfiguration? serverConfiguration,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false) UserConfiguration? userConfiguration,
|
||||
}) = _AccountModel;
|
||||
|
||||
factory AccountModel.fromJson(Map<String, dynamic> json) => _$AccountModelFromJson(json);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ mixin _$AccountModel {
|
|||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
ServerConfiguration? get serverConfiguration =>
|
||||
throw _privateConstructorUsedError;
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
UserConfiguration? get userConfiguration =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this AccountModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
|
@ -68,7 +71,9 @@ abstract class $AccountModelCopyWith<$Res> {
|
|||
List<LibraryFiltersModel> savedFilters,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false) UserPolicy? policy,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
ServerConfiguration? serverConfiguration});
|
||||
ServerConfiguration? serverConfiguration,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
UserConfiguration? userConfiguration});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
|
@ -99,6 +104,7 @@ class _$AccountModelCopyWithImpl<$Res, $Val extends AccountModel>
|
|||
Object? savedFilters = null,
|
||||
Object? policy = freezed,
|
||||
Object? serverConfiguration = freezed,
|
||||
Object? userConfiguration = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
name: null == name
|
||||
|
|
@ -153,6 +159,10 @@ class _$AccountModelCopyWithImpl<$Res, $Val extends AccountModel>
|
|||
? _value.serverConfiguration
|
||||
: serverConfiguration // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConfiguration?,
|
||||
userConfiguration: freezed == userConfiguration
|
||||
? _value.userConfiguration
|
||||
: userConfiguration // ignore: cast_nullable_to_non_nullable
|
||||
as UserConfiguration?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +189,9 @@ abstract class _$$AccountModelImplCopyWith<$Res>
|
|||
List<LibraryFiltersModel> savedFilters,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false) UserPolicy? policy,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
ServerConfiguration? serverConfiguration});
|
||||
ServerConfiguration? serverConfiguration,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
UserConfiguration? userConfiguration});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
|
@ -208,6 +220,7 @@ class __$$AccountModelImplCopyWithImpl<$Res>
|
|||
Object? savedFilters = null,
|
||||
Object? policy = freezed,
|
||||
Object? serverConfiguration = freezed,
|
||||
Object? userConfiguration = freezed,
|
||||
}) {
|
||||
return _then(_$AccountModelImpl(
|
||||
name: null == name
|
||||
|
|
@ -262,6 +275,10 @@ class __$$AccountModelImplCopyWithImpl<$Res>
|
|||
? _value.serverConfiguration
|
||||
: serverConfiguration // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConfiguration?,
|
||||
userConfiguration: freezed == userConfiguration
|
||||
? _value.userConfiguration
|
||||
: userConfiguration // ignore: cast_nullable_to_non_nullable
|
||||
as UserConfiguration?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +300,9 @@ class _$AccountModelImpl extends _AccountModel with DiagnosticableTreeMixin {
|
|||
final List<LibraryFiltersModel> savedFilters = const [],
|
||||
@JsonKey(includeFromJson: false, includeToJson: false) this.policy,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
this.serverConfiguration})
|
||||
this.serverConfiguration,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
this.userConfiguration})
|
||||
: _latestItemsExcludes = latestItemsExcludes,
|
||||
_searchQueryHistory = searchQueryHistory,
|
||||
_savedFilters = savedFilters,
|
||||
|
|
@ -346,10 +365,13 @@ class _$AccountModelImpl extends _AccountModel with DiagnosticableTreeMixin {
|
|||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final ServerConfiguration? serverConfiguration;
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final UserConfiguration? userConfiguration;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'AccountModel(name: $name, id: $id, avatar: $avatar, lastUsed: $lastUsed, authMethod: $authMethod, localPin: $localPin, credentials: $credentials, latestItemsExcludes: $latestItemsExcludes, searchQueryHistory: $searchQueryHistory, quickConnectState: $quickConnectState, savedFilters: $savedFilters, policy: $policy, serverConfiguration: $serverConfiguration)';
|
||||
return 'AccountModel(name: $name, id: $id, avatar: $avatar, lastUsed: $lastUsed, authMethod: $authMethod, localPin: $localPin, credentials: $credentials, latestItemsExcludes: $latestItemsExcludes, searchQueryHistory: $searchQueryHistory, quickConnectState: $quickConnectState, savedFilters: $savedFilters, policy: $policy, serverConfiguration: $serverConfiguration, userConfiguration: $userConfiguration)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -369,7 +391,8 @@ class _$AccountModelImpl extends _AccountModel with DiagnosticableTreeMixin {
|
|||
..add(DiagnosticsProperty('quickConnectState', quickConnectState))
|
||||
..add(DiagnosticsProperty('savedFilters', savedFilters))
|
||||
..add(DiagnosticsProperty('policy', policy))
|
||||
..add(DiagnosticsProperty('serverConfiguration', serverConfiguration));
|
||||
..add(DiagnosticsProperty('serverConfiguration', serverConfiguration))
|
||||
..add(DiagnosticsProperty('userConfiguration', userConfiguration));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -398,7 +421,9 @@ class _$AccountModelImpl extends _AccountModel with DiagnosticableTreeMixin {
|
|||
.equals(other._savedFilters, _savedFilters) &&
|
||||
(identical(other.policy, policy) || other.policy == policy) &&
|
||||
(identical(other.serverConfiguration, serverConfiguration) ||
|
||||
other.serverConfiguration == serverConfiguration));
|
||||
other.serverConfiguration == serverConfiguration) &&
|
||||
(identical(other.userConfiguration, userConfiguration) ||
|
||||
other.userConfiguration == userConfiguration));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
|
|
@ -417,7 +442,8 @@ class _$AccountModelImpl extends _AccountModel with DiagnosticableTreeMixin {
|
|||
quickConnectState,
|
||||
const DeepCollectionEquality().hash(_savedFilters),
|
||||
policy,
|
||||
serverConfiguration);
|
||||
serverConfiguration,
|
||||
userConfiguration);
|
||||
|
||||
/// Create a copy of AccountModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
|
@ -451,7 +477,9 @@ abstract class _AccountModel extends AccountModel {
|
|||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final UserPolicy? policy,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final ServerConfiguration? serverConfiguration}) = _$AccountModelImpl;
|
||||
final ServerConfiguration? serverConfiguration,
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final UserConfiguration? userConfiguration}) = _$AccountModelImpl;
|
||||
const _AccountModel._() : super._();
|
||||
|
||||
factory _AccountModel.fromJson(Map<String, dynamic> json) =
|
||||
|
|
@ -485,6 +513,9 @@ abstract class _AccountModel extends AccountModel {
|
|||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
ServerConfiguration? get serverConfiguration;
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
UserConfiguration? get userConfiguration;
|
||||
|
||||
/// Create a copy of AccountModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
|
|
|||
|
|
@ -175,6 +175,20 @@ class StreamModel {
|
|||
});
|
||||
}
|
||||
|
||||
class AudioAndSubStreamModel extends StreamModel {
|
||||
final String language;
|
||||
final String displayTitle;
|
||||
AudioAndSubStreamModel({
|
||||
required this.displayTitle,
|
||||
required super.name,
|
||||
required super.codec,
|
||||
required super.isDefault,
|
||||
required super.isExternal,
|
||||
required super.index,
|
||||
required this.language,
|
||||
});
|
||||
}
|
||||
|
||||
class VersionStreamModel {
|
||||
final String name;
|
||||
final int index;
|
||||
|
|
@ -250,19 +264,17 @@ extension SortByExternalExtension<T extends StreamModel> on Iterable<T> {
|
|||
}
|
||||
}
|
||||
|
||||
class AudioStreamModel extends StreamModel {
|
||||
final String displayTitle;
|
||||
final String language;
|
||||
class AudioStreamModel extends AudioAndSubStreamModel {
|
||||
final String channelLayout;
|
||||
|
||||
AudioStreamModel({
|
||||
required this.displayTitle,
|
||||
required super.displayTitle,
|
||||
required super.name,
|
||||
required super.codec,
|
||||
required super.isDefault,
|
||||
required super.isExternal,
|
||||
required super.index,
|
||||
required this.language,
|
||||
required super.language,
|
||||
required this.channelLayout,
|
||||
});
|
||||
|
||||
|
|
@ -292,8 +304,8 @@ class AudioStreamModel extends StreamModel {
|
|||
|
||||
AudioStreamModel.no({
|
||||
super.name = 'Off',
|
||||
this.displayTitle = 'Off',
|
||||
this.language = '',
|
||||
super.displayTitle = 'Off',
|
||||
super.language = '',
|
||||
super.codec = '',
|
||||
this.channelLayout = '',
|
||||
super.isDefault = false,
|
||||
|
|
@ -302,19 +314,17 @@ class AudioStreamModel extends StreamModel {
|
|||
});
|
||||
}
|
||||
|
||||
class SubStreamModel extends StreamModel {
|
||||
class SubStreamModel extends AudioAndSubStreamModel {
|
||||
String id;
|
||||
String title;
|
||||
String displayTitle;
|
||||
String language;
|
||||
String? url;
|
||||
bool supportsExternalStream;
|
||||
SubStreamModel({
|
||||
required super.name,
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.displayTitle,
|
||||
required this.language,
|
||||
required super.displayTitle,
|
||||
required super.language,
|
||||
this.url,
|
||||
required super.codec,
|
||||
required super.isDefault,
|
||||
|
|
@ -327,8 +337,8 @@ class SubStreamModel extends StreamModel {
|
|||
super.name = 'Off',
|
||||
this.id = 'Off',
|
||||
this.title = 'Off',
|
||||
this.displayTitle = 'Off',
|
||||
this.language = '',
|
||||
super.displayTitle = 'Off',
|
||||
super.language = '',
|
||||
this.url = '',
|
||||
super.codec = '',
|
||||
super.isDefault = false,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import 'package:fladder/util/bitrate_helper.dart';
|
|||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/util/map_bool_helper.dart';
|
||||
import 'package:fladder/util/streams_selection.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class Media {
|
||||
|
|
@ -196,13 +197,25 @@ class PlaybackModelHelper {
|
|||
);
|
||||
|
||||
final streamModel = firstItemToPlay.streamModel;
|
||||
final audioStreamIndex = selectAudioStream(
|
||||
ref.read(userProvider.select((value) => value?.userConfiguration?.rememberAudioSelections ?? true)),
|
||||
oldModel?.mediaStreams?.currentAudioStream,
|
||||
streamModel?.audioStreams,
|
||||
streamModel?.defaultAudioStreamIndex
|
||||
);
|
||||
final subStreamIndex = selectSubStream(
|
||||
ref.read(userProvider.select((value) => value?.userConfiguration?.rememberSubtitleSelections ?? true)),
|
||||
oldModel?.mediaStreams?.currentSubStream,
|
||||
streamModel?.subStreams,
|
||||
streamModel?.defaultSubStreamIndex
|
||||
);
|
||||
|
||||
final Response<PlaybackInfoResponse> response = await api.itemsItemIdPlaybackInfoPost(
|
||||
itemId: firstItemToPlay.id,
|
||||
body: PlaybackInfoDto(
|
||||
startTimeTicks: startPosition?.toRuntimeTicks,
|
||||
audioStreamIndex: streamModel?.defaultAudioStreamIndex,
|
||||
subtitleStreamIndex: streamModel?.defaultSubStreamIndex,
|
||||
audioStreamIndex: audioStreamIndex,
|
||||
subtitleStreamIndex: subStreamIndex,
|
||||
enableTranscoding: true,
|
||||
autoOpenLiveStream: true,
|
||||
deviceProfile: ref.read(videoProfileProvider),
|
||||
|
|
@ -223,8 +236,8 @@ class PlaybackModelHelper {
|
|||
if (mediaSource == null) return null;
|
||||
|
||||
final mediaStreamsWithUrls = MediaStreamsModel.fromMediaStreamsList(playbackInfo.mediaSources, ref).copyWith(
|
||||
defaultAudioStreamIndex: streamModel?.defaultAudioStreamIndex,
|
||||
defaultSubStreamIndex: streamModel?.defaultSubStreamIndex,
|
||||
defaultAudioStreamIndex: audioStreamIndex,
|
||||
defaultSubStreamIndex: subStreamIndex,
|
||||
);
|
||||
|
||||
final mediaSegments = await api.mediaSegmentsGet(id: item.id);
|
||||
|
|
@ -328,8 +341,18 @@ class PlaybackModelHelper {
|
|||
|
||||
final currentPosition = ref.read(mediaPlaybackProvider.select((value) => value.position));
|
||||
|
||||
final audioIndex = playbackModel.mediaStreams?.defaultAudioStreamIndex;
|
||||
final subIndex = playbackModel.mediaStreams?.defaultSubStreamIndex;
|
||||
final audioIndex = selectAudioStream(
|
||||
ref.read(userProvider.select((value) => value?.userConfiguration?.rememberAudioSelections ?? true)),
|
||||
playbackModel.mediaStreams?.currentAudioStream,
|
||||
playbackModel.audioStreams,
|
||||
playbackModel.mediaStreams?.defaultAudioStreamIndex
|
||||
);
|
||||
final subIndex = selectSubStream(
|
||||
ref.read(userProvider.select((value) => value?.userConfiguration?.rememberSubtitleSelections ?? true)),
|
||||
playbackModel.mediaStreams?.currentSubStream,
|
||||
playbackModel.subStreams,
|
||||
playbackModel.mediaStreams?.defaultSubStreamIndex
|
||||
);
|
||||
|
||||
Response<PlaybackInfoResponse> response = await api.itemsItemIdPlaybackInfoPost(
|
||||
itemId: item.id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue