mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-26 21:40:11 +08:00
feat: interactive video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -47,6 +47,9 @@
|
|||||||
|
|
||||||
## feat
|
## feat
|
||||||
|
|
||||||
|
- [x] 互动视频
|
||||||
|
- [x] 发评反诈
|
||||||
|
- [x] 高能进度条
|
||||||
- [x] 滑动跳转预览视频缩略图
|
- [x] 滑动跳转预览视频缩略图
|
||||||
- [x] Live Photo
|
- [x] Live Photo
|
||||||
- [x] 复制/移动收藏夹/稍后再看视频
|
- [x] 复制/移动收藏夹/稍后再看视频
|
||||||
|
|||||||
@@ -977,7 +977,6 @@ class VideoHttp {
|
|||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
dynamic data = res.data['data'];
|
dynamic data = res.data['data'];
|
||||||
List subtitlesJson = data['subtitle']['subtitles'];
|
|
||||||
/*
|
/*
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -995,10 +994,11 @@ class VideoHttp {
|
|||||||
*/
|
*/
|
||||||
return {
|
return {
|
||||||
'status': true,
|
'status': true,
|
||||||
'data': subtitlesJson,
|
'data': data['subtitle']['subtitles'],
|
||||||
'view_points': data['view_points'],
|
'view_points': data['view_points'],
|
||||||
// 'last_play_time': data['last_play_time'],
|
// 'last_play_time': data['last_play_time'],
|
||||||
'last_play_cid': data['last_play_cid'],
|
'last_play_cid': data['last_play_cid'],
|
||||||
|
'interaction': data['interaction'],
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {'status': false, 'data': [], 'msg': res.data['message']};
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
|||||||
@@ -1846,6 +1846,31 @@ class VideoDetailController extends GetxController
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interactive video
|
||||||
|
dynamic graphVersion;
|
||||||
|
Map? steinEdgeInfo;
|
||||||
|
late final RxBool showSteinEdgeInfo = false.obs;
|
||||||
|
void getSteinEdgeInfo([edgeId]) async {
|
||||||
|
steinEdgeInfo = null;
|
||||||
|
try {
|
||||||
|
dynamic res = await Request().get(
|
||||||
|
'https://api.bilibili.com/x/stein/edgeinfo_v2',
|
||||||
|
queryParameters: {
|
||||||
|
'bvid': bvid,
|
||||||
|
'graph_version': graphVersion,
|
||||||
|
if (edgeId != null) 'edge_id': edgeId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
steinEdgeInfo = res.data['data'];
|
||||||
|
} else {
|
||||||
|
debugPrint('getSteinEdgeInfo error: ${res.data['message']}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('getSteinEdgeInfo: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
late bool continuePlayingPart = GStorage.continuePlayingPart;
|
late bool continuePlayingPart = GStorage.continuePlayingPart;
|
||||||
|
|
||||||
Future _querySubtitles() async {
|
Future _querySubtitles() async {
|
||||||
@@ -1854,6 +1879,19 @@ class VideoDetailController extends GetxController
|
|||||||
// SmartDialog.showToast('查询字幕错误,${res["msg"]}');
|
// SmartDialog.showToast('查询字幕错误,${res["msg"]}');
|
||||||
// }
|
// }
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
|
// interactive video
|
||||||
|
if (graphVersion == null) {
|
||||||
|
try {
|
||||||
|
final introCtr = Get.find<VideoIntroController>(tag: heroTag);
|
||||||
|
if (introCtr.videoDetail.value.rights?['is_stein_gate'] == 1) {
|
||||||
|
graphVersion = res['interaction']?['graph_version'];
|
||||||
|
getSteinEdgeInfo();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('handle stein: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (continuePlayingPart) {
|
if (continuePlayingPart) {
|
||||||
continuePlayingPart = false;
|
continuePlayingPart = false;
|
||||||
try {
|
try {
|
||||||
@@ -1945,7 +1983,7 @@ class VideoDetailController extends GetxController
|
|||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
onReset() {
|
onReset([isStein]) {
|
||||||
playedTime = null;
|
playedTime = null;
|
||||||
videoUrl = null;
|
videoUrl = null;
|
||||||
audioUrl = null;
|
audioUrl = null;
|
||||||
@@ -1968,6 +2006,13 @@ class VideoDetailController extends GetxController
|
|||||||
segmentList.clear();
|
segmentList.clear();
|
||||||
_segmentProgressList = null;
|
_segmentProgressList = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interactive video
|
||||||
|
if (isStein != true) {
|
||||||
|
graphVersion = null;
|
||||||
|
}
|
||||||
|
steinEdgeInfo = null;
|
||||||
|
showSteinEdgeInfo.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
late final showDmChart = GStorage.showDmChart;
|
late final showDmChart = GStorage.showDmChart;
|
||||||
|
|||||||
@@ -578,13 +578,13 @@ class VideoIntroController extends GetxController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改分P或番剧分集
|
// 修改分P或番剧分集
|
||||||
Future changeSeasonOrbangu(epid, bvid, cid, aid, cover) async {
|
Future changeSeasonOrbangu(epid, bvid, cid, aid, cover, [isStein]) async {
|
||||||
// 重新获取视频资源
|
// 重新获取视频资源
|
||||||
final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag)
|
final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag)
|
||||||
..plPlayerController.pause()
|
..plPlayerController.pause()
|
||||||
..makeHeartBeat()
|
..makeHeartBeat()
|
||||||
..updateMediaListHistory(aid)
|
..updateMediaListHistory(aid)
|
||||||
..onReset()
|
..onReset(isStein)
|
||||||
..bvid = bvid
|
..bvid = bvid
|
||||||
..oid.value = aid ?? IdUtils.bv2av(bvid)
|
..oid.value = aid ?? IdUtils.bv2av(bvid)
|
||||||
..cid.value = cid
|
..cid.value = cid
|
||||||
|
|||||||
@@ -240,6 +240,15 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
// 播放器状态监听
|
// 播放器状态监听
|
||||||
void playerListener(PlayerStatus? status) async {
|
void playerListener(PlayerStatus? status) async {
|
||||||
if (status == PlayerStatus.completed) {
|
if (status == PlayerStatus.completed) {
|
||||||
|
try {
|
||||||
|
if ((videoDetailController.steinEdgeInfo?['edges']['questions'][0]
|
||||||
|
['choices'] as List?)
|
||||||
|
?.isNotEmpty ==
|
||||||
|
true) {
|
||||||
|
videoDetailController.showSteinEdgeInfo.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
shutdownTimerService.handleWaitingFinished();
|
shutdownTimerService.handleWaitingFinished();
|
||||||
bool notExitFlag = false;
|
bool notExitFlag = false;
|
||||||
|
|
||||||
@@ -1421,6 +1430,69 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
// child: Text('index'),
|
// child: Text('index'),
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
|
|
||||||
|
Obx(
|
||||||
|
() {
|
||||||
|
if (videoDetailController.showSteinEdgeInfo.value) {
|
||||||
|
try {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: plPlayerController?.showControls.value == true
|
||||||
|
? 75
|
||||||
|
: 16,
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 25,
|
||||||
|
runSpacing: 10,
|
||||||
|
children: (videoDetailController.steinEdgeInfo!['edges']
|
||||||
|
['questions'][0]['choices'] as List)
|
||||||
|
.map((item) {
|
||||||
|
return FilledButton.tonal(
|
||||||
|
style: FilledButton.styleFrom(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
),
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.secondaryContainer
|
||||||
|
.withOpacity(0.8),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 15,
|
||||||
|
vertical: 10,
|
||||||
|
),
|
||||||
|
visualDensity:
|
||||||
|
VisualDensity(horizontal: -2, vertical: -2),
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
videoIntroController.changeSeasonOrbangu(
|
||||||
|
null,
|
||||||
|
videoDetailController.bvid,
|
||||||
|
item['cid'],
|
||||||
|
IdUtils.bv2av(videoDetailController.bvid),
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
videoDetailController
|
||||||
|
.getSteinEdgeInfo(item['id']);
|
||||||
|
},
|
||||||
|
child: Text(item['option']),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('build stein edges: $e');
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user