mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
feature: Added LibMDK video player backend (#162)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
6e32018183
commit
da354437e3
53 changed files with 1499 additions and 1006 deletions
|
|
@ -22,8 +22,8 @@ class TrickPlayModel with _$TrickPlayModel {
|
|||
int get imagesPerTile => tileWidth * tileHeight;
|
||||
|
||||
String? getTile(Duration position) {
|
||||
final int currentIndex = (position.inMilliseconds ~/ interval.inMilliseconds).clamp(0, thumbnailCount - 1);
|
||||
final int indexOfTile = (currentIndex ~/ imagesPerTile).clamp(0, (images.length - 1));
|
||||
final int currentIndex = (position.inMilliseconds ~/ interval.inMilliseconds).clamp(0, thumbnailCount);
|
||||
final int indexOfTile = (currentIndex ~/ imagesPerTile).clamp(0, images.length);
|
||||
return images.elementAtOrNull(indexOfTile);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
|
|
@ -13,9 +14,7 @@ import 'package:fladder/providers/api_provider.dart';
|
|||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart'
|
||||
if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class DirectPlaybackModel implements PlaybackModel {
|
||||
DirectPlaybackModel({
|
||||
|
|
@ -67,22 +66,8 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
|
||||
@override
|
||||
Future<DirectPlaybackModel> setSubtitle(SubStreamModel? model, MediaControlsWrapper player) async {
|
||||
final wantedSubtitle =
|
||||
model ?? subStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultSubStreamIndex);
|
||||
if (wantedSubtitle == null) return this;
|
||||
if (wantedSubtitle.index == SubStreamModel.no().index) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.no());
|
||||
} else {
|
||||
final subTracks = player.subTracks.getRange(2, player.subTracks.length).toList();
|
||||
final index = subStreams.sublist(1).indexWhere((element) => element.id == wantedSubtitle.id);
|
||||
final subTrack = subTracks.elementAtOrNull(index);
|
||||
if (wantedSubtitle.isExternal && wantedSubtitle.url != null && subTrack == null) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.uri(wantedSubtitle.url!));
|
||||
} else if (subTrack != null) {
|
||||
await player.setSubtitleTrack(subTrack);
|
||||
}
|
||||
}
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: wantedSubtitle.index));
|
||||
final newIndex = await player.setSubtitleTrack(model, this);
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -90,19 +75,8 @@ class DirectPlaybackModel implements PlaybackModel {
|
|||
|
||||
@override
|
||||
Future<DirectPlaybackModel>? setAudio(AudioStreamModel? model, MediaControlsWrapper player) async {
|
||||
final wantedAudioStream =
|
||||
model ?? audioStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultAudioStreamIndex);
|
||||
if (wantedAudioStream == null) return this;
|
||||
if (wantedAudioStream.index == AudioStreamModel.no().index) {
|
||||
await player.setAudioTrack(AudioTrack.no());
|
||||
} else {
|
||||
final audioTracks = player.audioTracks.getRange(2, player.audioTracks.length).toList();
|
||||
final audioTrack = audioTracks.elementAtOrNull(audioStreams.indexOf(wantedAudioStream) - 1);
|
||||
if (audioTrack != null) {
|
||||
await player.setAudioTrack(audioTrack);
|
||||
}
|
||||
}
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: wantedAudioStream.index));
|
||||
final newIndex = await player.setAudioTrack(model, this);
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
|
|
@ -13,9 +13,7 @@ import 'package:fladder/models/syncing/sync_item.dart';
|
|||
import 'package:fladder/providers/sync_provider.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart'
|
||||
if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class OfflinePlaybackModel implements PlaybackModel {
|
||||
OfflinePlaybackModel({
|
||||
|
|
@ -66,22 +64,8 @@ class OfflinePlaybackModel implements PlaybackModel {
|
|||
|
||||
@override
|
||||
Future<OfflinePlaybackModel> setSubtitle(SubStreamModel? model, MediaControlsWrapper player) async {
|
||||
final wantedSubtitle =
|
||||
model ?? subStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultSubStreamIndex);
|
||||
if (wantedSubtitle == null) return this;
|
||||
if (wantedSubtitle.index == SubStreamModel.no().index) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.no());
|
||||
} else {
|
||||
final subTracks = player.subTracks.getRange(2, player.subTracks.length).toList();
|
||||
final index = subStreams.sublist(1).indexWhere((element) => element.id == wantedSubtitle.id);
|
||||
final subTrack = subTracks.elementAtOrNull(index);
|
||||
if (wantedSubtitle.isExternal && wantedSubtitle.url != null && subTrack == null) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.uri(wantedSubtitle.url!));
|
||||
} else if (subTrack != null) {
|
||||
await player.setSubtitleTrack(subTrack);
|
||||
}
|
||||
}
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: wantedSubtitle.index));
|
||||
final newIndex = await player.setSubtitleTrack(model, this);
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -89,19 +73,8 @@ class OfflinePlaybackModel implements PlaybackModel {
|
|||
|
||||
@override
|
||||
Future<OfflinePlaybackModel>? setAudio(AudioStreamModel? model, MediaControlsWrapper player) async {
|
||||
final wantedAudioStream =
|
||||
model ?? audioStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultAudioStreamIndex);
|
||||
if (wantedAudioStream == null) return this;
|
||||
if (wantedAudioStream.index == AudioStreamModel.no().index) {
|
||||
await player.setAudioTrack(AudioTrack.no());
|
||||
} else {
|
||||
final audioTracks = player.audioTracks.getRange(2, player.audioTracks.length).toList();
|
||||
final audioTrack = audioTracks.elementAtOrNull(audioStreams.indexOf(wantedAudioStream) - 1);
|
||||
if (audioTrack != null) {
|
||||
await player.setAudioTrack(audioTrack);
|
||||
}
|
||||
}
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: wantedAudioStream.index));
|
||||
final newIndex = await player.setAudioTrack(model, this);
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'dart:developer';
|
|||
import 'package:chopper/chopper.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
|
|
@ -27,10 +26,23 @@ 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/duration_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart'
|
||||
if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class Media {
|
||||
final String url;
|
||||
|
||||
const Media({
|
||||
required this.url,
|
||||
});
|
||||
}
|
||||
|
||||
extension PlaybackModelExtension on PlaybackModel? {
|
||||
SubStreamModel? get defaultSubStream =>
|
||||
this?.subStreams?.firstWhereOrNull((element) => element.index == this?.mediaStreams?.defaultSubStreamIndex);
|
||||
|
||||
AudioStreamModel? get defaultAudioStream =>
|
||||
this?.audioStreams?.firstWhereOrNull((element) => element.index == this?.mediaStreams?.defaultAudioStreamIndex);
|
||||
|
||||
String? get label => switch (this) {
|
||||
DirectPlaybackModel _ => PlaybackType.directStream.name,
|
||||
TranscodePlaybackModel _ => PlaybackType.transcode.name,
|
||||
|
|
@ -119,7 +131,7 @@ class PlaybackModelHelper {
|
|||
syncedItem: syncedItem,
|
||||
trickPlay: syncedItem.trickPlayModel,
|
||||
mediaSegments: syncedItem.mediaSegments,
|
||||
media: Media(syncedItem.videoFile.path),
|
||||
media: Media(url: syncedItem.videoFile.path),
|
||||
queue: itemQueue.whereNotNull().toList(),
|
||||
syncedQueue: children,
|
||||
mediaStreams: item.streamModel ?? syncedItemModel.streamModel,
|
||||
|
|
@ -170,7 +182,7 @@ class PlaybackModelHelper {
|
|||
subtitleStreamIndex: streamModel?.defaultSubStreamIndex,
|
||||
enableTranscoding: true,
|
||||
autoOpenLiveStream: true,
|
||||
deviceProfile: defaultProfile,
|
||||
deviceProfile: ref.read(videoProfileProvider),
|
||||
userId: userId,
|
||||
mediaSourceId: firstItemToPlay.id,
|
||||
),
|
||||
|
|
@ -218,7 +230,7 @@ class PlaybackModelHelper {
|
|||
chapters: chapters,
|
||||
playbackInfo: playbackInfo,
|
||||
trickPlay: trickPlay,
|
||||
media: Media('${ref.read(userProvider)?.server ?? ""}/Videos/${mediaSource.id}/stream?$params'),
|
||||
media: Media(url: '${ref.read(userProvider)?.server ?? ""}/Videos/${mediaSource.id}/stream?$params'),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
);
|
||||
} else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) {
|
||||
|
|
@ -229,7 +241,7 @@ class PlaybackModelHelper {
|
|||
chapters: chapters,
|
||||
trickPlay: trickPlay,
|
||||
playbackInfo: playbackInfo,
|
||||
media: Media("${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"),
|
||||
media: Media(url: "${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
);
|
||||
}
|
||||
|
|
@ -300,7 +312,7 @@ class PlaybackModelHelper {
|
|||
subtitleStreamIndex: subIndex,
|
||||
enableTranscoding: true,
|
||||
autoOpenLiveStream: true,
|
||||
deviceProfile: defaultProfile,
|
||||
deviceProfile: ref.read(videoProfileProvider),
|
||||
userId: userId,
|
||||
mediaSourceId: item.id,
|
||||
),
|
||||
|
|
@ -347,7 +359,7 @@ class PlaybackModelHelper {
|
|||
chapters: playbackModel.chapters,
|
||||
playbackInfo: playbackInfo,
|
||||
trickPlay: playbackModel.trickPlay,
|
||||
media: Media(directPlay),
|
||||
media: Media(url: directPlay),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
);
|
||||
} else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) {
|
||||
|
|
@ -358,7 +370,7 @@ class PlaybackModelHelper {
|
|||
chapters: playbackModel.chapters,
|
||||
playbackInfo: playbackInfo,
|
||||
trickPlay: playbackModel.trickPlay,
|
||||
media: Media("${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"),
|
||||
media: Media(url: "${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"),
|
||||
mediaStreams: mediaStreamsWithUrls,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
|
|
@ -13,9 +14,7 @@ import 'package:fladder/providers/api_provider.dart';
|
|||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_extensions.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart'
|
||||
if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:fladder/wrappers/media_control_wrapper.dart';
|
||||
|
||||
class TranscodePlaybackModel implements PlaybackModel {
|
||||
TranscodePlaybackModel({
|
||||
|
|
@ -67,22 +66,8 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
|
||||
@override
|
||||
Future<TranscodePlaybackModel> setSubtitle(SubStreamModel? model, MediaControlsWrapper player) async {
|
||||
final wantedSubtitle =
|
||||
model ?? subStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultSubStreamIndex);
|
||||
if (wantedSubtitle == null) return this;
|
||||
if (wantedSubtitle.index == SubStreamModel.no().index) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.no());
|
||||
} else {
|
||||
final subTracks = player.subTracks.getRange(2, player.subTracks.length).toList();
|
||||
final index = subStreams.sublist(1).indexWhere((element) => element.id == wantedSubtitle.id);
|
||||
final subTrack = subTracks.elementAtOrNull(index);
|
||||
if (wantedSubtitle.isExternal && wantedSubtitle.url != null && subTrack == null) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.uri(wantedSubtitle.url!));
|
||||
} else if (subTrack != null) {
|
||||
await player.setSubtitleTrack(subTrack);
|
||||
}
|
||||
}
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: wantedSubtitle.index));
|
||||
final newIndex = await player.setSubtitleTrack(model, this);
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -90,19 +75,8 @@ class TranscodePlaybackModel implements PlaybackModel {
|
|||
|
||||
@override
|
||||
Future<TranscodePlaybackModel>? setAudio(AudioStreamModel? model, MediaControlsWrapper player) async {
|
||||
final wantedAudioStream =
|
||||
model ?? audioStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultAudioStreamIndex);
|
||||
if (wantedAudioStream == null) return this;
|
||||
if (wantedAudioStream.index == AudioStreamModel.no().index) {
|
||||
await player.setAudioTrack(AudioTrack.no());
|
||||
} else {
|
||||
final audioTracks = player.audioTracks.getRange(2, player.audioTracks.length).toList();
|
||||
final audioTrack = audioTracks.elementAtOrNull(audioStreams.indexOf(wantedAudioStream) - 1);
|
||||
if (audioTrack != null) {
|
||||
await player.setAudioTrack(audioTrack);
|
||||
}
|
||||
}
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: wantedAudioStream.index));
|
||||
final newIndex = await player.setAudioTrack(model, this);
|
||||
return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: newIndex));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
|
|||
@Default(false) bool fillScreen,
|
||||
@Default(true) bool hardwareAccel,
|
||||
@Default(false) bool useLibass,
|
||||
PlayerOptions? playerOptions,
|
||||
@Default(100) double internalVolume,
|
||||
Set<DeviceOrientation>? allowedOrientations,
|
||||
@Default(AutoNextType.smart) AutoNextType nextVideoType,
|
||||
|
|
@ -33,8 +34,10 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
|
|||
|
||||
factory VideoPlayerSettingsModel.fromJson(Map<String, dynamic> json) => _$VideoPlayerSettingsModelFromJson(json);
|
||||
|
||||
PlayerOptions get wantedPlayer => playerOptions ?? PlayerOptions.platformDefaults;
|
||||
|
||||
bool playerSame(VideoPlayerSettingsModel other) {
|
||||
return other.hardwareAccel == hardwareAccel && other.useLibass == useLibass;
|
||||
return other.hardwareAccel == hardwareAccel && other.useLibass == useLibass && other.wantedPlayer == wantedPlayer;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -48,6 +51,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
|
|||
other.hardwareAccel == hardwareAccel &&
|
||||
other.useLibass == useLibass &&
|
||||
other.internalVolume == internalVolume &&
|
||||
other.playerOptions == playerOptions &&
|
||||
other.audioDevice == audioDevice;
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +67,27 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
|
|||
}
|
||||
}
|
||||
|
||||
enum PlayerOptions {
|
||||
libMDK,
|
||||
libMPV;
|
||||
|
||||
const PlayerOptions();
|
||||
|
||||
static Iterable<PlayerOptions> get available => kIsWeb ? {PlayerOptions.libMPV} : PlayerOptions.values;
|
||||
|
||||
static PlayerOptions get platformDefaults {
|
||||
if (kIsWeb) return PlayerOptions.libMPV;
|
||||
return switch (defaultTargetPlatform) {
|
||||
_ => PlayerOptions.libMPV,
|
||||
};
|
||||
}
|
||||
|
||||
String label(BuildContext context) => switch (this) {
|
||||
PlayerOptions.libMDK => "MDK",
|
||||
PlayerOptions.libMPV => "MPV",
|
||||
};
|
||||
}
|
||||
|
||||
enum AutoNextType {
|
||||
off,
|
||||
smart,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ mixin _$VideoPlayerSettingsModel {
|
|||
bool get fillScreen => throw _privateConstructorUsedError;
|
||||
bool get hardwareAccel => throw _privateConstructorUsedError;
|
||||
bool get useLibass => throw _privateConstructorUsedError;
|
||||
PlayerOptions? get playerOptions => throw _privateConstructorUsedError;
|
||||
double get internalVolume => throw _privateConstructorUsedError;
|
||||
Set<DeviceOrientation>? get allowedOrientations =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
|
@ -54,6 +55,7 @@ abstract class $VideoPlayerSettingsModelCopyWith<$Res> {
|
|||
bool fillScreen,
|
||||
bool hardwareAccel,
|
||||
bool useLibass,
|
||||
PlayerOptions? playerOptions,
|
||||
double internalVolume,
|
||||
Set<DeviceOrientation>? allowedOrientations,
|
||||
AutoNextType nextVideoType,
|
||||
|
|
@ -81,6 +83,7 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
|
|||
Object? fillScreen = null,
|
||||
Object? hardwareAccel = null,
|
||||
Object? useLibass = null,
|
||||
Object? playerOptions = freezed,
|
||||
Object? internalVolume = null,
|
||||
Object? allowedOrientations = freezed,
|
||||
Object? nextVideoType = null,
|
||||
|
|
@ -107,6 +110,10 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
|
|||
? _value.useLibass
|
||||
: useLibass // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
playerOptions: freezed == playerOptions
|
||||
? _value.playerOptions
|
||||
: playerOptions // ignore: cast_nullable_to_non_nullable
|
||||
as PlayerOptions?,
|
||||
internalVolume: null == internalVolume
|
||||
? _value.internalVolume
|
||||
: internalVolume // ignore: cast_nullable_to_non_nullable
|
||||
|
|
@ -142,6 +149,7 @@ abstract class _$$VideoPlayerSettingsModelImplCopyWith<$Res>
|
|||
bool fillScreen,
|
||||
bool hardwareAccel,
|
||||
bool useLibass,
|
||||
PlayerOptions? playerOptions,
|
||||
double internalVolume,
|
||||
Set<DeviceOrientation>? allowedOrientations,
|
||||
AutoNextType nextVideoType,
|
||||
|
|
@ -168,6 +176,7 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
|
|||
Object? fillScreen = null,
|
||||
Object? hardwareAccel = null,
|
||||
Object? useLibass = null,
|
||||
Object? playerOptions = freezed,
|
||||
Object? internalVolume = null,
|
||||
Object? allowedOrientations = freezed,
|
||||
Object? nextVideoType = null,
|
||||
|
|
@ -194,6 +203,10 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
|
|||
? _value.useLibass
|
||||
: useLibass // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
playerOptions: freezed == playerOptions
|
||||
? _value.playerOptions
|
||||
: playerOptions // ignore: cast_nullable_to_non_nullable
|
||||
as PlayerOptions?,
|
||||
internalVolume: null == internalVolume
|
||||
? _value.internalVolume
|
||||
: internalVolume // ignore: cast_nullable_to_non_nullable
|
||||
|
|
@ -224,6 +237,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
this.fillScreen = false,
|
||||
this.hardwareAccel = true,
|
||||
this.useLibass = false,
|
||||
this.playerOptions,
|
||||
this.internalVolume = 100,
|
||||
final Set<DeviceOrientation>? allowedOrientations,
|
||||
this.nextVideoType = AutoNextType.smart,
|
||||
|
|
@ -249,6 +263,8 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
@JsonKey()
|
||||
final bool useLibass;
|
||||
@override
|
||||
final PlayerOptions? playerOptions;
|
||||
@override
|
||||
@JsonKey()
|
||||
final double internalVolume;
|
||||
final Set<DeviceOrientation>? _allowedOrientations;
|
||||
|
|
@ -270,7 +286,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, audioDevice: $audioDevice)';
|
||||
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, playerOptions: $playerOptions, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, audioDevice: $audioDevice)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -283,6 +299,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
..add(DiagnosticsProperty('fillScreen', fillScreen))
|
||||
..add(DiagnosticsProperty('hardwareAccel', hardwareAccel))
|
||||
..add(DiagnosticsProperty('useLibass', useLibass))
|
||||
..add(DiagnosticsProperty('playerOptions', playerOptions))
|
||||
..add(DiagnosticsProperty('internalVolume', internalVolume))
|
||||
..add(DiagnosticsProperty('allowedOrientations', allowedOrientations))
|
||||
..add(DiagnosticsProperty('nextVideoType', nextVideoType))
|
||||
|
|
@ -313,6 +330,7 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
|||
final bool fillScreen,
|
||||
final bool hardwareAccel,
|
||||
final bool useLibass,
|
||||
final PlayerOptions? playerOptions,
|
||||
final double internalVolume,
|
||||
final Set<DeviceOrientation>? allowedOrientations,
|
||||
final AutoNextType nextVideoType,
|
||||
|
|
@ -333,6 +351,8 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
|||
@override
|
||||
bool get useLibass;
|
||||
@override
|
||||
PlayerOptions? get playerOptions;
|
||||
@override
|
||||
double get internalVolume;
|
||||
@override
|
||||
Set<DeviceOrientation>? get allowedOrientations;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ _$VideoPlayerSettingsModelImpl _$$VideoPlayerSettingsModelImplFromJson(
|
|||
fillScreen: json['fillScreen'] as bool? ?? false,
|
||||
hardwareAccel: json['hardwareAccel'] as bool? ?? true,
|
||||
useLibass: json['useLibass'] as bool? ?? false,
|
||||
playerOptions:
|
||||
$enumDecodeNullable(_$PlayerOptionsEnumMap, json['playerOptions']),
|
||||
internalVolume: (json['internalVolume'] as num?)?.toDouble() ?? 100,
|
||||
allowedOrientations: (json['allowedOrientations'] as List<dynamic>?)
|
||||
?.map((e) => $enumDecode(_$DeviceOrientationEnumMap, e))
|
||||
|
|
@ -33,6 +35,7 @@ Map<String, dynamic> _$$VideoPlayerSettingsModelImplToJson(
|
|||
'fillScreen': instance.fillScreen,
|
||||
'hardwareAccel': instance.hardwareAccel,
|
||||
'useLibass': instance.useLibass,
|
||||
'playerOptions': _$PlayerOptionsEnumMap[instance.playerOptions],
|
||||
'internalVolume': instance.internalVolume,
|
||||
'allowedOrientations': instance.allowedOrientations
|
||||
?.map((e) => _$DeviceOrientationEnumMap[e]!)
|
||||
|
|
@ -51,6 +54,11 @@ const _$BoxFitEnumMap = {
|
|||
BoxFit.scaleDown: 'scaleDown',
|
||||
};
|
||||
|
||||
const _$PlayerOptionsEnumMap = {
|
||||
PlayerOptions.libMDK: 'libMDK',
|
||||
PlayerOptions.libMPV: 'libMPV',
|
||||
};
|
||||
|
||||
const _$DeviceOrientationEnumMap = {
|
||||
DeviceOrientation.portraitUp: 'portraitUp',
|
||||
DeviceOrientation.landscapeLeft: 'landscapeLeft',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:ficonsax/ficonsax.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||
import 'package:fladder/models/items/chapters_model.dart';
|
||||
|
|
@ -73,8 +72,6 @@ class VideoPlayback {
|
|||
ItemStreamModel? currentItem,
|
||||
SyncedItem? currentSyncedItem,
|
||||
VideoStream? currentStream,
|
||||
Map<AudioStreamModel, AudioTrack>? audioMappings,
|
||||
Map<SubStreamModel, SubtitleTrack>? subMappings,
|
||||
}) {
|
||||
return VideoPlayback(
|
||||
queue: queue ?? this.queue,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue