mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
feature: Video quality options (#234)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
957ad6c991
commit
935d6fe176
25 changed files with 644 additions and 232 deletions
|
|
@ -12,52 +12,23 @@ import 'package:fladder/models/items/trick_play_model.dart';
|
|||
import 'package:fladder/models/playback/playback_model.dart';
|
||||
import 'package:fladder/providers/api_provider.dart';
|
||||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/util/bitrate_helper.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class DirectPlaybackModel implements PlaybackModel {
|
||||
class DirectPlaybackModel extends PlaybackModel {
|
||||
DirectPlaybackModel({
|
||||
required this.item,
|
||||
required this.media,
|
||||
required this.playbackInfo,
|
||||
this.mediaStreams,
|
||||
this.mediaSegments,
|
||||
this.chapters,
|
||||
this.trickPlay,
|
||||
this.queue = const [],
|
||||
required super.item,
|
||||
required super.media,
|
||||
super.playbackInfo,
|
||||
super.mediaStreams,
|
||||
super.mediaSegments,
|
||||
super.chapters,
|
||||
super.trickPlay,
|
||||
super.queue,
|
||||
super.bitRateOptions,
|
||||
});
|
||||
|
||||
@override
|
||||
final ItemBaseModel item;
|
||||
|
||||
@override
|
||||
final Media? media;
|
||||
|
||||
@override
|
||||
final PlaybackInfoResponse playbackInfo;
|
||||
|
||||
@override
|
||||
final MediaStreamsModel? mediaStreams;
|
||||
|
||||
@override
|
||||
final MediaSegmentsModel? mediaSegments;
|
||||
|
||||
@override
|
||||
final List<Chapter>? chapters;
|
||||
|
||||
@override
|
||||
final TrickPlayModel? trickPlay;
|
||||
|
||||
@override
|
||||
ItemBaseModel? get nextVideo => queue.nextOrNull(item);
|
||||
|
||||
@override
|
||||
ItemBaseModel? get previousVideo => queue.previousOrNull(item);
|
||||
|
||||
@override
|
||||
Future<Duration>? startDuration() async => item.userData.playBackPosition;
|
||||
|
||||
@override
|
||||
List<SubStreamModel> get subStreams => [SubStreamModel.no(), ...mediaStreams?.subStreams ?? []];
|
||||
|
||||
|
|
@ -79,6 +50,11 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DirectPlaybackModel>? setQualityOption(Map<Bitrate, bool> map) async {
|
||||
return copyWith(bitRateOptions: map);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PlaybackModel?> playbackStarted(Duration position, Ref ref) async {
|
||||
await ref.read(jellyApiProvider).sessionsPlayingPost(
|
||||
|
|
@ -86,7 +62,7 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
canSeek: true,
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.id,
|
||||
playSessionId: playbackInfo.playSessionId,
|
||||
playSessionId: playbackInfo?.playSessionId,
|
||||
subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex,
|
||||
audioStreamIndex: item.streamModel?.defaultAudioStreamIndex,
|
||||
volumeLevel: 100,
|
||||
|
|
@ -108,7 +84,7 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
body: PlaybackStopInfo(
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.id,
|
||||
playSessionId: playbackInfo.playSessionId,
|
||||
playSessionId: playbackInfo?.playSessionId,
|
||||
positionTicks: position.toRuntimeTicks,
|
||||
),
|
||||
);
|
||||
|
|
@ -124,7 +100,7 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
canSeek: true,
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.id,
|
||||
playSessionId: playbackInfo.playSessionId,
|
||||
playSessionId: playbackInfo?.playSessionId,
|
||||
subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex,
|
||||
audioStreamIndex: item.streamModel?.defaultAudioStreamIndex,
|
||||
volumeLevel: 100,
|
||||
|
|
@ -142,9 +118,6 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
@override
|
||||
String toString() => 'DirectPlaybackModel(item: $item, playbackInfo: $playbackInfo)';
|
||||
|
||||
@override
|
||||
final List<ItemBaseModel> queue;
|
||||
|
||||
@override
|
||||
DirectPlaybackModel copyWith({
|
||||
ItemBaseModel? item,
|
||||
|
|
@ -156,6 +129,7 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
ValueGetter<List<Chapter>?>? chapters,
|
||||
ValueGetter<TrickPlayModel?>? trickPlay,
|
||||
List<ItemBaseModel>? queue,
|
||||
Map<Bitrate, bool>? bitRateOptions,
|
||||
}) {
|
||||
return DirectPlaybackModel(
|
||||
item: item ?? this.item,
|
||||
|
|
@ -166,6 +140,7 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
chapters: chapters != null ? chapters() : this.chapters,
|
||||
trickPlay: trickPlay != null ? trickPlay() : this.trickPlay,
|
||||
queue: queue ?? this.queue,
|
||||
bitRateOptions: bitRateOptions ?? this.bitRateOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'package:flutter/widgets.dart';
|
|||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
import 'package:fladder/models/items/chapters_model.dart';
|
||||
import 'package:fladder/models/items/media_segments_model.dart';
|
||||
|
|
@ -15,42 +14,24 @@ import 'package:fladder/util/duration_extensions.dart';
|
|||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class OfflinePlaybackModel implements PlaybackModel {
|
||||
class OfflinePlaybackModel extends PlaybackModel {
|
||||
OfflinePlaybackModel({
|
||||
required this.item,
|
||||
required this.media,
|
||||
required this.syncedItem,
|
||||
this.mediaStreams,
|
||||
this.playbackInfo,
|
||||
this.mediaSegments,
|
||||
this.trickPlay,
|
||||
this.queue = const [],
|
||||
super.mediaStreams,
|
||||
super.playbackInfo,
|
||||
required super.item,
|
||||
required super.media,
|
||||
super.mediaSegments,
|
||||
super.trickPlay,
|
||||
super.queue = const [],
|
||||
this.syncedQueue = const [],
|
||||
});
|
||||
|
||||
@override
|
||||
final ItemBaseModel item;
|
||||
|
||||
@override
|
||||
final PlaybackInfoResponse? playbackInfo;
|
||||
|
||||
@override
|
||||
final Media? media;
|
||||
|
||||
final SyncedItem syncedItem;
|
||||
|
||||
@override
|
||||
final MediaStreamsModel? mediaStreams;
|
||||
|
||||
@override
|
||||
final MediaSegmentsModel? mediaSegments;
|
||||
|
||||
@override
|
||||
List<Chapter>? get chapters => syncedItem.chapters;
|
||||
|
||||
@override
|
||||
final TrickPlayModel? trickPlay;
|
||||
|
||||
@override
|
||||
Future<Duration>? startDuration() async => item.userData.playBackPosition;
|
||||
|
||||
|
|
@ -118,9 +99,6 @@ class OfflinePlaybackModel implements PlaybackModel {
|
|||
@override
|
||||
String toString() => 'OfflinePlaybackModel(item: $item, syncedItem: $syncedItem)';
|
||||
|
||||
@override
|
||||
final List<ItemBaseModel> queue;
|
||||
|
||||
final List<SyncedItem> syncedQueue;
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -22,11 +22,15 @@ import 'package:fladder/models/video_stream_model.dart';
|
|||
import 'package:fladder/profiles/default_profile.dart';
|
||||
import 'package:fladder/providers/api_provider.dart';
|
||||
import 'package:fladder/providers/service_provider.dart';
|
||||
import 'package:fladder/providers/settings/video_player_settings_provider.dart';
|
||||
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
||||
import 'package:fladder/providers/sync_provider.dart';
|
||||
import 'package:fladder/providers/user_provider.dart';
|
||||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
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/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class Media {
|
||||
|
|
@ -52,15 +56,17 @@ extension PlaybackModelExtension on PlaybackModel? {
|
|||
};
|
||||
}
|
||||
|
||||
abstract class PlaybackModel {
|
||||
final ItemBaseModel item = throw UnimplementedError();
|
||||
final Media? media = throw UnimplementedError();
|
||||
final List<ItemBaseModel> queue = const [];
|
||||
final MediaSegmentsModel? mediaSegments = null;
|
||||
final PlaybackInfoResponse? playbackInfo = throw UnimplementedError();
|
||||
class PlaybackModel {
|
||||
final ItemBaseModel item;
|
||||
final Media? media;
|
||||
final List<ItemBaseModel> queue;
|
||||
final MediaSegmentsModel? mediaSegments;
|
||||
final PlaybackInfoResponse? playbackInfo;
|
||||
|
||||
List<Chapter>? get chapters;
|
||||
TrickPlayModel? get trickPlay;
|
||||
Map<Bitrate, bool> bitRateOptions;
|
||||
|
||||
List<Chapter>? chapters = [];
|
||||
TrickPlayModel? trickPlay;
|
||||
|
||||
Future<PlaybackModel?> updatePlaybackPosition(Duration position, bool isPlaying, Ref ref) =>
|
||||
throw UnimplementedError();
|
||||
|
|
@ -68,21 +74,32 @@ abstract class PlaybackModel {
|
|||
Future<PlaybackModel?> playbackStopped(Duration position, Duration? totalDuration, Ref ref) =>
|
||||
throw UnimplementedError();
|
||||
|
||||
final MediaStreamsModel? mediaStreams = throw UnimplementedError();
|
||||
List<SubStreamModel>? get subStreams;
|
||||
List<AudioStreamModel>? get audioStreams;
|
||||
final MediaStreamsModel? mediaStreams;
|
||||
List<SubStreamModel>? get subStreams => throw UnimplementedError();
|
||||
List<AudioStreamModel>? get audioStreams => throw UnimplementedError();
|
||||
|
||||
Future<Duration>? startDuration() async => item.userData.playBackPosition;
|
||||
Future<PlaybackModel>? setSubtitle(SubStreamModel? model, MediaControlsWrapper player) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<PlaybackModel>? setAudio(AudioStreamModel? model, MediaControlsWrapper player) => null;
|
||||
Future<PlaybackModel>? setSubtitle(SubStreamModel? model, MediaControlsWrapper player) => throw UnimplementedError();
|
||||
Future<PlaybackModel>? setAudio(AudioStreamModel? model, MediaControlsWrapper player) => throw UnimplementedError();
|
||||
Future<PlaybackModel>? setQualityOption(Map<Bitrate, bool> map) => throw UnimplementedError();
|
||||
|
||||
ItemBaseModel? get nextVideo => throw UnimplementedError();
|
||||
ItemBaseModel? get previousVideo => throw UnimplementedError();
|
||||
ItemBaseModel? get nextVideo => queue.nextOrNull(item);
|
||||
ItemBaseModel? get previousVideo => queue.previousOrNull(item);
|
||||
|
||||
PlaybackModel copyWith();
|
||||
PlaybackModel copyWith() => throw UnimplementedError();
|
||||
|
||||
PlaybackModel({
|
||||
required this.playbackInfo,
|
||||
this.mediaStreams,
|
||||
required this.item,
|
||||
required this.media,
|
||||
this.queue = const [],
|
||||
this.bitRateOptions = const {},
|
||||
this.mediaSegments,
|
||||
this.chapters,
|
||||
this.trickPlay,
|
||||
});
|
||||
}
|
||||
|
||||
final playbackModelHelper = Provider<PlaybackModelHelper>((ref) {
|
||||
|
|
@ -149,8 +166,13 @@ class PlaybackModelHelper {
|
|||
}
|
||||
}
|
||||
|
||||
Future<PlaybackModel?> createServerPlaybackModel(ItemBaseModel? item, PlaybackType? type,
|
||||
{PlaybackModel? oldModel, List<ItemBaseModel>? libraryQueue, Duration? startPosition}) async {
|
||||
Future<PlaybackModel?> createServerPlaybackModel(
|
||||
ItemBaseModel? item,
|
||||
PlaybackType? type, {
|
||||
PlaybackModel? oldModel,
|
||||
List<ItemBaseModel>? libraryQueue,
|
||||
Duration? startPosition,
|
||||
}) async {
|
||||
try {
|
||||
if (item == null) return null;
|
||||
final userId = ref.read(userProvider)?.id;
|
||||
|
|
@ -165,18 +187,18 @@ class PlaybackModelHelper {
|
|||
|
||||
final fullItem = await api.usersUserIdItemsItemIdGet(itemId: firstItemToPlay.id);
|
||||
|
||||
Map<Bitrate, bool> qualityOptions = getVideoQualityOptions(
|
||||
VideoQualitySettings(
|
||||
maxBitRate: ref.read(videoPlayerSettingsProvider.select((value) => value.maxHomeBitrate)),
|
||||
videoBitRate: firstItemToPlay.streamModel?.videoStreams.first.bitRate ?? 0,
|
||||
videoCodec: firstItemToPlay.streamModel?.videoStreams.first.codec,
|
||||
),
|
||||
);
|
||||
|
||||
final streamModel = firstItemToPlay.streamModel;
|
||||
|
||||
Response<PlaybackInfoResponse> response = await api.itemsItemIdPlaybackInfoPost(
|
||||
final Response<PlaybackInfoResponse> response = await api.itemsItemIdPlaybackInfoPost(
|
||||
itemId: firstItemToPlay.id,
|
||||
enableDirectPlay: type != PlaybackType.transcode,
|
||||
enableDirectStream: type != PlaybackType.transcode,
|
||||
enableTranscoding: true,
|
||||
autoOpenLiveStream: true,
|
||||
startTimeTicks: startPosition?.toRuntimeTicks,
|
||||
audioStreamIndex: streamModel?.defaultAudioStreamIndex,
|
||||
subtitleStreamIndex: streamModel?.defaultSubStreamIndex,
|
||||
mediaSourceId: firstItemToPlay.id,
|
||||
body: PlaybackInfoDto(
|
||||
startTimeTicks: startPosition?.toRuntimeTicks,
|
||||
audioStreamIndex: streamModel?.defaultAudioStreamIndex,
|
||||
|
|
@ -185,6 +207,9 @@ class PlaybackModelHelper {
|
|||
autoOpenLiveStream: true,
|
||||
deviceProfile: ref.read(videoProfileProvider),
|
||||
userId: userId,
|
||||
enableDirectPlay: type != PlaybackType.transcode,
|
||||
enableDirectStream: type != PlaybackType.transcode,
|
||||
maxStreamingBitrate: qualityOptions.enabledFirst.keys.firstOrNull?.bitRate,
|
||||
mediaSourceId: firstItemToPlay.id,
|
||||
),
|
||||
);
|
||||
|
|
@ -234,10 +259,9 @@ class PlaybackModelHelper {
|
|||
chapters: chapters,
|
||||
playbackInfo: playbackInfo,
|
||||
trickPlay: trickPlay,
|
||||
media: Media(
|
||||
url: mediaPath ?? playbackUrl,
|
||||
),
|
||||
media: Media(url: mediaPath ?? playbackUrl),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
bitRateOptions: qualityOptions,
|
||||
);
|
||||
} else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) {
|
||||
return TranscodePlaybackModel(
|
||||
|
|
@ -309,22 +333,17 @@ class PlaybackModelHelper {
|
|||
|
||||
Response<PlaybackInfoResponse> response = await api.itemsItemIdPlaybackInfoPost(
|
||||
itemId: item.id,
|
||||
enableDirectPlay: true,
|
||||
enableDirectStream: true,
|
||||
enableTranscoding: true,
|
||||
autoOpenLiveStream: true,
|
||||
startTimeTicks: currentPosition.toRuntimeTicks,
|
||||
audioStreamIndex: audioIndex,
|
||||
subtitleStreamIndex: subIndex,
|
||||
mediaSourceId: item.id,
|
||||
body: PlaybackInfoDto(
|
||||
startTimeTicks: currentPosition.toRuntimeTicks,
|
||||
audioStreamIndex: audioIndex,
|
||||
enableDirectPlay: true,
|
||||
enableDirectStream: true,
|
||||
subtitleStreamIndex: subIndex,
|
||||
enableTranscoding: true,
|
||||
autoOpenLiveStream: true,
|
||||
deviceProfile: ref.read(videoProfileProvider),
|
||||
userId: userId,
|
||||
maxStreamingBitrate: playbackModel.bitRateOptions.enabledFirst.entries.firstOrNull?.key.bitRate,
|
||||
mediaSourceId: item.id,
|
||||
),
|
||||
);
|
||||
|
|
@ -363,6 +382,8 @@ class PlaybackModelHelper {
|
|||
|
||||
final directPlay = '${ref.read(userProvider)?.server ?? ""}/Videos/${mediaSource.id}/stream?$params';
|
||||
|
||||
final mediaPath = isValidVideoUrl(mediaSource.path ?? "");
|
||||
|
||||
newModel = DirectPlaybackModel(
|
||||
item: playbackModel.item,
|
||||
queue: playbackModel.queue,
|
||||
|
|
@ -370,8 +391,9 @@ class PlaybackModelHelper {
|
|||
chapters: playbackModel.chapters,
|
||||
playbackInfo: playbackInfo,
|
||||
trickPlay: playbackModel.trickPlay,
|
||||
media: Media(url: directPlay),
|
||||
media: Media(url: mediaPath ?? directPlay),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
bitRateOptions: playbackModel.bitRateOptions,
|
||||
);
|
||||
} else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) {
|
||||
newModel = TranscodePlaybackModel(
|
||||
|
|
@ -383,6 +405,7 @@ class PlaybackModelHelper {
|
|||
trickPlay: playbackModel.trickPlay,
|
||||
media: Media(url: "${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
bitRateOptions: playbackModel.bitRateOptions,
|
||||
);
|
||||
}
|
||||
if (newModel == null) return;
|
||||
|
|
|
|||
|
|
@ -12,52 +12,23 @@ import 'package:fladder/models/items/trick_play_model.dart';
|
|||
import 'package:fladder/models/playback/playback_model.dart';
|
||||
import 'package:fladder/providers/api_provider.dart';
|
||||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/util/bitrate_helper.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class TranscodePlaybackModel implements PlaybackModel {
|
||||
class TranscodePlaybackModel extends PlaybackModel {
|
||||
TranscodePlaybackModel({
|
||||
required this.item,
|
||||
required this.media,
|
||||
required this.playbackInfo,
|
||||
this.mediaStreams,
|
||||
this.mediaSegments,
|
||||
this.chapters,
|
||||
this.trickPlay,
|
||||
this.queue = const [],
|
||||
required super.item,
|
||||
required super.media,
|
||||
required super.playbackInfo,
|
||||
super.mediaStreams,
|
||||
super.mediaSegments,
|
||||
super.chapters,
|
||||
super.trickPlay,
|
||||
super.queue = const [],
|
||||
super.bitRateOptions,
|
||||
});
|
||||
|
||||
@override
|
||||
final ItemBaseModel item;
|
||||
|
||||
@override
|
||||
final Media? media;
|
||||
|
||||
@override
|
||||
final PlaybackInfoResponse playbackInfo;
|
||||
|
||||
@override
|
||||
final MediaStreamsModel? mediaStreams;
|
||||
|
||||
@override
|
||||
final MediaSegmentsModel? mediaSegments;
|
||||
|
||||
@override
|
||||
final List<Chapter>? chapters;
|
||||
|
||||
@override
|
||||
final TrickPlayModel? trickPlay;
|
||||
|
||||
@override
|
||||
ItemBaseModel? get nextVideo => queue.nextOrNull(item);
|
||||
|
||||
@override
|
||||
ItemBaseModel? get previousVideo => queue.previousOrNull(item);
|
||||
|
||||
@override
|
||||
Future<Duration>? startDuration() async => item.userData.playBackPosition;
|
||||
|
||||
@override
|
||||
List<SubStreamModel> get subStreams => [SubStreamModel.no(), ...mediaStreams?.subStreams ?? []];
|
||||
|
||||
|
|
@ -79,6 +50,9 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TranscodePlaybackModel>? setQualityOption(Map<Bitrate, bool> map) async => copyWith(bitRateOptions: map);
|
||||
|
||||
@override
|
||||
Future<PlaybackModel?> playbackStarted(Duration position, Ref ref) async {
|
||||
await ref.read(jellyApiProvider).sessionsPlayingPost(
|
||||
|
|
@ -86,8 +60,8 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
canSeek: true,
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.id,
|
||||
playSessionId: playbackInfo.playSessionId,
|
||||
sessionId: playbackInfo.playSessionId,
|
||||
playSessionId: playbackInfo?.playSessionId,
|
||||
sessionId: playbackInfo?.playSessionId,
|
||||
subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex,
|
||||
audioStreamIndex: item.streamModel?.defaultAudioStreamIndex,
|
||||
volumeLevel: 100,
|
||||
|
|
@ -109,7 +83,7 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
body: PlaybackStopInfo(
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.id,
|
||||
playSessionId: playbackInfo.playSessionId,
|
||||
playSessionId: playbackInfo?.playSessionId,
|
||||
positionTicks: position.toRuntimeTicks,
|
||||
),
|
||||
);
|
||||
|
|
@ -125,8 +99,8 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
canSeek: true,
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.id,
|
||||
playSessionId: playbackInfo.playSessionId,
|
||||
sessionId: playbackInfo.playSessionId,
|
||||
playSessionId: playbackInfo?.playSessionId,
|
||||
sessionId: playbackInfo?.playSessionId,
|
||||
subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex,
|
||||
audioStreamIndex: item.streamModel?.defaultAudioStreamIndex,
|
||||
volumeLevel: 100,
|
||||
|
|
@ -143,9 +117,6 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
@override
|
||||
String toString() => 'TranscodePlaybackModel(item: $item, playbackInfo: $playbackInfo)';
|
||||
|
||||
@override
|
||||
final List<ItemBaseModel> queue;
|
||||
|
||||
@override
|
||||
TranscodePlaybackModel copyWith({
|
||||
ItemBaseModel? item,
|
||||
|
|
@ -157,6 +128,7 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
ValueGetter<List<Chapter>?>? chapters,
|
||||
ValueGetter<TrickPlayModel?>? trickPlay,
|
||||
List<ItemBaseModel>? queue,
|
||||
Map<Bitrate, bool>? bitRateOptions,
|
||||
}) {
|
||||
return TranscodePlaybackModel(
|
||||
item: item ?? this.item,
|
||||
|
|
@ -167,6 +139,7 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
chapters: chapters != null ? chapters() : this.chapters,
|
||||
trickPlay: trickPlay != null ? trickPlay() : this.trickPlay,
|
||||
queue: queue ?? this.queue,
|
||||
bitRateOptions: bitRateOptions ?? this.bitRateOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue