* refa: cdn

* feat: live cdn (WIP)

* tweaks

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* add live quality [skip ci]

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* mod: replace durl host

* tweak [skip ci]

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

---------

Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
My-Responsitories
2025-11-15 20:12:21 +08:00
committed by GitHub
parent e589f27195
commit 27ae296b28
13 changed files with 297 additions and 156 deletions

View File

@@ -54,9 +54,9 @@ List<SettingsModel> get videoSettings => [
title: 'CDN 设置',
leading: const Icon(MdiIcons.cloudPlusOutline),
getSubtitle: () =>
'当前使用:${CDNService.fromCode(VideoUtils.cdnService).desc},部分 CDN 可能失效,如无法播放请尝试切换',
'当前使用:${VideoUtils.cdnService.desc},部分 CDN 可能失效,如无法播放请尝试切换',
onTap: (setState) async {
String? result = await showDialog(
CDNService? result = await showDialog(
context: Get.context!,
builder: (context) {
return const CdnSelectDialog();
@@ -64,7 +64,57 @@ List<SettingsModel> get videoSettings => [
);
if (result != null) {
VideoUtils.cdnService = result;
await GStorage.setting.put(SettingBoxKey.CDNService, result);
await GStorage.setting.put(SettingBoxKey.CDNService, result.name);
setState();
}
},
),
SettingsModel(
settingsType: SettingsType.normal,
title: '直播 CDN 设置',
leading: const Icon(MdiIcons.cloudPlusOutline),
getSubtitle: () => '当前使用:${Pref.liveCdnUrl ?? "默认"}',
onTap: (setState) async {
String? result = await showDialog<String>(
context: Get.context!,
builder: (context) {
String host = Pref.liveCdnUrl ?? '';
return AlertDialog(
title: const Text('输入CDN host'),
content: TextFormField(
initialValue: host,
autofocus: true,
onChanged: (value) => host = value,
),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'取消',
style: TextStyle(
color: ColorScheme.of(context).outline,
),
),
),
TextButton(
onPressed: () => Get.back(result: host),
child: const Text('确定'),
),
],
);
},
);
if (result != null) {
if (result.isEmpty) {
result = null;
await GStorage.setting.delete(SettingBoxKey.liveCdnUrl);
} else {
if (!result.startsWith('http')) {
result = 'https://${result}';
}
await GStorage.setting.put(SettingBoxKey.liveCdnUrl, result);
}
VideoUtils.liveCdnUrl = result;
setState();
}
},

View File

@@ -68,7 +68,7 @@ class SelectDialog<T> extends StatelessWidget {
}
class CdnSelectDialog extends StatefulWidget {
final VideoItem? sample;
final BaseItem? sample;
const CdnSelectDialog({
super.key,
@@ -113,7 +113,7 @@ class _CdnSelectDialogState extends State<CdnSelectDialog> {
super.dispose();
}
Future<VideoItem> _getSampleUrl() async {
Future<BaseItem> _getSampleUrl() async {
final result = await VideoHttp.videoUrl(
cid: 196018899,
bvid: 'BV1fK4y1t7hj',
@@ -134,16 +134,19 @@ class _CdnSelectDialogState extends State<CdnSelectDialog> {
}
}
Future<void> _testAllCdnServices(VideoItem videoItem) async {
Future<void> _testAllCdnServices(BaseItem videoItem) async {
for (final item in CDNService.values) {
if (!mounted) break;
await _testSingleCdn(item, videoItem);
}
}
Future<void> _testSingleCdn(CDNService item, VideoItem videoItem) async {
Future<void> _testSingleCdn(CDNService item, BaseItem videoItem) async {
try {
final cdnUrl = VideoUtils.getCdnUrl(videoItem, item.code);
final cdnUrl = VideoUtils.getCdnUrl(
videoItem.playUrls,
defaultCDNService: item,
);
await _measureDownloadSpeed(cdnUrl, item.index);
} catch (e) {
_handleSpeedTestError(e, item.index);
@@ -211,7 +214,17 @@ class _CdnSelectDialogState extends State<CdnSelectDialog> {
if (kDebugMode) debugPrint('CDN speed test error: $error');
if (!mounted) return;
var message = error.toString();
String message;
if (error is DioException) {
final statusCode = error.response?.statusCode;
if (statusCode != null && 400 <= statusCode && statusCode < 500) {
message = '此视频可能无法替换为该CDN';
} else {
message = error.toString();
}
} else {
message = error.toString();
}
if (message.isEmpty) {
message = '测速失败';
}
@@ -220,9 +233,9 @@ class _CdnSelectDialogState extends State<CdnSelectDialog> {
@override
Widget build(BuildContext context) {
return SelectDialog<String>(
return SelectDialog<CDNService>(
title: 'CDN 设置',
values: CDNService.values.map((i) => (i.code, i.desc)).toList(),
values: CDNService.values.map((i) => (i, i.desc)).toList(),
value: VideoUtils.cdnService,
subtitleBuilder: _cdnSpeedTest
? (context, index) {