diff --git a/lib/http/constants.dart b/lib/http/constants.dart index cad413ef..b734c279 100644 --- a/lib/http/constants.dart +++ b/lib/http/constants.dart @@ -6,6 +6,7 @@ class HttpString { static const String liveBaseUrl = 'https://api.live.bilibili.com'; static const String passBaseUrl = 'https://passport.bilibili.com'; static const String messageBaseUrl = 'https://message.bilibili.com'; + static const String bangumiBaseUrl = 'https://bili.meark.me'; static const List validateStatusCodes = [ 302, 304, diff --git a/lib/http/init.dart b/lib/http/init.dart index a0b36369..cb9d6f39 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -27,11 +27,13 @@ class Request { late bool enableSystemProxy; late String systemProxyHost; late String systemProxyPort; - static final RegExp spmPrefixExp = RegExp(r''); + static final RegExp spmPrefixExp = + RegExp(r''); /// 设置cookie static setCookie() async { Box userInfoCache = GStrorage.userInfo; + Box setting = GStrorage.setting; final String cookiePath = await Utils.getCookiePath(); final PersistCookieJar cookieJar = PersistCookieJar( ignoreExpires: true, @@ -54,7 +56,11 @@ class Request { } } setOptionsHeaders(userInfo, userInfo != null && userInfo.mid != null); - + String baseUrlType = 'default'; + if (setting.get(SettingBoxKey.enableGATMode, defaultValue: false)) { + baseUrlType = 'bangumi'; + } + setBaseUrl(type: baseUrlType); try { await buvidActivate(); } catch (e) { @@ -95,11 +101,10 @@ class Request { String spmPrefix = spmPrefixExp.firstMatch(html.data)!.group(1)!; Random rand = Random(); String rand_png_end = base64.encode( - List.generate(32, (_) => rand.nextInt(256)) + - List.filled(4, 0) + - [73, 69, 78, 68] + - List.generate(4, (_) => rand.nextInt(256)) - ); + List.generate(32, (_) => rand.nextInt(256)) + + List.filled(4, 0) + + [73, 69, 78, 68] + + List.generate(4, (_) => rand.nextInt(256))); String jsonData = json.encode({ '3064': 1, @@ -110,11 +115,9 @@ class Request { }, }); - await Request().post( - Api.activateBuvidApi, - data: {'payload': jsonData}, - options: Options(contentType: 'application/json') - ); + await Request().post(Api.activateBuvidApi, + data: {'payload': jsonData}, + options: Options(contentType: 'application/json')); } /* @@ -294,4 +297,17 @@ class Request { } return headerUa; } + + static setBaseUrl({String type = 'default'}) { + switch (type) { + case 'default': + dio.options.baseUrl = HttpString.apiBaseUrl; + break; + case 'bangumi': + dio.options.baseUrl = HttpString.bangumiBaseUrl; + break; + default: + dio.options.baseUrl = HttpString.apiBaseUrl; + } + } } diff --git a/lib/models/common/subtitle_type.dart b/lib/models/common/subtitle_type.dart deleted file mode 100644 index ac3ee3e0..00000000 --- a/lib/models/common/subtitle_type.dart +++ /dev/null @@ -1,95 +0,0 @@ -enum SubtitleType { - // 中文(中国) - zhCN, - // 中文(自动翻译) - aizh, - // 英语(自动生成) - aien, - // 中文(简体) - zhHans, - // 英文(美国) - enUS, - // 中文繁体 - zhTW, - // - en, - // - pt, - // - es, -} - -extension SubtitleTypeExtension on SubtitleType { - String get description { - switch (this) { - case SubtitleType.zhCN: - return '中文(中国)'; - case SubtitleType.aizh: - return '中文(自动翻译)'; - case SubtitleType.aien: - return '英语(自动生成)'; - case SubtitleType.zhHans: - return '中文(简体)'; - case SubtitleType.enUS: - return '英文(美国)'; - case SubtitleType.zhTW: - return '中文(繁体)'; - case SubtitleType.en: - return '英文'; - case SubtitleType.pt: - return '葡萄牙语'; - case SubtitleType.es: - return '西班牙语'; - } - } -} - -extension SubtitleIdExtension on SubtitleType { - String get id { - switch (this) { - case SubtitleType.zhCN: - return 'zh-CN'; - case SubtitleType.aizh: - return 'ai-zh'; - case SubtitleType.aien: - return 'ai-en'; - case SubtitleType.zhHans: - return 'zh-Hans'; - case SubtitleType.enUS: - return 'en-US'; - case SubtitleType.zhTW: - return 'zh-TW'; - case SubtitleType.en: - return 'en'; - case SubtitleType.pt: - return 'pt'; - case SubtitleType.es: - return 'es'; - } - } -} - -extension SubtitleCodeExtension on SubtitleType { - int get code { - switch (this) { - case SubtitleType.zhCN: - return 1; - case SubtitleType.aizh: - return 2; - case SubtitleType.aien: - return 3; - case SubtitleType.zhHans: - return 4; - case SubtitleType.enUS: - return 5; - case SubtitleType.zhTW: - return 6; - case SubtitleType.en: - return 7; - case SubtitleType.pt: - return 8; - case SubtitleType.es: - return 9; - } - } -} diff --git a/lib/models/video/subTitile/result.dart b/lib/models/video/subTitile/result.dart index d3e32e55..e137439f 100644 --- a/lib/models/video/subTitile/result.dart +++ b/lib/models/video/subTitile/result.dart @@ -1,6 +1,3 @@ -import 'package:get/get.dart'; -import '../../common/subtitle_type.dart'; - class SubTitlteModel { SubTitlteModel({ this.aid, @@ -78,11 +75,6 @@ class SubTitlteItemModel { aiType: json["ai_type"], aiStatus: json["ai_status"], title: json["lan_doc"], - code: SubtitleType.values - .firstWhereOrNull( - (element) => element.id.toString() == json["lan"]) - ?.index ?? - -1, content: '', body: [], ); diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index 0f7dcdc3..cb8a3996 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; +import 'package:pilipala/http/init.dart'; import 'package:pilipala/models/video/play/ao_output.dart'; import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; @@ -163,6 +164,14 @@ class _PlaySettingState extends State { callFn: (bool val) { GlobalData().enablePlayerControlAnimation = val; }), + SetSwitchItem( + title: '港澳台模式', + setKey: SettingBoxKey.enableGATMode, + defaultVal: false, + callFn: (bool val) { + Request.setBaseUrl(type: val ? 'bangumi' : 'default'); + }, + ), ListTile( dense: false, title: Text('默认视频画质', style: titleStyle), diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index ea85a5b9..c5e37be1 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -141,13 +141,7 @@ class VideoDetailController extends GetxController if (Platform.isAndroid) { floating = Floating(); } - headerControl = HeaderControl( - controller: plPlayerController, - videoDetailCtr: this, - floating: floating, - bvid: bvid, - videoType: videoType, - ); + // CDN优化 enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true); // 预设的画质 @@ -158,7 +152,18 @@ class VideoDetailController extends GetxController defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa, defaultValue: AudioQuality.hiRes.code); oid.value = IdUtils.bv2av(Get.parameters['bvid']!); - getSubtitle(); + getSubtitle().then( + (subtitles) { + headerControl = HeaderControl( + controller: plPlayerController, + videoDetailCtr: this, + floating: floating, + bvid: bvid, + videoType: videoType, + showSubtitleBtn: subtitles.isNotEmpty, + ); + }, + ); } showReplyReplyPanel(oid, fRpid, firstFloor) { @@ -432,28 +437,24 @@ class VideoDetailController extends GetxController if (result['status']) { if (result['data'].subtitles.isNotEmpty) { subtitles = result['data'].subtitles; - if (subtitles.isNotEmpty) { - for (var i in subtitles) { - final Map res = await VideoHttp.getSubtitleContent( - i.subtitleUrl, - ); - i.content = res['content']; - i.body = res['body']; - } - } + getDanmaku(subtitles); } - return result['data']; + return subtitles; } } - // 获取字幕内容 - // Future getSubtitleContent(String url) async { - // var res = await Request().get('https:$url'); - // subtitleContents.value = res.data['body'].map((e) { - // return SubTitileContentModel.fromJson(e); - // }).toList(); - // setSubtitleContent(); - // } + // 获取弹幕 + Future getDanmaku(List subtitles) async { + if (subtitles.isNotEmpty) { + for (var i in subtitles) { + final Map res = await VideoHttp.getSubtitleContent( + i.subtitleUrl, + ); + i.content = res['content']; + i.body = res['body']; + } + } + } setSubtitleContent() { plPlayerController.subtitleContent.value = ''; diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 1a1b1b74..50aac4cd 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -435,7 +435,8 @@ class VideoIntroController extends GetxController { videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.cover.value = cover; videoDetailCtr.queryVideoUrl(); - videoDetailCtr.getSubtitle(); + videoDetailCtr.clearSubtitleContent(); + await videoDetailCtr.getSubtitle(); videoDetailCtr.setSubtitleContent(); // 重新请求评论 try { diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index be1bd331..4fe69481 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -188,7 +188,7 @@ class _VideoReplyPanelState extends State if (snapshot.connectionState == ConnectionState.done) { var data = snapshot.data; if (_videoReplyController.replyList.isNotEmpty || - (data && data['status'])) { + (data != null && data['status'])) { // 请求成功 return Obx( () => _videoReplyController.isLoadingMore && diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 5072377a..f3b9549a 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -30,6 +30,7 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget { this.floating, this.bvid, this.videoType, + this.showSubtitleBtn, super.key, }); final PlPlayerController? controller; @@ -37,6 +38,7 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget { final Floating? floating; final String? bvid; final SearchType? videoType; + final bool? showSubtitleBtn; @override State createState() => _HeaderControlState(); @@ -426,7 +428,12 @@ class _HeaderControlState extends State { /// 选择字幕 void showSubtitleDialog() async { int tempThemeValue = widget.controller!.subTitleCode.value; - int len = widget.videoDetailCtr!.subtitles.length; + final List subtitles = widget.videoDetailCtr!.subtitles; + int len = subtitles.length; + if (subtitles.firstWhereOrNull((element) => element.id == tempThemeValue) == + null) { + tempThemeValue = -1; + } showDialog( context: context, builder: (BuildContext context) { @@ -458,7 +465,7 @@ class _HeaderControlState extends State { ), ...widget.videoDetailCtr!.subtitles .map((e) => RadioListTile( - value: e.code, + value: e.id, title: Text(e.title), groupValue: tempThemeValue, onChanged: (value) { @@ -1322,14 +1329,15 @@ class _HeaderControlState extends State { ], /// 字幕 - ComBtn( - icon: const Icon( - Icons.closed_caption_off, - size: 22, - color: Colors.white, + if (widget.showSubtitleBtn!) + ComBtn( + icon: const Icon( + Icons.closed_caption_off, + size: 22, + color: Colors.white, + ), + fuc: () => showSubtitleDialog(), ), - fuc: () => showSubtitleDialog(), - ), SizedBox(width: buttonSpace), Obx( () => SizedBox( diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index a614d75d..a5de33fd 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -123,7 +123,7 @@ class PlPlayerController { PreferredSizeWidget? headerControl; PreferredSizeWidget? bottomControl; Widget? danmuWidget; - late RxList subtitles; + RxList subtitles = [].obs; String videoType = 'archive'; /// 数据加载监听 @@ -642,10 +642,6 @@ class PlPlayerController { const Duration(seconds: 1), () => videoPlayerServiceHandler.onPositionChange(event)); }), - - // onSubTitleOpenChanged.listen((bool event) { - // toggleSubtitle(event ? subTitleCode.value : -1); - // }) ], ); } @@ -1049,25 +1045,6 @@ class PlPlayerController { void toggleSubtitle(int code) { _subTitleOpen.value = code != -1; _subTitleCode.value = code; - // if (code == -1) { - // // 关闭字幕 - // _subTitleOpen.value = false; - // _subTitleCode.value = code; - // _videoPlayerController?.setSubtitleTrack(SubtitleTrack.no()); - // return; - // } - // final SubTitlteItemModel? subtitle = subtitles?.firstWhereOrNull( - // (element) => element.code == code, - // ); - // _subTitleOpen.value = true; - // _subTitleCode.value = code; - // _videoPlayerController?.setSubtitleTrack( - // SubtitleTrack.data( - // subtitle!.content!, - // title: subtitle.title, - // language: subtitle.lan, - // ), - // ); } void querySubtitleContent(double progress) { @@ -1079,7 +1056,7 @@ class PlPlayerController { return; } final SubTitlteItemModel? subtitle = subtitles.firstWhereOrNull( - (element) => element.code == subTitleCode.value, + (element) => element.id == subTitleCode.value, ); if (subtitle != null && subtitle.body!.isNotEmpty) { for (var content in subtitle.body!) { diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index bf9074e3..dca5a158 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -104,6 +104,8 @@ class SettingBoxKey { enablePlayerControlAnimation = 'enablePlayerControlAnimation', // 默认音频输出方式 defaultAoOutput = 'defaultAoOutput', + // 港澳台模式 + enableGATMode = 'enableGATMode', // youtube 双击快进快退 enableQuickDouble = 'enableQuickDouble',