diff --git a/lib/models/video/play/quality.dart b/lib/models/video/play/quality.dart index 6cae84cc..7bedf62a 100644 --- a/lib/models/video/play/quality.dart +++ b/lib/models/video/play/quality.dart @@ -39,6 +39,14 @@ extension VideoQualityCode on VideoQuality { } return null; } + + static int? toCode(VideoQuality quality) { + final index = VideoQuality.values.indexOf(quality); + if (index != -1 && index < _codeList.length) { + return _codeList[index]; + } + return null; + } } extension VideoQualityDesc on VideoQuality { diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index 2098302d..b26028cf 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -236,6 +236,7 @@ class BangumiIntroController extends GetxController { videoDetailCtr.bvid = bvid; videoDetailCtr.cid.value = cid; videoDetailCtr.danmakuCid.value = cid; + videoDetailCtr.oid.value = aid; videoDetailCtr.queryVideoUrl(); // 重新请求评论 try { diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index b01f3be7..3e965f34 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -85,7 +85,9 @@ class _BangumiPanelState extends State { item.cid, item.aid, ); - _bottomSheetController?.close(); + if (_bottomSheetController != null) { + _bottomSheetController?.close(); + } currentIndex = i; scrollToIndex(); } diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 4d40e535..3cc43005 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -51,7 +51,7 @@ class VideoDetailController extends GetxController /// 播放器配置 画质 音质 解码格式 late VideoQuality currentVideoQa; AudioQuality? currentAudioQa; - late VideoDecodeFormats currentDecodeFormats; + VideoDecodeFormats? currentDecodeFormats; // 是否开始自动播放 存在多p的情况下,第二p需要为true RxBool autoPlay = true.obs; // 视频资源是否有效 @@ -107,6 +107,7 @@ class VideoDetailController extends GetxController BottomControlType.fullscreen, ].obs; RxDouble sheetHeight = 0.0.obs; + RxString archiveSourceType = 'dash'.obs; @override void onInit() { @@ -189,37 +190,43 @@ class VideoDetailController extends GetxController plPlayerController.isBuffering.value = false; plPlayerController.buffered.value = Duration.zero; - /// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl - List videoList = - data.dash!.video!.where((i) => i.id == currentVideoQa.code).toList(); - try { - firstVideo = videoList - .firstWhere((i) => i.codecs!.startsWith(currentDecodeFormats.code)); - } catch (_) { - if (currentVideoQa == VideoQuality.dolbyVision) { - firstVideo = videoList.first; - currentDecodeFormats = - VideoDecodeFormatsCode.fromString(videoList.first.codecs!)!; - } else { - // 当前格式不可用 - currentDecodeFormats = VideoDecodeFormatsCode.fromString(setting.get( - SettingBoxKey.defaultDecode, - defaultValue: VideoDecodeFormats.values.last.code))!; - firstVideo = videoList - .firstWhere((i) => i.codecs!.startsWith(currentDecodeFormats.code)); + if (archiveSourceType.value == 'dash') { + /// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl + List videoList = + data.dash!.video!.where((i) => i.id == currentVideoQa.code).toList(); + try { + firstVideo = videoList.firstWhere( + (i) => i.codecs!.startsWith(currentDecodeFormats?.code)); + } catch (_) { + if (currentVideoQa == VideoQuality.dolbyVision) { + firstVideo = videoList.first; + currentDecodeFormats = + VideoDecodeFormatsCode.fromString(videoList.first.codecs!)!; + } else { + // 当前格式不可用 + currentDecodeFormats = VideoDecodeFormatsCode.fromString(setting.get( + SettingBoxKey.defaultDecode, + defaultValue: VideoDecodeFormats.values.last.code))!; + firstVideo = videoList.firstWhere( + (i) => i.codecs!.startsWith(currentDecodeFormats?.code)); + } + } + videoUrl = firstVideo.baseUrl!; + + /// 根据currentAudioQa 重新设置audioUrl + if (currentAudioQa != null) { + final AudioItem firstAudio = data.dash!.audio!.firstWhere( + (AudioItem i) => i.id == currentAudioQa!.code, + orElse: () => data.dash!.audio!.first, + ); + audioUrl = firstAudio.baseUrl ?? ''; } } - videoUrl = firstVideo.baseUrl!; - /// 根据currentAudioQa 重新设置audioUrl - if (currentAudioQa != null) { - final AudioItem firstAudio = data.dash!.audio!.firstWhere( - (AudioItem i) => i.id == currentAudioQa!.code, - orElse: () => data.dash!.audio!.first, - ); - audioUrl = firstAudio.baseUrl ?? ''; + if (archiveSourceType.value == 'durl') { + cacheVideoQa = VideoQualityCode.toCode(currentVideoQa); + queryVideoUrl(); } - playerInit(); } @@ -272,7 +279,8 @@ class VideoDetailController extends GetxController // 视频链接 Future queryVideoUrl() async { - var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid); + var result = + await VideoHttp.videoUrl(cid: cid.value, bvid: bvid, qn: cacheVideoQa); if (result['status']) { data = result['data']; if (data.acceptDesc!.isNotEmpty && data.acceptDesc!.contains('试看')) { @@ -290,8 +298,22 @@ class VideoDetailController extends GetxController } return result; } + if (data.durl != null) { + archiveSourceType.value = 'durl'; + videoUrl = data.durl!.first.url!; + audioUrl = ''; + defaultST = Duration.zero; + firstVideo = VideoItem(); + currentVideoQa = VideoQualityCode.fromCode(data.quality!)!; + if (autoPlay.value) { + await playerInit(); + isShowCover.value = false; + } + return result; + } final List allVideosList = data.dash!.video!; try { + archiveSourceType.value = 'dash'; // 当前可播放的最高质量视频 int currentHighVideoQa = allVideosList.first.quality!.code; // 预设的画质为null,则当前可用的最高质量 @@ -321,7 +343,7 @@ class VideoDetailController extends GetxController // 当前视频没有对应格式返回第一个 bool flag = false; for (var i in supportDecodeFormats) { - if (i.startsWith(currentDecodeFormats.code)) { + if (i.startsWith(currentDecodeFormats?.code)) { flag = true; } } @@ -335,7 +357,7 @@ class VideoDetailController extends GetxController /// 取出符合当前解码格式的videoItem try { firstVideo = videosList.firstWhere( - (e) => e.codecs!.startsWith(currentDecodeFormats.code)); + (e) => e.codecs!.startsWith(currentDecodeFormats?.code)); } catch (_) { firstVideo = videosList.first; } diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index e00311c5..6acd20d7 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -180,15 +180,16 @@ class _HeaderControlState extends State { '当前音质 ${widget.videoDetailCtr!.currentAudioQa!.description}', style: subTitleStyle), ), - ListTile( - onTap: () => {Get.back(), showSetDecodeFormats()}, - dense: true, - leading: const Icon(Icons.av_timer_outlined, size: 20), - title: const Text('解码格式', style: titleStyle), - subtitle: Text( - '当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}', - style: subTitleStyle), - ), + if (widget.videoDetailCtr!.currentDecodeFormats != null) + ListTile( + onTap: () => {Get.back(), showSetDecodeFormats()}, + dense: true, + leading: const Icon(Icons.av_timer_outlined, size: 20), + title: const Text('解码格式', style: titleStyle), + subtitle: Text( + '当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats!.description}', + style: subTitleStyle), + ), ListTile( onTap: () => {Get.back(), showSetRepeat()}, dense: true, @@ -541,16 +542,24 @@ class _HeaderControlState extends State { /// 可用的质量分类 int userfulQaSam = 0; - final List video = videoInfo.dash!.video!; - final Set idSet = {}; - for (final VideoItem item in video) { - final int id = item.id!; - if (!idSet.contains(id)) { - idSet.add(id); - userfulQaSam++; + if (videoInfo.dash != null) { + // dash格式视频一次请求会返回所有可播放的清晰度video + final List video = videoInfo.dash!.video!; + final Set idSet = {}; + for (final VideoItem item in video) { + final int id = item.id!; + if (!idSet.contains(id)) { + idSet.add(id); + userfulQaSam++; + } } } + if (videoInfo.durl != null) { + // durl格式视频一次请求返回对应清晰度video + userfulQaSam = videoFormat.length - 1; + } + showModalBottomSheet( context: context, elevation: 0, @@ -707,7 +716,7 @@ class _HeaderControlState extends State { void showSetDecodeFormats() { // 当前选中的解码格式 final VideoDecodeFormats currentDecodeFormats = - widget.videoDetailCtr!.currentDecodeFormats; + widget.videoDetailCtr!.currentDecodeFormats!; final VideoItem firstVideo = widget.videoDetailCtr!.firstVideo; // 当前视频可用的解码格式 final List videoFormat = videoInfo.supportFormats!;