mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: cellular video/audio qa
Closes #52 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:PiliPalaX/utils/utils.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
@@ -77,29 +77,8 @@ class ApiInterceptor extends Interceptor {
|
||||
case DioExceptionType.sendTimeout:
|
||||
return '发送请求超时,请检查网络设置';
|
||||
case DioExceptionType.unknown:
|
||||
final String res = await checkConnect();
|
||||
final String res = (await Utils.checkConnectivity()).title;
|
||||
return '$res网络异常 ${error.error}';
|
||||
}
|
||||
}
|
||||
|
||||
static Future<String> checkConnect() async {
|
||||
final List<ConnectivityResult> connectivityResult =
|
||||
await Connectivity().checkConnectivity();
|
||||
switch (connectivityResult.first) {
|
||||
case ConnectivityResult.mobile:
|
||||
return '流量';
|
||||
case ConnectivityResult.wifi:
|
||||
return 'Wi-Fi';
|
||||
case ConnectivityResult.ethernet:
|
||||
return '局域';
|
||||
case ConnectivityResult.vpn:
|
||||
return '代理';
|
||||
case ConnectivityResult.other:
|
||||
return '其他';
|
||||
case ConnectivityResult.none:
|
||||
return '无';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,12 +68,13 @@ class _MainAppState extends State<MainApp>
|
||||
}
|
||||
|
||||
void _checkDefaultSearch([bool shouldCheck = false]) {
|
||||
if (shouldCheck &&
|
||||
_mainController.pages[_mainController.pageController.page?.round() ?? 0]
|
||||
is! HomePage) {
|
||||
return;
|
||||
}
|
||||
if (_homeController.enableSearchWord) {
|
||||
if (shouldCheck &&
|
||||
_mainController
|
||||
.pages[_mainController.pageController.page?.round() ?? 0]
|
||||
is! HomePage) {
|
||||
return;
|
||||
}
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - _homeController.lateCheckAt >= 5 * 60 * 1000) {
|
||||
_homeController.lateCheckAt = now;
|
||||
|
||||
@@ -148,11 +148,10 @@ class _ExtraSettingState extends State<ExtraSetting> {
|
||||
leading: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
const Icon(Icons.shield),
|
||||
const Icon(Icons.shield_outlined),
|
||||
Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
size: 18,
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
size: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -20,7 +20,9 @@ class VideoSetting extends StatefulWidget {
|
||||
class _VideoSettingState extends State<VideoSetting> {
|
||||
Box setting = GStorage.setting;
|
||||
late dynamic defaultVideoQa;
|
||||
late dynamic defaultVideoQaCellular;
|
||||
late dynamic defaultAudioQa;
|
||||
late dynamic defaultAudioQaCellular;
|
||||
late dynamic defaultDecode;
|
||||
late dynamic secondDecode;
|
||||
late dynamic hardwareDecoding;
|
||||
@@ -30,20 +32,42 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
defaultVideoQa = setting.get(SettingBoxKey.defaultVideoQa,
|
||||
defaultValue: VideoQuality.values.last.code);
|
||||
defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa,
|
||||
defaultValue: AudioQuality.values.last.code);
|
||||
defaultDecode = setting.get(SettingBoxKey.defaultDecode,
|
||||
defaultValue: VideoDecodeFormats.values.last.code);
|
||||
secondDecode = setting.get(SettingBoxKey.secondDecode,
|
||||
defaultValue: VideoDecodeFormats.values[1].code);
|
||||
hardwareDecoding = setting.get(SettingBoxKey.hardwareDecoding,
|
||||
defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto');
|
||||
videoSync =
|
||||
setting.get(SettingBoxKey.videoSync, defaultValue: 'display-resample');
|
||||
defaultCDNService = setting.get(SettingBoxKey.CDNService,
|
||||
defaultValue: CDNService.backupUrl.code);
|
||||
defaultVideoQa = setting.get(
|
||||
SettingBoxKey.defaultVideoQa,
|
||||
defaultValue: VideoQuality.values.last.code,
|
||||
);
|
||||
defaultVideoQaCellular = setting.get(
|
||||
SettingBoxKey.defaultVideoQaCellular,
|
||||
defaultValue: VideoQuality.high1080.code,
|
||||
);
|
||||
defaultAudioQa = setting.get(
|
||||
SettingBoxKey.defaultAudioQa,
|
||||
defaultValue: AudioQuality.values.last.code,
|
||||
);
|
||||
defaultAudioQaCellular = setting.get(
|
||||
SettingBoxKey.defaultAudioQaCellular,
|
||||
defaultValue: AudioQuality.k192.code,
|
||||
);
|
||||
defaultDecode = setting.get(
|
||||
SettingBoxKey.defaultDecode,
|
||||
defaultValue: VideoDecodeFormats.values.last.code,
|
||||
);
|
||||
secondDecode = setting.get(
|
||||
SettingBoxKey.secondDecode,
|
||||
defaultValue: VideoDecodeFormats.values[1].code,
|
||||
);
|
||||
hardwareDecoding = setting.get(
|
||||
SettingBoxKey.hardwareDecoding,
|
||||
defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto',
|
||||
);
|
||||
videoSync = setting.get(
|
||||
SettingBoxKey.videoSync,
|
||||
defaultValue: 'display-resample',
|
||||
);
|
||||
defaultCDNService = setting.get(
|
||||
SettingBoxKey.CDNService,
|
||||
defaultValue: CDNService.backupUrl.code,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -79,26 +103,25 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
defaultVal: true,
|
||||
),
|
||||
ListTile(
|
||||
enabled: false,
|
||||
onTap: null,
|
||||
title: Text("b站定向流量支持", style: titleStyle),
|
||||
title: Text("B站定向流量支持", style: titleStyle),
|
||||
subtitle:
|
||||
Text("若套餐含b站定向流量,则会自动使用。可查阅运营商的流量记录确认。", style: subTitleStyle),
|
||||
Text("若套餐含B站定向流量,则会自动使用。可查阅运营商的流量记录确认。", style: subTitleStyle),
|
||||
leading: const Icon(Icons.perm_data_setting_outlined),
|
||||
trailing: Transform.scale(
|
||||
alignment: Alignment.centerRight, // 缩放Switch的大小后保持右侧对齐, 避免右侧空隙过大
|
||||
scale: 0.8,
|
||||
child: Switch(
|
||||
thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
|
||||
(Set<WidgetState> states) {
|
||||
if (states.isNotEmpty &&
|
||||
states.first == WidgetState.selected) {
|
||||
return const Icon(Icons.done);
|
||||
}
|
||||
return null; // All other states will use the default thumbIcon.
|
||||
}),
|
||||
value: true,
|
||||
onChanged: null),
|
||||
thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
|
||||
(Set<WidgetState> states) {
|
||||
if (states.isNotEmpty &&
|
||||
states.first == WidgetState.selected) {
|
||||
return const Icon(Icons.lock_outline_rounded);
|
||||
}
|
||||
return null; // All other states will use the default thumbIcon.
|
||||
}),
|
||||
value: true,
|
||||
onChanged: (_) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
@@ -147,11 +170,12 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SelectDialog<int>(
|
||||
title: '默认画质',
|
||||
value: defaultVideoQa,
|
||||
values: VideoQuality.values.reversed.map((e) {
|
||||
return {'title': e.description, 'value': e.code};
|
||||
}).toList());
|
||||
title: '默认画质',
|
||||
value: defaultVideoQa,
|
||||
values: VideoQuality.values.reversed.map((e) {
|
||||
return {'title': e.description, 'value': e.code};
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (result != null) {
|
||||
@@ -161,6 +185,34 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: false,
|
||||
title: Text('蜂窝网络画质', style: titleStyle),
|
||||
leading: const Icon(Icons.video_settings_outlined),
|
||||
subtitle: Text(
|
||||
'当前画质:${VideoQualityCode.fromCode(defaultVideoQaCellular)!.description!}',
|
||||
style: subTitleStyle,
|
||||
),
|
||||
onTap: () async {
|
||||
int? result = await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SelectDialog<int>(
|
||||
title: '蜂窝网络画质',
|
||||
value: defaultVideoQaCellular,
|
||||
values: VideoQuality.values.reversed.map((e) {
|
||||
return {'title': e.description, 'value': e.code};
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (result != null) {
|
||||
defaultVideoQaCellular = result;
|
||||
setting.put(SettingBoxKey.defaultVideoQaCellular, result);
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: false,
|
||||
title: Text('默认音质', style: titleStyle),
|
||||
@@ -174,11 +226,12 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SelectDialog<int>(
|
||||
title: '默认音质',
|
||||
value: defaultAudioQa,
|
||||
values: AudioQuality.values.reversed.map((e) {
|
||||
return {'title': e.description, 'value': e.code};
|
||||
}).toList());
|
||||
title: '默认音质',
|
||||
value: defaultAudioQa,
|
||||
values: AudioQuality.values.reversed.map((e) {
|
||||
return {'title': e.description, 'value': e.code};
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (result != null) {
|
||||
@@ -188,6 +241,34 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: false,
|
||||
title: Text('蜂窝网络音质', style: titleStyle),
|
||||
leading: const Icon(Icons.music_video_outlined),
|
||||
subtitle: Text(
|
||||
'当前音质:${AudioQualityCode.fromCode(defaultAudioQaCellular)!.description!}',
|
||||
style: subTitleStyle,
|
||||
),
|
||||
onTap: () async {
|
||||
int? result = await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SelectDialog<int>(
|
||||
title: '蜂窝网络音质',
|
||||
value: defaultAudioQaCellular,
|
||||
values: AudioQuality.values.reversed.map((e) {
|
||||
return {'title': e.description, 'value': e.code};
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (result != null) {
|
||||
defaultAudioQaCellular = result;
|
||||
setting.put(SettingBoxKey.defaultAudioQaCellular, result);
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: false,
|
||||
title: Text('首选解码格式', style: titleStyle),
|
||||
|
||||
@@ -18,6 +18,7 @@ import 'package:PiliPalaX/pages/video/detail/related/controller.dart';
|
||||
import 'package:PiliPalaX/pages/video/detail/reply/controller.dart';
|
||||
import 'package:PiliPalaX/utils/extension.dart';
|
||||
import 'package:canvas_danmaku/models/danmaku_content_item.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:floating/floating.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -206,7 +207,7 @@ class VideoDetailController extends GetxController
|
||||
late PreferredSizeWidget headerControl;
|
||||
|
||||
// late bool enableCDN;
|
||||
late int? cacheVideoQa;
|
||||
int? cacheVideoQa;
|
||||
late String cacheDecode;
|
||||
late String cacheSecondDecode;
|
||||
late int cacheAudioQa;
|
||||
@@ -303,16 +304,11 @@ class VideoDetailController extends GetxController
|
||||
// CDN优化
|
||||
// enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true);
|
||||
|
||||
// 预设的画质
|
||||
cacheVideoQa = setting.get(SettingBoxKey.defaultVideoQa,
|
||||
defaultValue: VideoQuality.values.last.code);
|
||||
// 预设的解码格式
|
||||
cacheDecode = setting.get(SettingBoxKey.defaultDecode,
|
||||
defaultValue: VideoDecodeFormats.values.last.code);
|
||||
cacheSecondDecode = setting.get(SettingBoxKey.secondDecode,
|
||||
defaultValue: VideoDecodeFormats.values[1].code);
|
||||
cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa,
|
||||
defaultValue: AudioQuality.hiRes.code);
|
||||
oid.value = IdUtils.bv2av(Get.parameters['bvid']!);
|
||||
enableSponsorBlock =
|
||||
setting.get(SettingBoxKey.enableSponsorBlock, defaultValue: false);
|
||||
@@ -1013,6 +1009,21 @@ class VideoDetailController extends GetxController
|
||||
|
||||
// 视频链接
|
||||
Future queryVideoUrl() async {
|
||||
if (cacheVideoQa == null) {
|
||||
await Utils.checkConnectivity().then((res) {
|
||||
cacheVideoQa = res == ConnectivityResult.mobile
|
||||
? setting.get(SettingBoxKey.defaultVideoQaCellular,
|
||||
defaultValue: VideoQuality.high1080.code)
|
||||
: setting.get(SettingBoxKey.defaultVideoQa,
|
||||
defaultValue: VideoQuality.values.last.code);
|
||||
|
||||
cacheAudioQa = res == ConnectivityResult.mobile
|
||||
? setting.get(SettingBoxKey.defaultAudioQaCellular,
|
||||
defaultValue: AudioQuality.k192.code)
|
||||
: setting.get(SettingBoxKey.defaultAudioQa,
|
||||
defaultValue: AudioQuality.hiRes.code);
|
||||
});
|
||||
}
|
||||
var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid);
|
||||
if (result['status']) {
|
||||
data = result['data'];
|
||||
|
||||
@@ -808,21 +808,21 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
videoFormat[i].quality) {
|
||||
return;
|
||||
}
|
||||
Get.back();
|
||||
final int quality = videoFormat[i].quality!;
|
||||
widget.videoDetailCtr!.currentVideoQa =
|
||||
VideoQualityCode.fromCode(quality)!;
|
||||
String oldQualityDesc =
|
||||
VideoQualityCode.fromCode(setting.get(
|
||||
SettingBoxKey.defaultVideoQa,
|
||||
defaultValue:
|
||||
VideoQuality.values.last.code))!
|
||||
.description;
|
||||
setting.put(
|
||||
SettingBoxKey.defaultVideoQa, quality);
|
||||
SmartDialog.showToast(
|
||||
"默认画质由:$oldQualityDesc 变为:${VideoQualityCode.fromCode(quality)!.description}");
|
||||
widget.videoDetailCtr!.updatePlayer();
|
||||
Get.back();
|
||||
// String oldQualityDesc =
|
||||
// VideoQualityCode.fromCode(setting.get(
|
||||
// SettingBoxKey.defaultVideoQa,
|
||||
// defaultValue:
|
||||
// VideoQuality.values.last.code))!
|
||||
// .description;
|
||||
// setting.put(
|
||||
// SettingBoxKey.defaultVideoQa, quality);
|
||||
// SmartDialog.showToast(
|
||||
// "默认画质由:$oldQualityDesc 变为:${VideoQualityCode.fromCode(quality)!.description}");
|
||||
},
|
||||
// 可能包含会员解锁画质
|
||||
enabled: i >= totalQaSam - userfulQaSam,
|
||||
@@ -897,20 +897,20 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
if (currentAudioQa.code == i.id) {
|
||||
return;
|
||||
}
|
||||
Get.back();
|
||||
final int quality = i.id!;
|
||||
widget.videoDetailCtr!.currentAudioQa =
|
||||
AudioQualityCode.fromCode(quality)!;
|
||||
String oldQualityDesc = AudioQualityCode.fromCode(
|
||||
setting.get(SettingBoxKey.defaultAudioQa,
|
||||
defaultValue:
|
||||
AudioQuality.values.last.code))!
|
||||
.description;
|
||||
setting.put(
|
||||
SettingBoxKey.defaultAudioQa, quality);
|
||||
SmartDialog.showToast(
|
||||
"默认音质由:$oldQualityDesc 变为:${AudioQualityCode.fromCode(quality)!.description}");
|
||||
widget.videoDetailCtr!.updatePlayer();
|
||||
Get.back();
|
||||
// String oldQualityDesc = AudioQualityCode.fromCode(
|
||||
// setting.get(SettingBoxKey.defaultAudioQa,
|
||||
// defaultValue:
|
||||
// AudioQuality.values.last.code))!
|
||||
// .description;
|
||||
// setting.put(
|
||||
// SettingBoxKey.defaultAudioQa, quality);
|
||||
// SmartDialog.showToast(
|
||||
// "默认音质由:$oldQualityDesc 变为:${AudioQualityCode.fromCode(quality)!.description}");
|
||||
},
|
||||
contentPadding:
|
||||
const EdgeInsets.only(left: 20, right: 20),
|
||||
@@ -1763,11 +1763,15 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
icon: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Icon(Icons.shield, size: 18),
|
||||
Icon(
|
||||
Icons.shield_outlined,
|
||||
size: 19,
|
||||
color: Colors.white,
|
||||
),
|
||||
Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
size: 17,
|
||||
color: Colors.black87,
|
||||
size: 13,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -257,7 +257,9 @@ class SettingBoxKey {
|
||||
autoUpgradeEnable = 'autoUpgradeEnable',
|
||||
feedBackEnable = 'feedBackEnable',
|
||||
defaultVideoQa = 'defaultVideoQa',
|
||||
defaultVideoQaCellular = 'defaultVideoQaCellular',
|
||||
defaultAudioQa = 'defaultAudioQa',
|
||||
defaultAudioQaCellular = 'defaultAudioQaCellular',
|
||||
autoPlayEnable = 'autoPlayEnable',
|
||||
fullScreenMode = 'fullScreenMode',
|
||||
defaultDecode = 'defaultDecode',
|
||||
|
||||
@@ -17,6 +17,7 @@ import 'package:PiliPalaX/pages/video/detail/introduction/widgets/group_panel.da
|
||||
import 'package:PiliPalaX/utils/feed_back.dart';
|
||||
import 'package:PiliPalaX/utils/login.dart';
|
||||
import 'package:PiliPalaX/utils/storage.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -30,9 +31,17 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:html/parser.dart' as html_parser;
|
||||
|
||||
extension ConnectivityResultExt on ConnectivityResult {
|
||||
String get title => ['蓝牙', 'Wi-Fi', '局域', '流量', '无', '代理', '其他'][index];
|
||||
}
|
||||
|
||||
class Utils {
|
||||
static final Random random = Random();
|
||||
|
||||
static Future<ConnectivityResult> checkConnectivity() async {
|
||||
return (await Connectivity().checkConnectivity()).first;
|
||||
}
|
||||
|
||||
static Future<dynamic> getWwebid(mid) async {
|
||||
try {
|
||||
dynamic response =
|
||||
|
||||
Reference in New Issue
Block a user