chore: Play BigBuckBunny for every fake item (#243)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2025-02-28 10:17:05 +01:00 committed by GitHub
parent 3ca3d72b9c
commit 485de0d7b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 110 additions and 36 deletions

View file

@ -641,6 +641,44 @@ class FakeJellyfinOpenApi extends JellyfinOpenApi {
const BaseItemDtoQueryResult(),
);
}
@override
Future<chopper.Response<PlaybackInfoResponse>> itemsItemIdPlaybackInfoPost({
required String? itemId,
String? userId,
int? maxStreamingBitrate,
int? startTimeTicks,
int? audioStreamIndex,
int? subtitleStreamIndex,
int? maxAudioChannels,
String? mediaSourceId,
String? liveStreamId,
bool? autoOpenLiveStream,
bool? enableDirectPlay,
bool? enableDirectStream,
bool? enableTranscoding,
bool? allowVideoStreamCopy,
bool? allowAudioStreamCopy,
required PlaybackInfoDto? body,
}) async {
return chopper.Response(
FakeHelper.fakeCorrectResponse,
FakeHelper.bigBuckBunny,
);
}
@override
Future<chopper.Response<MediaSegmentDtoQueryResult>> mediaSegmentsItemIdGet({
required String? itemId,
List<enums.MediaSegmentType>? includeSegmentTypes,
}) async {
return chopper.Response(
FakeHelper.fakeCorrectResponse,
const MediaSegmentDtoQueryResult(
items: [],
),
);
}
}
class FakeHelper {
@ -700,4 +738,30 @@ class FakeHelper {
accessToken: 'A_TOTALLY_REAL_TOKEN',
serverId: "1",
);
static PlaybackInfoResponse bigBuckBunny = PlaybackInfoResponse.fromJson({
"MediaSources": [
{
"Protocol": "File",
"Id": "234sdfsdf234",
"Path": "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
"Type": "Default",
"Container": "mkv",
"Size": 513949601,
"Name": "Big Buck Bunny",
"IsRemote": false,
"ETag": "sdfsdfsd",
"RunTimeTicks": 26540060000,
"SupportsTranscoding": false,
"SupportsDirectStream": true,
"SupportsDirectPlay": true,
"VideoType": "VideoFile",
"MediaAttachments": [],
"Formats": [],
"Bitrate": 1741204,
"HasSegments": true
}
],
"PlaySessionId": "asdf234qwafsdfsdf"
});
}

View file

@ -190,8 +190,8 @@ class PlaybackModelHelper {
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,
videoBitRate: firstItemToPlay.streamModel?.videoStreams.firstOrNull?.bitRate ?? 0,
videoCodec: firstItemToPlay.streamModel?.videoStreams.firstOrNull?.codec,
),
);
@ -215,9 +215,12 @@ class PlaybackModelHelper {
);
PlaybackInfoResponse? playbackInfo = response.body;
if (playbackInfo == null) return null;
final mediaSource = playbackInfo.mediaSources?.first;
final mediaSource = playbackInfo.mediaSources?[streamModel?.versionStreamIndex ?? 0];
if (mediaSource == null) return null;
final mediaStreamsWithUrls = MediaStreamsModel.fromMediaStreamsList(playbackInfo.mediaSources, ref).copyWith(
defaultAudioStreamIndex: streamModel?.defaultAudioStreamIndex,
@ -228,9 +231,7 @@ class PlaybackModelHelper {
final trickPlay = (await api.getTrickPlay(item: fullItem.body, ref: ref))?.body;
final chapters = fullItem.body?.overview.chapters ?? [];
final mediaPath = isValidVideoUrl(mediaSource?.path ?? "");
if (mediaSource == null) return null;
final mediaPath = isValidVideoUrl(mediaSource.path ?? "");
if ((mediaSource.supportsDirectStream ?? false) || (mediaSource.supportsDirectPlay ?? false)) {
final Map<String, String?> directOptions = {
@ -271,6 +272,7 @@ class PlaybackModelHelper {
playbackInfo: playbackInfo,
media: Media(url: "${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"),
mediaStreams: mediaStreamsWithUrls,
bitRateOptions: qualityOptions,
);
}
return null;

View file

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/widgets.dart';
import 'package:collection/collection.dart';
@ -49,42 +51,47 @@ class VideoQualitySettings {
}
Map<Bitrate, bool> getVideoQualityOptions(VideoQualitySettings options) {
final maxStreamingBitrate = options.maxBitRate;
final videoBitRate = options.videoBitRate;
final videoCodec = options.videoCodec;
double referenceBitRate = videoBitRate.toDouble();
try {
final maxStreamingBitrate = options.maxBitRate;
final videoBitRate = options.videoBitRate;
final videoCodec = options.videoCodec;
double referenceBitRate = videoBitRate.toDouble();
final bitRateValues = Bitrate.values.where((value) => value.calculatedBitRate > 0).toSet();
final bitRateValues = Bitrate.values.where((value) => value.calculatedBitRate > 0).toSet();
final qualityOptions = <Bitrate>{Bitrate.original, Bitrate.auto};
final qualityOptions = <Bitrate>{Bitrate.original, Bitrate.auto};
if (videoBitRate > 0 && videoBitRate < bitRateValues.first.calculatedBitRate) {
if (videoCodec != null && ['hevc', 'av1', 'vp9'].contains(videoCodec) && referenceBitRate <= 20000000) {
referenceBitRate *= 1.5;
if (videoBitRate > 0 && videoBitRate < bitRateValues.first.calculatedBitRate) {
if (videoCodec != null && ['hevc', 'av1', 'vp9'].contains(videoCodec) && referenceBitRate <= 20000000) {
referenceBitRate *= 1.5;
}
final sourceOption = bitRateValues.where((value) => value.calculatedBitRate > referenceBitRate).lastOrNull;
if (sourceOption != null) {
qualityOptions.add(sourceOption);
}
}
final sourceOption = bitRateValues.where((value) => value.calculatedBitRate > referenceBitRate).lastOrNull;
qualityOptions
.addAll(bitRateValues.where((value) => videoBitRate <= 0 || value.calculatedBitRate <= referenceBitRate));
if (sourceOption != null) {
qualityOptions.add(sourceOption);
Bitrate? selectedQualityOption;
if (maxStreamingBitrate != null && maxStreamingBitrate != Bitrate.original) {
selectedQualityOption = qualityOptions
.where((value) =>
value.calculatedBitRate > 0 && value.calculatedBitRate <= maxStreamingBitrate.calculatedBitRate)
.firstOrNull;
}
return qualityOptions.toList().asMap().map(
(_, bitrate) => MapEntry(
bitrate,
bitrate == maxStreamingBitrate || bitrate == selectedQualityOption,
),
);
} catch (e) {
log(e.toString());
return {};
}
qualityOptions
.addAll(bitRateValues.where((value) => videoBitRate <= 0 || value.calculatedBitRate <= referenceBitRate));
Bitrate? selectedQualityOption;
if (maxStreamingBitrate != null && maxStreamingBitrate != Bitrate.original) {
selectedQualityOption = qualityOptions
.where(
(value) => value.calculatedBitRate > 0 && value.calculatedBitRate <= maxStreamingBitrate.calculatedBitRate)
.firstOrNull;
}
return qualityOptions.toList().asMap().map(
(_, bitrate) => MapEntry(
bitrate,
bitrate == maxStreamingBitrate || bitrate == selectedQualityOption,
),
);
}

View file

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';