Merge branch 'design'
This commit is contained in:
@ -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<int> validateStatusCodes = [
|
||||
302,
|
||||
304,
|
||||
|
@ -27,11 +27,13 @@ class Request {
|
||||
late bool enableSystemProxy;
|
||||
late String systemProxyHost;
|
||||
late String systemProxyPort;
|
||||
static final RegExp spmPrefixExp = RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
|
||||
static final RegExp spmPrefixExp =
|
||||
RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
|
||||
|
||||
/// 设置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<int>.generate(32, (_) => rand.nextInt(256)) +
|
||||
List<int>.filled(4, 0) +
|
||||
[73, 69, 78, 68] +
|
||||
List<int>.generate(4, (_) => rand.nextInt(256))
|
||||
);
|
||||
List<int>.generate(32, (_) => rand.nextInt(256)) +
|
||||
List<int>.filled(4, 0) +
|
||||
[73, 69, 78, 68] +
|
||||
List<int>.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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: [],
|
||||
);
|
||||
|
@ -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<PlaySetting> {
|
||||
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),
|
||||
|
@ -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<String, dynamic> 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<SubTitileContentModel>((e) {
|
||||
// return SubTitileContentModel.fromJson(e);
|
||||
// }).toList();
|
||||
// setSubtitleContent();
|
||||
// }
|
||||
// 获取弹幕
|
||||
Future getDanmaku(List subtitles) async {
|
||||
if (subtitles.isNotEmpty) {
|
||||
for (var i in subtitles) {
|
||||
final Map<String, dynamic> res = await VideoHttp.getSubtitleContent(
|
||||
i.subtitleUrl,
|
||||
);
|
||||
i.content = res['content'];
|
||||
i.body = res['body'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSubtitleContent() {
|
||||
plPlayerController.subtitleContent.value = '';
|
||||
|
@ -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 {
|
||||
|
@ -188,7 +188,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
var data = snapshot.data;
|
||||
if (_videoReplyController.replyList.isNotEmpty ||
|
||||
(data && data['status'])) {
|
||||
(data != null && data['status'])) {
|
||||
// 请求成功
|
||||
return Obx(
|
||||
() => _videoReplyController.isLoadingMore &&
|
||||
|
@ -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<HeaderControl> createState() => _HeaderControlState();
|
||||
@ -426,7 +428,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
/// 选择字幕
|
||||
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<HeaderControl> {
|
||||
),
|
||||
...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<HeaderControl> {
|
||||
],
|
||||
|
||||
/// 字幕
|
||||
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(
|
||||
|
@ -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!) {
|
||||
|
@ -104,6 +104,8 @@ class SettingBoxKey {
|
||||
enablePlayerControlAnimation = 'enablePlayerControlAnimation',
|
||||
// 默认音频输出方式
|
||||
defaultAoOutput = 'defaultAoOutput',
|
||||
// 港澳台模式
|
||||
enableGATMode = 'enableGATMode',
|
||||
|
||||
// youtube 双击快进快退
|
||||
enableQuickDouble = 'enableQuickDouble',
|
||||
|
Reference in New Issue
Block a user