Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-04 11:13:50 +08:00
parent 2e614fa03c
commit 3208661a52
8 changed files with 120 additions and 70 deletions

View File

@@ -224,12 +224,18 @@ class VideoHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
late PlayUrlModel data; late PlayUrlModel data;
switch (videoType) { switch (videoType) {
case VideoType.ugc || VideoType.pugv: case VideoType.ugc:
data = PlayUrlModel.fromJson(res.data['data']); 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: case VideoType.pgc:
data = PlayUrlModel.fromJson(res.data['result']['video_info']) var result = res.data['result'];
..lastPlayTime = res data = PlayUrlModel.fromJson(result['video_info'])
.data['result']?['play_view_business_info']?['user_status']?['watch_progress']?['current_watch_progress']; ..lastPlayTime =
result?['play_view_business_info']?['user_status']?['watch_progress']?['current_watch_progress'];
} }
return {'status': true, 'data': data}; return {'status': true, 'data': data};
} else { } else {
@@ -639,6 +645,7 @@ class VideoHttp {
// 视频播放进度 // 视频播放进度
static Future heartBeat({ static Future heartBeat({
aid,
bvid, bvid,
cid, cid,
progress, progress,
@@ -647,10 +654,11 @@ class VideoHttp {
subType, subType,
required VideoType videoType, required VideoType videoType,
}) async { }) async {
final isPugv = videoType == VideoType.pugv;
await Request().post( await Request().post(
Api.heartBeat, Api.heartBeat,
queryParameters: { queryParameters: {
'bvid': bvid, if (isPugv) 'aid': ?aid else 'bvid': ?bvid,
'cid': cid, 'cid': cid,
'epid': ?epid, 'epid': ?epid,
'sid': ?seasonId, 'sid': ?seasonId,

View File

@@ -49,7 +49,7 @@ abstract class CommonIntroController extends GetxController {
final Rx<VideoDetailData> videoDetail = VideoDetailData().obs; final Rx<VideoDetailData> videoDetail = VideoDetailData().obs;
Future<void> queryVideoIntro(); void queryVideoIntro();
bool prevPlay(); bool prevPlay();
bool nextPlay(); bool nextPlay();

View File

@@ -71,7 +71,11 @@ class HistoryItem extends StatelessWidget {
PageUtils.viewPgc(epId: item.history.epid); PageUtils.viewPgc(epId: item.history.epid);
} else if (item.history.business == 'cheese') { } else if (item.history.business == 'cheese') {
if (item.uri?.isNotEmpty == true) { if (item.uri?.isNotEmpty == true) {
PageUtils.viewPgcFromUri(item.uri!, isPgc: false); PageUtils.viewPgcFromUri(
item.uri!,
isPgc: false,
aid: item.history.oid,
);
} }
} else { } else {
int? cid = int? cid =

View File

@@ -1130,6 +1130,7 @@ class VideoDetailController extends GetxController
: Duration(milliseconds: data.timeLength!)), : Duration(milliseconds: data.timeLength!)),
// 宽>高 水平 否则 垂直 // 宽>高 水平 否则 垂直
isVertical: isVertical.value, isVertical: isVertical.value,
aid: aid,
bvid: bvid, bvid: bvid,
cid: cid.value, cid: cid.value,
autoplay: autoplay ?? autoPlay.value, autoplay: autoplay ?? autoPlay.value,
@@ -1599,6 +1600,7 @@ class VideoDetailController extends GetxController
: playedTime!.inSeconds, : playedTime!.inSeconds,
type: HeartBeatType.status, type: HeartBeatType.status,
isManual: true, isManual: true,
aid: aid,
bvid: bvid, bvid: bvid,
cid: cid.value, cid: cid.value,
epid: isUgc ? null : epId, epid: isUgc ? null : epId,

View File

@@ -312,8 +312,8 @@ class PgcIntroController extends CommonIntroController {
hasLater.value = false; hasLater.value = false;
this.cid.value = cid; this.cid.value = cid;
queryVideoIntro();
queryOnlineTotal(); queryOnlineTotal();
queryVideoIntro(episode as EpisodeItem);
} catch (e) { } catch (e) {
debugPrint('pgc onChangeEpisode: $e'); debugPrint('pgc onChangeEpisode: $e');
} }
@@ -467,8 +467,8 @@ class PgcIntroController extends CommonIntroController {
} }
@override @override
Future<void> queryVideoIntro() async { void queryVideoIntro([EpisodeItem? episode]) {
final episode = pgcItem.episodes!.firstWhere((e) => e.cid == cid.value); episode ??= pgcItem.episodes!.firstWhere((e) => e.cid == cid.value);
videoPlayerServiceHandler.onVideoDetailChange( videoPlayerServiceHandler.onVideoDetailChange(
episode, episode,
cid.value, cid.value,

View File

@@ -118,6 +118,7 @@ class PlPlayerController {
final bool _listenersInitialized = false; final bool _listenersInitialized = false;
// 记录历史记录 // 记录历史记录
int? _aid;
String _bvid = ''; String _bvid = '';
int _cid = 0; int _cid = 0;
dynamic _epid; dynamic _epid;
@@ -528,6 +529,7 @@ class PlPlayerController {
// 方向 // 方向
bool? isVertical, bool? isVertical,
// 记录历史记录 // 记录历史记录
int? aid,
String bvid = '', String bvid = '',
int cid = 0, int cid = 0,
dynamic epid, dynamic epid,
@@ -553,6 +555,7 @@ class PlPlayerController {
dataStatus.status.value = DataStatus.loading; dataStatus.status.value = DataStatus.loading;
// 初始化全屏方向 // 初始化全屏方向
_isVertical = isVertical ?? false; _isVertical = isVertical ?? false;
_aid = aid;
_bvid = bvid; _bvid = bvid;
_cid = cid; _cid = cid;
_epid = epid; _epid = epid;
@@ -1440,6 +1443,7 @@ class PlPlayerController {
int progress, { int progress, {
HeartBeatType type = HeartBeatType.playing, HeartBeatType type = HeartBeatType.playing,
bool isManual = false, bool isManual = false,
dynamic aid,
dynamic bvid, dynamic bvid,
dynamic cid, dynamic cid,
dynamic epid, dynamic epid,
@@ -1467,6 +1471,7 @@ class PlPlayerController {
if (type == HeartBeatType.status || type == HeartBeatType.completed) { if (type == HeartBeatType.status || type == HeartBeatType.completed) {
await VideoHttp.heartBeat( await VideoHttp.heartBeat(
aid: aid ?? _aid,
bvid: bvid ?? _bvid, bvid: bvid ?? _bvid,
cid: cid ?? _cid, cid: cid ?? _cid,
progress: isComplete ? -1 : progress, progress: isComplete ? -1 : progress,
@@ -1481,6 +1486,7 @@ class PlPlayerController {
else if (progress - _heartDuration >= 5) { else if (progress - _heartDuration >= 5) {
_heartDuration = progress; _heartDuration = progress;
await VideoHttp.heartBeat( await VideoHttp.heartBeat(
aid: aid ?? _aid,
bvid: bvid ?? _bvid, bvid: bvid ?? _bvid,
cid: cid ?? _cid, cid: cid ?? _cid,
progress: progress, progress: progress,

View File

@@ -463,6 +463,14 @@ class PiliScheme {
return true; return true;
} }
return false; 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: default:
if (!selfHandle) { if (!selfHandle) {
// if (kDebugMode) debugPrint('$uri'); // if (kDebugMode) debugPrint('$uri');
@@ -818,6 +826,7 @@ class PiliScheme {
launchURL(); launchURL();
return false; return false;
case 'cheese': case 'cheese':
// https://www.bilibili.com/cheese/play/ss123456
bool hasMatch = PageUtils.viewPgcFromUri(path, isPgc: false); bool hasMatch = PageUtils.viewPgcFromUri(path, isPgc: false);
if (hasMatch) { if (hasMatch) {
return true; return true;

View File

@@ -9,7 +9,6 @@ import 'package:PiliPlus/models/common/video/video_type.dart';
import 'package:PiliPlus/models/dynamics/result.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/episode.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.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/common/common_intro_controller.dart';
import 'package:PiliPlus/pages/contact/view.dart'; import 'package:PiliPlus/pages/contact/view.dart';
import 'package:PiliPlus/pages/fav_panel/view.dart'; import 'package:PiliPlus/pages/fav_panel/view.dart';
@@ -699,6 +698,7 @@ class PageUtils {
String uri, { String uri, {
bool isPgc = true, bool isPgc = true,
String? progress, String? progress,
int? aid,
}) { }) {
RegExpMatch? match = _pgcRegex.firstMatch(uri); RegExpMatch? match = _pgcRegex.firstMatch(uri);
if (match != null) { if (match != null) {
@@ -714,6 +714,7 @@ class PageUtils {
viewPugv( viewPugv(
seasonId: isSeason ? id : null, seasonId: isSeason ? id : null,
epId: isSeason ? null : id, epId: isSeason ? null : id,
aid: aid,
); );
} }
return true; return true;
@@ -721,6 +722,22 @@ class PageUtils {
return false; return false;
} }
static EpisodeItem findEpisode(
List<EpisodeItem> 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<void> viewPgc({ static Future<void> viewPgc({
dynamic seasonId, dynamic seasonId,
dynamic epId, dynamic epId,
@@ -732,30 +749,42 @@ class PageUtils {
SmartDialog.dismiss(); SmartDialog.dismiss();
if (result.isSuccess) { if (result.isSuccess) {
PgcInfoModel data = result.data; PgcInfoModel data = result.data;
final episodes = data.episodes;
// epId episode -> progress episode -> first episode if (episodes != null && episodes.isNotEmpty) {
EpisodeItem? episode; final EpisodeItem episode = findEpisode(
episodes,
if (epId != null) { epId: epId ?? data.userStatus?.progress?.lastEpId,
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( toVideoPage(
'bvid=${item.bvid}&cid=${item.cid}&seasonId=${data.seasonId}&epId=${item.epId}', '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: { arguments: {
'pgcApi': true, 'pgcApi': true,
'pic': item.cover, 'pic': episode.cover,
'heroTag': Utils.makeHeroTag(item.cid), 'heroTag': Utils.makeHeroTag(episode.cid),
'videoType': VideoType.ugc, 'videoType': VideoType.ugc,
if (progress != null) if (progress != null)
'progress': int.tryParse(progress), 'progress': int.tryParse(progress),
@@ -769,29 +798,8 @@ class PageUtils {
} }
} }
} }
if (data.episodes.isNullOrEmpty) {
SmartDialog.showToast('资源加载失败'); 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 { } else {
result.toast(); result.toast();
} }
@@ -802,27 +810,40 @@ class PageUtils {
} }
} }
static Future<void> viewPugv({dynamic seasonId, dynamic epId}) async { static Future<void> viewPugv({
dynamic seasonId,
dynamic epId,
int? aid,
}) async {
try { try {
SmartDialog.showLoading(msg: '资源获取中'); SmartDialog.showLoading(msg: '资源获取中');
var res = await SearchHttp.pugvInfo(seasonId: seasonId, epId: epId); var res = await SearchHttp.pugvInfo(seasonId: seasonId, epId: epId);
SmartDialog.dismiss(); SmartDialog.dismiss();
if (res.isSuccess) { if (res.isSuccess) {
PgcInfoModel data = res.data; PgcInfoModel data = res.data;
if (data.episodes?.isNotEmpty == true) { final episodes = data.episodes;
final item = data.episodes!.first; 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( 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: { arguments: {
'pic': item.cover, 'pic': episode.cover,
'heroTag': Utils.makeHeroTag(item.cid), 'heroTag': Utils.makeHeroTag(episode.cid),
'videoType': VideoType.pugv, 'videoType': VideoType.pugv,
'pgcItem': data, 'pgcItem': data,
}, },
preventDuplicates: false, preventDuplicates: false,
); );
} else { } else {
SmartDialog.showToast('NULL'); SmartDialog.showToast('资源加载失败');
} }
} else { } else {
res.toast(); res.toast();