diff --git a/lib/common/widgets/disabled_icon.dart b/lib/common/widgets/disabled_icon.dart index b5732a340..fa1554756 100644 --- a/lib/common/widgets/disabled_icon.dart +++ b/lib/common/widgets/disabled_icon.dart @@ -22,8 +22,6 @@ class DisabledIcon extends SingleChildRenderObjectWidget { final StrokeCap strokeCap; final double lineLengthScale; - T enable() => child as T; - @override RenderObject createRenderObject(BuildContext context) { late final iconTheme = IconTheme.of(context); @@ -31,12 +29,12 @@ class DisabledIcon extends SingleChildRenderObjectWidget { disable: disable, iconSize: iconSize ?? - (child is Icon ? (child as Icon?)?.size : null) ?? + (child is Icon ? (child as Icon).size : null) ?? iconTheme.size ?? 24.0, color: color ?? - (child is Icon ? (child as Icon?)?.color : null) ?? + (child is Icon ? (child as Icon).color : null) ?? iconTheme.color!, strokeCap: strokeCap, lineLengthScale: lineLengthScale, diff --git a/lib/common/widgets/image/network_img_layer.dart b/lib/common/widgets/image/network_img_layer.dart index 648332172..c6a7528c1 100644 --- a/lib/common/widgets/image/network_img_layer.dart +++ b/lib/common/widgets/image/network_img_layer.dart @@ -15,7 +15,7 @@ class NetworkImgLayer extends StatelessWidget { this.type = .def, this.fadeOutDuration = const Duration(milliseconds: 120), this.fadeInDuration = const Duration(milliseconds: 120), - this.quality, + this.quality = 1, this.borderRadius = StyleString.mdRadius, this.getPlaceHolder, this.fit = .cover, @@ -29,7 +29,7 @@ class NetworkImgLayer extends StatelessWidget { final ImageType type; final Duration fadeOutDuration; final Duration fadeInDuration; - final int? quality; + final int quality; final BorderRadius borderRadius; final ValueGetter? getPlaceHolder; final BoxFit fit; diff --git a/lib/pages/live_emote/view.dart b/lib/pages/live_emote/view.dart index 3991ba6ee..13398e044 100644 --- a/lib/pages/live_emote/view.dart +++ b/lib/pages/live_emote/view.dart @@ -152,7 +152,7 @@ class _LiveEmotePanelState extends State width: width, height: height, type: ImageType.emote, - quality: item.pkgType == 3 ? null : 80, + quality: item.pkgType == 3 ? 1 : 80, ), ), ), diff --git a/lib/pages/rcmd/view.dart b/lib/pages/rcmd/view.dart index 048d9cca5..40cb0261c 100644 --- a/lib/pages/rcmd/view.dart +++ b/lib/pages/rcmd/view.dart @@ -79,9 +79,7 @@ class _RcmdPageState extends CommonPageState child: Card( child: Container( alignment: Alignment.center, - padding: const EdgeInsets.symmetric( - horizontal: 10, - ), + padding: const .symmetric(horizontal: 10), child: Text( '上次看到这里\n点击刷新', textAlign: .center, @@ -95,9 +93,7 @@ class _RcmdPageState extends CommonPageState ), ); } - int actualIndex = controller.lastRefreshAt == null - ? index - : index > controller.lastRefreshAt! + final actualIndex = index > controller.lastRefreshAt! ? index - 1 : index; return VideoCardV( diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 8ce2012b1..6a385775e 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -205,8 +205,8 @@ class _VideoDetailPageVState extends State } } - void playCallBack() { - plPlayerController?.play(); + Future? playCallBack() { + return plPlayerController?.play(); } // 播放器状态监听 diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index d4d9aa808..c75f05967 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -496,15 +496,15 @@ class PlPlayerController { return _instance != null; } - static void setPlayCallBack(VoidCallback? playCallBack) { + static void setPlayCallBack(Future? Function()? playCallBack) { _playCallBack = playCallBack; } - static VoidCallback? _playCallBack; + static Future? Function()? _playCallBack; - static void playIfExists() { + static Future? playIfExists() { // await _instance?.play(repeat: repeat, hideControls: hideControls); - _playCallBack?.call(); + return _playCallBack?.call(); } // try to get PlayerStatus @@ -819,7 +819,7 @@ class PlPlayerController { } // 音轨 - late final String audioUri; + final String audioUri; if (isFileSource) { audioUri = onlyPlayAudio.value || mediaType == 1 ? '' @@ -969,9 +969,9 @@ class PlPlayerController { } late final bool enableAutoEnter = Pref.enableAutoEnter; - Future autoEnterFullscreen() async { + Future? autoEnterFullscreen() { if (enableAutoEnter) { - Future.delayed(const Duration(milliseconds: 500), () { + return Future.delayed(const Duration(milliseconds: 500), () { if (dataStatus.status.value != DataStatus.loaded) { _stopListenerForEnterFullScreen(); _dataListenerForEnterFullScreen = dataStatus.status.listen((status) { @@ -981,10 +981,11 @@ class PlPlayerController { } }); } else { - triggerFullScreen(status: true); + return triggerFullScreen(status: true); } }); } + return null; } Set subscriptions = {}; diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index eee4b41d0..d687f0a87 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -2601,7 +2601,7 @@ Future _getImg(String url) async { final cacheKey = Utils.getFileName(url, fileExt: false); try { final fileInfo = await cacheManager.getSingleFile( - url, + ImageUtils.safeThumbnailUrl(url), key: cacheKey, headers: Constants.baseHeaders, ); diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 26c58664c..7222d39b0 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -1,3 +1,5 @@ +import 'dart:io' show File; + import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/grpc/bilibili/app/listener/v1.pb.dart' show DetailItem; import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart'; @@ -8,8 +10,11 @@ import 'package:PiliPlus/models_new/video/video_detail/page.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/plugin/pl_player/models/play_status.dart'; import 'package:PiliPlus/utils/extension/iterable_ext.dart'; +import 'package:PiliPlus/utils/image_utils.dart'; +import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:audio_service/audio_service.dart'; +import 'package:path/path.dart' as path; Future initAudioService() { return AudioService.init( @@ -31,35 +36,37 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { static final List _item = []; bool enableBackgroundPlay = Pref.enableBackgroundPlay; - Function? onPlay; - Function? onPause; - Function(Duration position)? onSeek; + Future Function()? onPlay; + Future Function()? onPause; + Future Function(Duration position)? onSeek; @override - Future play() async { - onPlay?.call() ?? PlPlayerController.playIfExists(); + Future play() { + return onPlay?.call() ?? + PlPlayerController.playIfExists() ?? + Future.syncValue(null); // player.play(); } @override - Future pause() async { - await (onPause?.call() ?? PlPlayerController.pauseIfExists()); + Future pause() { + return onPause?.call() ?? PlPlayerController.pauseIfExists(); // player.pause(); } @override - Future seek(Duration position) async { + Future seek(Duration position) { playbackState.add( playbackState.value.copyWith( updatePosition: position, ), ); - await (onSeek?.call(position) ?? + return (onSeek?.call(position) ?? PlPlayerController.seekToIfExists(position, isSeek: false)); // await player.seekTo(position); } - Future setMediaItem(MediaItem newMediaItem) async { + void setMediaItem(MediaItem newMediaItem) { if (!enableBackgroundPlay) return; // if (kDebugMode) { // debugPrint("此时调用栈为:"); @@ -70,11 +77,11 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { if (!mediaItem.isClosed) mediaItem.add(newMediaItem); } - Future setPlaybackState( + void setPlaybackState( PlayerStatus status, bool isBuffering, bool isLive, - ) async { + ) { if (!enableBackgroundPlay || _item.isEmpty || !PlPlayerController.instanceExists()) { @@ -137,6 +144,8 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { if (!PlPlayerController.instanceExists()) return; if (data == null) return; + Uri getUri(String? cover) => Uri.parse(ImageUtils.safeThumbnailUrl(cover)); + late final id = '$cid$herotag'; MediaItem? mediaItem; if (data is VideoDetailData) { @@ -149,7 +158,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { title: current?.part ?? '', artist: data.owner?.name, duration: Duration(seconds: current?.duration ?? 0), - artUri: Uri.parse(data.pic ?? ''), + artUri: getUri(data.pic), ); } else { mediaItem = MediaItem( @@ -157,7 +166,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { title: data.title ?? '', artist: data.owner?.name, duration: Duration(seconds: data.duration ?? 0), - artUri: Uri.parse(data.pic ?? ''), + artUri: getUri(data.pic), ); } } else if (data is EpisodeItem) { @@ -168,14 +177,14 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { duration: data.from == 'pugv' ? Duration(seconds: data.duration ?? 0) : Duration(milliseconds: data.duration ?? 0), - artUri: Uri.parse(data.cover ?? ''), + artUri: getUri(data.cover), ); } else if (data is RoomInfoH5Data) { mediaItem = MediaItem( id: id, title: data.roomInfo?.title ?? '', artist: data.anchorInfo?.baseInfo?.uname, - artUri: Uri.parse(data.roomInfo?.cover ?? ''), + artUri: getUri(data.roomInfo?.cover), isLive: true, ); } else if (data is Part) { @@ -184,7 +193,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { title: data.part ?? '', artist: artist, duration: Duration(seconds: data.duration ?? 0), - artUri: Uri.parse(cover ?? ''), + artUri: getUri(cover), ); } else if (data is DetailItem) { mediaItem = MediaItem( @@ -192,15 +201,19 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { title: data.arc.title, artist: data.owner.name, duration: Duration(seconds: data.arc.duration.toInt()), - artUri: Uri.parse(data.arc.cover), + artUri: getUri(data.arc.cover), ); } else if (data is BiliDownloadEntryInfo) { + final coverFile = File(path.join(data.entryDirPath, PathUtils.coverName)); + final uri = coverFile.existsSync() + ? coverFile.absolute.uri + : getUri(data.cover); mediaItem = MediaItem( id: id, title: data.showTitle, artist: data.ownerName, duration: Duration(milliseconds: data.totalTimeMilli), - artUri: Uri.parse(data.cover), + artUri: uri, ); } if (mediaItem == null) return; diff --git a/lib/utils/image_utils.dart b/lib/utils/image_utils.dart index ac796db58..88f8cd084 100644 --- a/lib/utils/image_utils.dart +++ b/lib/utils/image_utils.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:math' as math; import 'dart:typed_data'; import 'package:PiliPlus/common/constants.dart'; @@ -267,22 +268,23 @@ abstract final class ImageUtils { r'(@(\d+[a-z]_?)*)(\..*)?$', caseSensitive: false, ); - static String thumbnailUrl(String? src, [int? quality]) { - if (src != null && quality != 100) { + static String thumbnailUrl(String? src, [int maxQuality = 1]) { + if (src != null && maxQuality != 100) { + maxQuality = math.max(maxQuality, GlobalData().imgQuality); bool hasMatch = false; src = src.splitMapJoin( _thumbRegex, - onMatch: (Match match) { + onMatch: (match) { hasMatch = true; String suffix = match.group(3) ?? '.webp'; - return '${match.group(1)}_${quality ?? GlobalData().imgQuality}q$suffix'; + return '${match.group(1)}_${maxQuality}q$suffix'; }, onNonMatch: (String str) { return str; }, ); if (!hasMatch) { - src += '@${quality ?? GlobalData().imgQuality}q.webp'; + src += '@${maxQuality}q.webp'; } } return src.http2https; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 2f4d20bb3..c5eb10677 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -162,9 +162,14 @@ abstract final class Utils { return randomBase64.substring(0, randomBase64.length - 2); } + static int _getExt(String uri) { + final i = uri.indexOf('?'); + return i == -1 ? uri.length : i; + } + static String getFileName(String uri, {bool fileExt = true}) { final i0 = uri.lastIndexOf('/') + 1; - final i1 = fileExt ? uri.length : uri.lastIndexOf('.'); + final i1 = fileExt ? _getExt(uri) : uri.lastIndexOf('.'); return uri.substring(i0, i1); }