diff --git a/lib/http/video.dart b/lib/http/video.dart index ffcfc867..bce29380 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -224,12 +224,18 @@ class VideoHttp { if (res.data['code'] == 0) { late PlayUrlModel data; switch (videoType) { - case VideoType.ugc || VideoType.pugv: + case VideoType.ugc: data = PlayUrlModel.fromJson(res.data['data']); + case VideoType.pugv: + var result = res.data['data']; + data = PlayUrlModel.fromJson(result) + ..lastPlayTime = + result?['play_view_business_info']?['user_status']?['watch_progress']?['current_watch_progress']; case VideoType.pgc: - data = PlayUrlModel.fromJson(res.data['result']['video_info']) - ..lastPlayTime = res - .data['result']?['play_view_business_info']?['user_status']?['watch_progress']?['current_watch_progress']; + var result = res.data['result']; + data = PlayUrlModel.fromJson(result['video_info']) + ..lastPlayTime = + result?['play_view_business_info']?['user_status']?['watch_progress']?['current_watch_progress']; } return {'status': true, 'data': data}; } else { @@ -639,6 +645,7 @@ class VideoHttp { // 视频播放进度 static Future heartBeat({ + aid, bvid, cid, progress, @@ -647,10 +654,11 @@ class VideoHttp { subType, required VideoType videoType, }) async { + final isPugv = videoType == VideoType.pugv; await Request().post( Api.heartBeat, queryParameters: { - 'bvid': bvid, + if (isPugv) 'aid': ?aid else 'bvid': ?bvid, 'cid': cid, 'epid': ?epid, 'sid': ?seasonId, diff --git a/lib/pages/common/common_intro_controller.dart b/lib/pages/common/common_intro_controller.dart index 6cbedd6e..53ef8501 100644 --- a/lib/pages/common/common_intro_controller.dart +++ b/lib/pages/common/common_intro_controller.dart @@ -49,7 +49,7 @@ abstract class CommonIntroController extends GetxController { final Rx videoDetail = VideoDetailData().obs; - Future queryVideoIntro(); + void queryVideoIntro(); bool prevPlay(); bool nextPlay(); diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index 13516037..c75249ae 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -71,7 +71,11 @@ class HistoryItem extends StatelessWidget { PageUtils.viewPgc(epId: item.history.epid); } else if (item.history.business == 'cheese') { if (item.uri?.isNotEmpty == true) { - PageUtils.viewPgcFromUri(item.uri!, isPgc: false); + PageUtils.viewPgcFromUri( + item.uri!, + isPgc: false, + aid: item.history.oid, + ); } } else { int? cid = diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index e6253f2e..c6d22adb 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -1130,6 +1130,7 @@ class VideoDetailController extends GetxController : Duration(milliseconds: data.timeLength!)), // 宽>高 水平 否则 垂直 isVertical: isVertical.value, + aid: aid, bvid: bvid, cid: cid.value, autoplay: autoplay ?? autoPlay.value, @@ -1599,6 +1600,7 @@ class VideoDetailController extends GetxController : playedTime!.inSeconds, type: HeartBeatType.status, isManual: true, + aid: aid, bvid: bvid, cid: cid.value, epid: isUgc ? null : epId, diff --git a/lib/pages/video/introduction/pgc/controller.dart b/lib/pages/video/introduction/pgc/controller.dart index b735091e..174ee622 100644 --- a/lib/pages/video/introduction/pgc/controller.dart +++ b/lib/pages/video/introduction/pgc/controller.dart @@ -312,8 +312,8 @@ class PgcIntroController extends CommonIntroController { hasLater.value = false; this.cid.value = cid; - queryVideoIntro(); queryOnlineTotal(); + queryVideoIntro(episode as EpisodeItem); } catch (e) { debugPrint('pgc onChangeEpisode: $e'); } @@ -467,8 +467,8 @@ class PgcIntroController extends CommonIntroController { } @override - Future queryVideoIntro() async { - final episode = pgcItem.episodes!.firstWhere((e) => e.cid == cid.value); + void queryVideoIntro([EpisodeItem? episode]) { + episode ??= pgcItem.episodes!.firstWhere((e) => e.cid == cid.value); videoPlayerServiceHandler.onVideoDetailChange( episode, cid.value, diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 787c3760..993d4493 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -118,6 +118,7 @@ class PlPlayerController { final bool _listenersInitialized = false; // 记录历史记录 + int? _aid; String _bvid = ''; int _cid = 0; dynamic _epid; @@ -528,6 +529,7 @@ class PlPlayerController { // 方向 bool? isVertical, // 记录历史记录 + int? aid, String bvid = '', int cid = 0, dynamic epid, @@ -553,6 +555,7 @@ class PlPlayerController { dataStatus.status.value = DataStatus.loading; // 初始化全屏方向 _isVertical = isVertical ?? false; + _aid = aid; _bvid = bvid; _cid = cid; _epid = epid; @@ -1440,6 +1443,7 @@ class PlPlayerController { int progress, { HeartBeatType type = HeartBeatType.playing, bool isManual = false, + dynamic aid, dynamic bvid, dynamic cid, dynamic epid, @@ -1467,6 +1471,7 @@ class PlPlayerController { if (type == HeartBeatType.status || type == HeartBeatType.completed) { await VideoHttp.heartBeat( + aid: aid ?? _aid, bvid: bvid ?? _bvid, cid: cid ?? _cid, progress: isComplete ? -1 : progress, @@ -1481,6 +1486,7 @@ class PlPlayerController { else if (progress - _heartDuration >= 5) { _heartDuration = progress; await VideoHttp.heartBeat( + aid: aid ?? _aid, bvid: bvid ?? _bvid, cid: cid ?? _cid, progress: progress, diff --git a/lib/utils/app_scheme.dart b/lib/utils/app_scheme.dart index 50b4a62d..1b99b77d 100644 --- a/lib/utils/app_scheme.dart +++ b/lib/utils/app_scheme.dart @@ -463,6 +463,14 @@ class PiliScheme { return true; } return false; + case 'cheese': + // bilibili://cheese/season/123456 + String? seasonId = uriDigitRegExp.firstMatch(path)?.group(1); + if (seasonId != null) { + PageUtils.viewPugv(seasonId: seasonId); + return true; + } + return false; default: if (!selfHandle) { // if (kDebugMode) debugPrint('$uri'); @@ -818,6 +826,7 @@ class PiliScheme { launchURL(); return false; case 'cheese': + // https://www.bilibili.com/cheese/play/ss123456 bool hasMatch = PageUtils.viewPgcFromUri(path, isPgc: false); if (hasMatch) { return true; diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart index b8ee00ff..5ab74e89 100644 --- a/lib/utils/page_utils.dart +++ b/lib/utils/page_utils.dart @@ -9,7 +9,6 @@ import 'package:PiliPlus/models/common/video/video_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart'; import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart'; -import 'package:PiliPlus/models_new/pgc/pgc_info_model/section.dart'; import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/contact/view.dart'; import 'package:PiliPlus/pages/fav_panel/view.dart'; @@ -699,6 +698,7 @@ class PageUtils { String uri, { bool isPgc = true, String? progress, + int? aid, }) { RegExpMatch? match = _pgcRegex.firstMatch(uri); if (match != null) { @@ -714,6 +714,7 @@ class PageUtils { viewPugv( seasonId: isSeason ? id : null, epId: isSeason ? null : id, + aid: aid, ); } return true; @@ -721,6 +722,22 @@ class PageUtils { return false; } + static EpisodeItem findEpisode( + List episodes, { + dynamic epId, + bool isPgc = true, + }) { + // epId episode -> progress episode -> first episode + EpisodeItem? episode; + if (epId != null) { + epId = epId.toString(); + episode = episodes.firstWhereOrNull( + (item) => (isPgc ? item.epId : item.id).toString() == epId, + ); + } + return episode ?? episodes.first; + } + static Future viewPgc({ dynamic seasonId, dynamic epId, @@ -732,66 +749,57 @@ class PageUtils { SmartDialog.dismiss(); if (result.isSuccess) { PgcInfoModel data = result.data; + final episodes = data.episodes; - // epId episode -> progress episode -> first episode - EpisodeItem? episode; - - if (epId != null) { - if (data.episodes?.isNotEmpty == true) { - episode = data.episodes!.firstWhereOrNull( - (item) { - return item.epId.toString() == epId.toString(); - }, - ); - } - if (episode == null && data.section?.isNotEmpty == true) { - for (Section item in data.section!) { - if (item.episodes?.isNotEmpty == true) { - for (EpisodeItem item in item.episodes!) { - if (item.epId.toString() == epId.toString()) { - // view as normal video - toVideoPage( - 'bvid=${item.bvid}&cid=${item.cid}&seasonId=${data.seasonId}&epId=${item.epId}', - arguments: { - 'pgcApi': true, - 'pic': item.cover, - 'heroTag': Utils.makeHeroTag(item.cid), - 'videoType': VideoType.ugc, - if (progress != null) - 'progress': int.tryParse(progress), - }, - preventDuplicates: false, - ); - return; + if (episodes != null && episodes.isNotEmpty) { + final EpisodeItem episode = findEpisode( + episodes, + epId: epId ?? data.userStatus?.progress?.lastEpId, + ); + toVideoPage( + 'bvid=${episode.bvid}&cid=${episode.cid}&seasonId=${data.seasonId}&epId=${episode.epId}&type=${data.type}', + arguments: { + 'pic': episode.cover, + 'heroTag': Utils.makeHeroTag(episode.cid), + 'videoType': VideoType.pgc, + 'pgcItem': data, + if (progress != null) 'progress': int.tryParse(progress), + }, + preventDuplicates: false, + ); + } else { + // find section + if (epId != null) { + final sections = data.section; + if (sections != null && sections.isNotEmpty) { + epId = epId.toString(); + for (var section in sections) { + final episodes = section.episodes; + if (episodes != null && episodes.isNotEmpty) { + for (var episode in episodes) { + if (episode.epId.toString() == epId) { + // view as ugc + toVideoPage( + 'bvid=${episode.bvid}&cid=${episode.cid}&seasonId=${data.seasonId}&epId=${episode.epId}', + arguments: { + 'pgcApi': true, + 'pic': episode.cover, + 'heroTag': Utils.makeHeroTag(episode.cid), + 'videoType': VideoType.ugc, + if (progress != null) + 'progress': int.tryParse(progress), + }, + preventDuplicates: false, + ); + return; + } } } } } } - } - - if (data.episodes.isNullOrEmpty) { SmartDialog.showToast('资源加载失败'); - return; } - - episode ??= data.userStatus?.progress?.lastEpId != null - ? data.episodes!.firstWhereOrNull( - (item) => item.epId == data.userStatus?.progress?.lastEpId, - ) ?? - data.episodes!.first - : data.episodes!.first; - toVideoPage( - 'bvid=${episode.bvid}&cid=${episode.cid}&seasonId=${data.seasonId}&epId=${episode.epId}&type=${data.type}', - arguments: { - 'pic': episode.cover, - 'heroTag': Utils.makeHeroTag(episode.cid), - 'videoType': VideoType.pgc, - 'pgcItem': data, - if (progress != null) 'progress': int.tryParse(progress), - }, - preventDuplicates: false, - ); } else { result.toast(); } @@ -802,27 +810,40 @@ class PageUtils { } } - static Future viewPugv({dynamic seasonId, dynamic epId}) async { + static Future viewPugv({ + dynamic seasonId, + dynamic epId, + int? aid, + }) async { try { SmartDialog.showLoading(msg: '资源获取中'); var res = await SearchHttp.pugvInfo(seasonId: seasonId, epId: epId); SmartDialog.dismiss(); if (res.isSuccess) { PgcInfoModel data = res.data; - if (data.episodes?.isNotEmpty == true) { - final item = data.episodes!.first; + final episodes = data.episodes; + if (episodes != null && episodes.isNotEmpty) { + EpisodeItem? episode; + if (aid != null) { + episode = episodes.firstWhereOrNull((e) => e.aid == aid); + } + episode ??= findEpisode( + episodes, + epId: epId ?? data.userStatus?.progress?.lastEpId, + isPgc: false, + ); toVideoPage( - 'bvid=${IdUtils.av2bv(item.aid!)}&cid=${item.cid}&seasonId=${data.seasonId}&epId=${item.id}', + 'bvid=${IdUtils.av2bv(episode.aid!)}&cid=${episode.cid}&seasonId=${data.seasonId}&epId=${episode.id}', arguments: { - 'pic': item.cover, - 'heroTag': Utils.makeHeroTag(item.cid), + 'pic': episode.cover, + 'heroTag': Utils.makeHeroTag(episode.cid), 'videoType': VideoType.pugv, 'pgcItem': data, }, preventDuplicates: false, ); } else { - SmartDialog.showToast('NULL'); + SmartDialog.showToast('资源加载失败'); } } else { res.toast();