diff --git a/README.md b/README.md index b0fee0cba..6a061c7bf 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ ## feat +- [x] SponsorBlock - [x] 显示视频完整合集 - [x] 三连动画 - [x] 番剧三连 diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index bd508611f..16ffaa2d1 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'dart:io'; import 'package:PiliPalaX/http/danmaku.dart'; +import 'package:PiliPalaX/http/init.dart'; +import 'package:dio/dio.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -90,6 +92,8 @@ class VideoDetailController extends GetxController PlayerStatus? playerStatus; + StreamSubscription? positionSubscription; + @override void onInit() { super.onInit(); @@ -147,6 +151,57 @@ class VideoDetailController extends GetxController cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa, defaultValue: AudioQuality.hiRes.code); oid.value = IdUtils.bv2av(Get.parameters['bvid']!); + _sponsorBlock(); + } + + List? _segmentList; + + Future _sponsorBlock() async { + dynamic result = await Request().get( + 'https://www.bsbsb.top/api/skipSegments', + data: {'videoID': bvid}, + options: Options( + headers: { + 'env': '', + 'app-key': '', + 'x-bili-mid': '', + 'x-bili-aurora-eid': '', + 'x-bili-aurora-zone': '', + HttpHeaders.cookieHeader: + 'buvid3= ; SESSDATA= ; bili_jct= ; DedeUserID= ; DedeUserID__ckMd5= ; sid= ', + }, + ), + ); + if (result.data is List && result.data.isNotEmpty) { + _segmentList = (result.data as List) + .where((item) => item['category'] == 'sponsor') + .toList() + .map((item) => item['segment']) + .toList(); + } + } + + void _initSkip() { + if (_segmentList != null && _segmentList!.isNotEmpty) { + positionSubscription = plPlayerController + .videoPlayerController?.stream.position + .listen((position) async { + for (List item in _segmentList!) { + // debugPrint( + // '${position.inSeconds},,${(item.first as double).round()}'); + if ((item.first as double).round() == position.inSeconds) { + try { + await plPlayerController + .seekTo(Duration(seconds: (item[1] as double).round())); + SmartDialog.showToast('已跳过赞助商广告'); + } catch (e) { + debugPrint('failed to skip: $e'); + SmartDialog.showToast('广告跳过失败'); + } + } + } + }); + } } /// 发送弹幕 @@ -346,6 +401,8 @@ class VideoDetailController extends GetxController autoplay: autoplay, ); + _initSkip(); + /// 开启自动全屏时,在player初始化完成后立即传入headerControl plPlayerController.headerControl = headerControl; } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 4b051ed4c..3d1151011 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -277,6 +277,7 @@ class _VideoDetailPageState extends State ScreenBrightness().resetScreenBrightness(); PlPlayerController.setPlayCallBack(null); } + videoDetailController.positionSubscription?.cancel(); appbarStream.close(); floating.dispose(); videoDetailController.floating?.dispose(); @@ -308,6 +309,8 @@ class _VideoDetailPageState extends State ScreenBrightness().resetScreenBrightness(); + videoDetailController.positionSubscription?.cancel(); + videoDetailController.playerStatus = plPlayerController?.playerStatus.status.value; diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 402bd4e75..e80b2b905 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -1321,6 +1321,7 @@ class PlPlayerController { var pp = _videoPlayerController!.platform as NativePlayer; await pp.setProperty('audio-files', ''); removeListeners(); + await _videoPlayerController?.stop(); await _videoPlayerController?.dispose(); _videoPlayerController = null; }