diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 655c6e16..565148ae 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -155,6 +155,9 @@ class VideoDetailController extends GetxController showReplyReplyPanel() { replyReplyBottomSheetCtr = scaffoldKey.currentState?.showBottomSheet((BuildContext context) { + // SmartDialog.show( + // alignment: Alignment.bottomRight, + // builder: (context) { return VideoReplyReplyPanel( oid: oid.value, rpid: fRpid, @@ -391,8 +394,7 @@ class VideoDetailController extends GetxController /// 优先顺序 设置中指定质量 -> 当前可选的最高质量 late AudioItem? firstAudio; - final List audiosList = data.dash!.audio!; - + final List audiosList = data.dash!.audio ?? []; if (data.dash!.dolby?.audio != null && data.dash!.dolby!.audio!.isNotEmpty) { // 杜比 @@ -413,17 +415,17 @@ class VideoDetailController extends GetxController } firstAudio = audiosList.firstWhere((e) => e.id == closestNumber, orElse: () => audiosList.first); + audioUrl = enableCDN + ? VideoUtils.getCdnUrl(firstAudio) + : (firstAudio.backupUrl ?? firstAudio.baseUrl!); + if (firstAudio.id != null) { + currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!; + } } else { firstAudio = AudioItem(); + audioUrl = ''; } - - audioUrl = enableCDN - ? VideoUtils.getCdnUrl(firstAudio) - : (firstAudio.backupUrl ?? firstAudio.baseUrl!); // - if (firstAudio.id != null) { - currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!; - } defaultST = Duration(milliseconds: data.lastPlayTime!); if (autoPlay.value) { isShowCover.value = false; diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 32a5cfba..03ff24eb 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -24,6 +24,7 @@ import 'package:screen_brightness/screen_brightness.dart'; import 'package:universal_platform/universal_platform.dart'; import '../../models/video/play/subtitle.dart'; +import '../../pages/video/detail/controller.dart'; // import 'package:wakelock_plus/wakelock_plus.dart'; Box videoStorage = GStorage.video; @@ -509,7 +510,7 @@ class PlPlayerController { Player player = _videoPlayerController ?? Player( configuration: PlayerConfiguration( - // 默认缓冲 5M 大小 + // 默认缓冲 3M 大小 bufferSize: bufferSize, ), ); @@ -534,9 +535,8 @@ class PlPlayerController { await player.setAudioTrack( AudioTrack.auto(), ); - // 音轨 - if (dataSource.audioSource != '' && dataSource.audioSource != null) { + if (dataSource.audioSource?.isNotEmpty ?? false) { await pp.setProperty( 'audio-files', UniversalPlatform.isWindows @@ -574,7 +574,6 @@ class PlPlayerController { ); player.setPlaylistMode(looping); - if (dataSource.type == DataSourceType.asset) { final assetUrl = dataSource.videoSource!.startsWith("asset://") ? dataSource.videoSource! @@ -599,7 +598,25 @@ class PlPlayerController { Future refreshPlayer() async { Duration currentPos = _position.value; - await _videoPlayerController?.open( + if (_videoPlayerController == null) { + SmartDialog.showToast('视频播放器为空,请重新进入本页面'); + return; + } + if (dataSource.videoSource?.isEmpty ?? true) { + SmartDialog.showToast('视频源为空,请重新进入本页面'); + return; + } + if (dataSource.audioSource?.isEmpty ?? true) { + SmartDialog.showToast('音频源为空'); + } else { + await (_videoPlayerController!.platform as NativePlayer).setProperty( + 'audio-files', + UniversalPlatform.isWindows + ? dataSource.audioSource!.replaceAll(';', '\\;') + : dataSource.audioSource!.replaceAll(':', '\\:'), + ); + } + await _videoPlayerController!.open( Media( dataSource.videoSource!, httpHeaders: dataSource.httpHeaders, @@ -724,6 +741,29 @@ class PlPlayerController { videoPlayerServiceHandler.onStatusChange( playerStatus.status.value, event); }), + // videoPlayerController!.stream.log.listen((event) { + // print('videoPlayerController!.stream.log.listen'); + // print(event); + // SmartDialog.showToast('视频加载日志: $event'); + // }), + videoPlayerController!.stream.error.listen((event) { + if (event.startsWith("Failed to open https://")) { + EasyThrottle.throttle('videoPlayerController!.stream.error.listen', + const Duration(milliseconds: 1000), () { + SmartDialog.showToast('视频链接打开失败,重试中', + displayTime: const Duration(milliseconds: 500)); + refreshPlayer(); + }); + return; + } + print('videoPlayerController!.stream.error.listen'); + print(event); + //tcp: ffurl_read returned 0xdfb9b0bb + //tcp: ffurl_read returned 0xffffff99 + if (!event.startsWith('tcp: ffurl_read returned ')) { + SmartDialog.showToast('视频加载错误, $event'); + } + }), // videoPlayerController!.stream.volume.listen((event) { // if (!mute.value && _volumeBeforeMute != event) { // _volumeBeforeMute = event / 100; diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 08f1191a..3066fd08 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -1079,24 +1079,39 @@ class _PLVideoPlayerState extends State if (_.dataStatus.loading || _.isBuffering.value) { return Center( child: GestureDetector( - onTap: () { - _.refreshPlayer(); - }, - child: Container( - padding: const EdgeInsets.all(30), - decoration: const BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [Colors.black26, Colors.transparent], - ), - ), - child: Image.asset( - 'assets/images/loading.gif', - height: 25, - semanticLabel: "加载中", - ), - ), - )); + onTap: () { + _.refreshPlayer(); + }, + child: Container( + padding: const EdgeInsets.all(30), + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: RadialGradient( + colors: [Colors.black26, Colors.transparent], + ), + ), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Image.asset( + 'assets/images/loading.gif', + height: 25, + semanticLabel: "加载中", + ), + if (_.isBuffering.value) + Obx(() { + if (_.buffered.value == Duration.zero) { + return const Text('Buffering...', + style: TextStyle( + color: Colors.white, fontSize: 12)); + } + String bufferStr = _.buffered.toString(); + return Text( + bufferStr.substring(0, bufferStr.length - 3), + style: const TextStyle( + color: Colors.white, fontSize: 12), + ); + }), + ]), + ))); } else { return const SizedBox(); }