mod: CDN优化 issues #70

This commit is contained in:
guozhigq
2023-10-21 01:11:38 +08:00
parent 41e9cfcbbb
commit 9744ec88a0
29 changed files with 89 additions and 38 deletions

View File

@ -67,6 +67,12 @@ class _PlaySettingState extends State<PlaySetting> {
setKey: SettingBoxKey.p1080,
defaultVal: true,
),
const SetSwitchItem(
title: 'CDN优化',
subTitle: '使用优质CDN线路',
setKey: SettingBoxKey.enableCDN,
defaultVal: true,
),
const SetSwitchItem(
title: '自动播放',
subTitle: '进入详情页自动播放',

View File

@ -16,6 +16,7 @@ import 'package:pilipala/pages/video/detail/replyReply/index.dart';
import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart';
import 'package:pilipala/utils/video_utils.dart';
import 'package:screen_brightness/screen_brightness.dart';
import 'widgets/header_control.dart';
@ -83,6 +84,11 @@ class VideoDetailController extends GetxController
Floating? floating;
late PreferredSizeWidget headerControl;
late bool enableCDN;
late int? cacheVideoQa;
late String cacheDecode;
late int cacheAudioQa;
@override
void onInit() {
super.onInit();
@ -120,6 +126,15 @@ class VideoDetailController extends GetxController
videoDetailCtr: this,
floating: floating,
);
// CDN优化
enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true);
// 预设的画质
cacheVideoQa = setting.get(SettingBoxKey.defaultVideoQa);
// 预设的解码格式
cacheDecode = setting.get(SettingBoxKey.defaultDecode,
defaultValue: VideoDecodeFormats.values.last.code);
cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa,
defaultValue: AudioQuality.hiRes.code);
}
showReplyReplyPanel() {
@ -231,22 +246,19 @@ class VideoDetailController extends GetxController
var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid);
if (result['status']) {
data = result['data'];
List<VideoItem> allVideosList = data.dash!.video!;
try {
// 当前可播放的最高质量视频
int currentHighVideoQa = allVideosList.first.quality!.code;
// 使用预设的画质 当前可用的最高质量
int cacheVideoQa = setting.get(SettingBoxKey.defaultVideoQa,
defaultValue: currentHighVideoQa);
// 预设的画质为null当前可用的最高质量
cacheVideoQa ??= currentHighVideoQa;
int resVideoQa = currentHighVideoQa;
if (cacheVideoQa <= currentHighVideoQa) {
if (cacheVideoQa! <= currentHighVideoQa) {
// 如果预设的画质低于当前最高
List<int> numbers = data.acceptQuality!
.where((e) => e <= currentHighVideoQa)
.toList();
resVideoQa = Utils.findClosestNumber(cacheVideoQa, numbers);
resVideoQa = Utils.findClosestNumber(cacheVideoQa!, numbers);
}
currentVideoQa = VideoQualityCode.fromCode(resVideoQa)!;
@ -260,9 +272,7 @@ class VideoDetailController extends GetxController
List supportDecodeFormats =
supportFormats.firstWhere((e) => e.quality == resVideoQa).codecs!;
// 默认从设置中取AVC
currentDecodeFormats = VideoDecodeFormatsCode.fromString(setting.get(
SettingBoxKey.defaultDecode,
defaultValue: VideoDecodeFormats.values.last.code))!;
currentDecodeFormats = VideoDecodeFormatsCode.fromString(cacheDecode)!;
try {
// 当前视频没有对应格式返回第一个
bool flag = false;
@ -285,7 +295,9 @@ class VideoDetailController extends GetxController
} catch (_) {
firstVideo = videosList.first;
}
videoUrl = firstVideo.baseUrl!;
videoUrl = enableCDN
? VideoUtils.getCdnUrl(firstVideo)
: (firstVideo.backupUrl ?? firstVideo.baseUrl!);
} catch (err) {
SmartDialog.showToast('firstVideo error: $err');
}
@ -295,8 +307,6 @@ class VideoDetailController extends GetxController
List<AudioItem> audiosList = data.dash!.audio!;
try {
int resultAudioQa = setting.get(SettingBoxKey.defaultAudioQa,
defaultValue: AudioQuality.hiRes.code);
if (data.dash!.dolby?.audio?.isNotEmpty == true) {
// 杜比
audiosList.insert(0, data.dash!.dolby!.audio!.first);
@ -309,9 +319,9 @@ class VideoDetailController extends GetxController
if (audiosList.isNotEmpty) {
List<int> numbers = audiosList.map((map) => map.id!).toList();
int closestNumber = Utils.findClosestNumber(resultAudioQa, numbers);
if (!numbers.contains(resultAudioQa) &&
numbers.any((e) => e > resultAudioQa)) {
int closestNumber = Utils.findClosestNumber(cacheAudioQa, numbers);
if (!numbers.contains(cacheAudioQa) &&
numbers.any((e) => e > cacheAudioQa)) {
closestNumber = 30280;
}
firstAudio = audiosList.firstWhere((e) => e.id == closestNumber);
@ -323,7 +333,9 @@ class VideoDetailController extends GetxController
SmartDialog.showToast('firstAudio error: $err');
}
audioUrl = firstAudio.baseUrl ?? '';
audioUrl = enableCDN
? VideoUtils.getCdnUrl(firstAudio)
: (firstAudio.backupUrl ?? firstAudio.baseUrl!);
//
if (firstAudio.id != null) {
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;

View File

@ -3,18 +3,15 @@ import 'dart:io';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:floating/floating.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/common/widgets/sliver_header.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/common/search_type.dart';
import 'package:pilipala/pages/bangumi/introduction/index.dart';
import 'package:pilipala/pages/danmaku/view.dart';
import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart';
import 'package:pilipala/pages/video/detail/reply/index.dart';
import 'package:pilipala/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/introduction/index.dart';
@ -23,7 +20,6 @@ import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
import 'package:pilipala/utils/storage.dart';
import 'widgets/app_bar.dart';
import 'widgets/header_control.dart';
class VideoDetailPage extends StatefulWidget {

View File

@ -332,12 +332,11 @@ class PlPlayerController {
// 数据加载完成
dataStatus.status.value = DataStatus.loaded;
await _initializePlayer(seekTo: seekTo);
// listen the video player events
if (!_listenersInitialized) {
startListeners();
}
await _initializePlayer(seekTo: seekTo);
bool autoEnterFullcreen =
setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false);
if (autoEnterFullcreen && _isFirstTime) {
@ -407,6 +406,7 @@ class PlPlayerController {
player,
configuration: VideoControllerConfiguration(
enableHardwareAcceleration: enableHA,
androidAttachSurfaceAfterVideoParameters: false,
),
);
@ -542,6 +542,7 @@ class PlPlayerController {
}
_position.value = position;
_heartDuration = position.inSeconds;
print('seek duration: $duration');
if (duration.value.inSeconds != 0) {
if (type != 'slider') {
/// 拖动进度条调节时,不等待第一帧,防止抖动
@ -552,17 +553,19 @@ class PlPlayerController {
// play();
// }
} else {
print('seek duration else');
_timerForSeek?.cancel();
_timerForSeek =
Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
//_timerForSeek = null;
if (duration.value.inSeconds != 0) {
await _videoPlayerController!.stream.buffer.first;
await _videoPlayerController?.seek(position);
// if (playerStatus.stopped) {
// play();
// }
if (playerStatus.status.value == PlayerStatus.paused) {
play();
}
t.cancel();
//_timerForSeek = null;
_timerForSeek = null;
}
});
}
@ -595,6 +598,8 @@ class PlPlayerController {
/// 播放视频
Future<void> play({bool repeat = false, bool hideControls = true}) async {
// 播放时自动隐藏控制条
controls = !hideControls;
// repeat为true将从头播放
if (repeat) {
await seekTo(Duration.zero);
@ -606,11 +611,6 @@ class PlPlayerController {
playerStatus.status.value = PlayerStatus.playing;
// screenManager.setOverlays(false);
// 播放时自动隐藏控制条
if (hideControls) {
_hideTaskControls();
}
}
/// 暂停播放

View File

@ -105,6 +105,7 @@ class SettingBoxKey {
static const String enableAutoEnter = 'enableAutoEnter';
static const String enableAutoExit = 'enableAutoExit';
static const String p1080 = 'p1080';
static const String enableCDN = 'enableCDN';
// youtube 双击快进快退
static const String enableQuickDouble = 'enableQuickDouble';

View File

@ -0,0 +1,36 @@
import 'package:pilipala/models/video/play/url.dart';
class VideoUtils {
static String getCdnUrl(dynamic item) {
var backupUrl = "";
var videoUrl = "";
/// 先获取backupUrl 一般是upgcxcode地址 播放更稳定
if (item is VideoItem) {
backupUrl = item.backupUrl ?? "";
videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? "");
} else if (item is AudioItem) {
backupUrl = item.backupUrl ?? "";
videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? "");
} else {
return "";
}
/// issues #70
if (videoUrl.contains(".mcdn.bilivideo") ||
videoUrl.contains("/upgcxcode/")) {
//CDN列表
var cdnList = {
'ali': 'upos-sz-mirrorali.bilivideo.com',
'cos': 'upos-sz-mirrorcos.bilivideo.com',
'hw': 'upos-sz-mirrorhw.bilivideo.com',
};
//取一个CDN
var cdn = cdnList['ali'] ?? "";
var reg = RegExp(r'(http|https)://(.*?)/upgcxcode/');
videoUrl = videoUrl.replaceAll(reg, "https://$cdn/upgcxcode/");
}
return videoUrl;
}
}

View File

@ -761,10 +761,10 @@ packages:
dependency: "direct main"
description:
name: media_kit
sha256: d652c2bdb0cd876bf1046e24d0b614651fefe59f7c3a2d9b7ed57217b9e7db94
sha256: "3dffc6d0c19117d51fbc42a7f89612e0595665800a596289ab7a80bdd93e0ad1"
url: "https://pub.dev"
source: hosted
version: "1.1.8+1"
version: "1.1.9"
media_kit_libs_android_video:
dependency: transitive
description:
@ -825,10 +825,10 @@ packages:
dependency: "direct main"
description:
name: media_kit_video
sha256: b1a427f0540c5f052dfab73e4b76a5eb8efa7ebb5d83179cb23fc3932afc315a
sha256: b8df9cf97aba1861af83b00ac16f5cac536debe0781a934a554b77c157a8f7e8
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
meta:
dependency: transitive
description:

View File

@ -84,8 +84,8 @@ dependencies:
crypto: ^3.0.3
# 视频播放器
media_kit: ^1.1.8 # Primary package.
media_kit_video: ^1.2.1 # For video rendering.
media_kit: ^1.1.9 # Primary package.
media_kit_video: ^1.2.2 # For video rendering.
media_kit_libs_video: ^1.0.3
# 音量、亮度、屏幕控制