feat: 调整设置,支持导入导出,代码优化

This commit is contained in:
orz12
2024-04-27 02:05:50 +08:00
parent a4d3713b05
commit ea8f44f4da
41 changed files with 882 additions and 424 deletions

View File

@@ -56,6 +56,7 @@ class VideoDetailController extends GetxController
RxBool isShowCover = true.obs;
// 硬解
RxBool enableHA = true.obs;
RxString hwdec = 'auto-safe'.obs;
/// 本地存储
Box userInfoCache = GStrorage.userInfo;
@@ -117,7 +118,8 @@ class VideoDetailController extends GetxController
autoPlay.value =
setting.get(SettingBoxKey.autoPlayEnable, defaultValue: true);
enableHA.value = setting.get(SettingBoxKey.enableHA, defaultValue: true);
hwdec.value = setting.get(SettingBoxKey.hardwareDecoding,
defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto');
if (userInfo == null ||
localCache.get(LocalCacheKey.historyPause) == true) {
enableHeart = false;
@@ -270,6 +272,7 @@ class VideoDetailController extends GetxController
),
// 硬解
enableHA: enableHA.value,
hwdec: hwdec.value,
seekTo: seekToTime ?? defaultST,
duration: duration ?? data.timeLength == null
? null
@@ -300,109 +303,112 @@ class VideoDetailController extends GetxController
'该视频为专属视频,仅提供试看',
displayTime: const Duration(seconds: 3),
);
}
if (data.dash == null && data.durl != null) {
videoUrl = data.durl!.first.url!;
audioUrl = '';
defaultST = Duration.zero;
firstVideo = VideoItem();
// 实际为FLV/MP4格式但已被淘汰这里仅做兜底处理
firstVideo = VideoItem(
id: data.quality!,
baseUrl: videoUrl,
codecs: 'avc1',
quality: VideoQualityCode.fromCode(data.quality!)!
);
currentDecodeFormats = VideoDecodeFormatsCode.fromString('avc1')!;
currentVideoQa = VideoQualityCode.fromCode(data.quality!)!;
if (autoPlay.value) {
await playerInit();
isShowCover.value = false;
}
return result;
}
final List<VideoItem> allVideosList = data.dash!.video!;
try {
// 当前可播放的最高质量视频
int currentHighVideoQa = allVideosList.first.quality!.code;
// 预设的画质为null则当前可用的最高质量
cacheVideoQa ??= currentHighVideoQa;
int resVideoQa = currentHighVideoQa;
if (cacheVideoQa! <= currentHighVideoQa) {
// 如果预设的画质低于当前最高
final List<int> numbers = data.acceptQuality!
.where((e) => e <= currentHighVideoQa)
.toList();
resVideoQa = Utils.findClosestNumber(cacheVideoQa!, numbers);
}
currentVideoQa = VideoQualityCode.fromCode(resVideoQa)!;
/// 取出符合当前画质的videoList
final List<VideoItem> videosList =
allVideosList.where((e) => e.quality!.code == resVideoQa).toList();
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
final List<FormatItem> supportFormats = data.supportFormats!;
// 根据画质选编码格式
final List supportDecodeFormats =
supportFormats.firstWhere((e) => e.quality == resVideoQa).codecs!;
// 默认从设置中取AV1
currentDecodeFormats = VideoDecodeFormatsCode.fromString(cacheDecode)!;
VideoDecodeFormats secondDecodeFormats =
VideoDecodeFormatsCode.fromString(cacheSecondDecode)!;
try {
// 当前视频没有对应格式返回第一个
int flag = 0;
for (var i in supportDecodeFormats) {
if (i.startsWith(currentDecodeFormats.code)) {
flag = 1;
break;
} else if (i.startsWith(secondDecodeFormats.code)) {
flag = 2;
}
}
if (flag == 2) {
currentDecodeFormats = secondDecodeFormats;
} else if (flag == 0) {
currentDecodeFormats =
VideoDecodeFormatsCode.fromString(supportDecodeFormats.first)!;
}
} catch (err) {
SmartDialog.showToast('DecodeFormats error: $err');
}
/// 取出符合当前解码格式的videoItem
try {
firstVideo = videosList.firstWhere(
(e) => e.codecs!.startsWith(currentDecodeFormats.code));
} catch (_) {
firstVideo = videosList.first;
}
videoUrl = enableCDN
? VideoUtils.getCdnUrl(firstVideo)
: (firstVideo.backupUrl ?? firstVideo.baseUrl!);
} catch (err) {
SmartDialog.showToast('firstVideo error: $err');
if (data.dash == null) {
SmartDialog.showToast('视频资源不存在');
isShowCover.value = false;
return result;
}
final List<VideoItem> allVideosList = data.dash!.video!;
print("allVideosList:${allVideosList}");
// 当前可播放的最高质量视频
int currentHighVideoQa = allVideosList.first.quality!.code;
// 预设的画质为null则当前可用的最高质量
cacheVideoQa ??= currentHighVideoQa;
int resVideoQa = currentHighVideoQa;
if (cacheVideoQa! <= currentHighVideoQa) {
// 如果预设的画质低于当前最高
final List<int> numbers =
data.acceptQuality!.where((e) => e <= currentHighVideoQa).toList();
resVideoQa = Utils.findClosestNumber(cacheVideoQa!, numbers);
}
currentVideoQa = VideoQualityCode.fromCode(resVideoQa)!;
/// 取出符合当前画质的videoList
final List<VideoItem> videosList =
allVideosList.where((e) => e.quality!.code == resVideoQa).toList();
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
final List<FormatItem> supportFormats = data.supportFormats!;
// 根据画质选编码格式
final List supportDecodeFormats = supportFormats
.firstWhere((e) => e.quality == resVideoQa,
orElse: () => supportFormats.first)
.codecs!;
// 默认从设置中取AV1
currentDecodeFormats = VideoDecodeFormatsCode.fromString(cacheDecode)!;
VideoDecodeFormats secondDecodeFormats =
VideoDecodeFormatsCode.fromString(cacheSecondDecode)!;
// 当前视频没有对应格式返回第一个
int flag = 0;
for (var i in supportDecodeFormats) {
if (i.startsWith(currentDecodeFormats.code)) {
flag = 1;
break;
} else if (i.startsWith(secondDecodeFormats.code)) {
flag = 2;
}
}
if (flag == 2) {
currentDecodeFormats = secondDecodeFormats;
} else if (flag == 0) {
currentDecodeFormats =
VideoDecodeFormatsCode.fromString(supportDecodeFormats.first)!;
}
/// 取出符合当前解码格式的videoItem
firstVideo = videosList.firstWhere(
(e) => e.codecs!.startsWith(currentDecodeFormats.code),
orElse: () => videosList.first);
videoUrl = enableCDN
? VideoUtils.getCdnUrl(firstVideo)
: (firstVideo.backupUrl ?? firstVideo.baseUrl!);
/// 优先顺序 设置中指定质量 -> 当前可选的最高质量
late AudioItem? firstAudio;
final List<AudioItem> audiosList = data.dash!.audio!;
try {
if (data.dash!.dolby?.audio?.isNotEmpty == true) {
// 杜比
audiosList.insert(0, data.dash!.dolby!.audio!.first);
}
if (data.dash!.dolby?.audio != null && data.dash!.dolby!.audio!.isNotEmpty) {
// 杜比
audiosList.insert(0, data.dash!.dolby!.audio!.first);
}
if (data.dash!.flac?.audio != null) {
// 无损
audiosList.insert(0, data.dash!.flac!.audio!);
}
if (data.dash!.flac?.audio != null) {
// 无损
audiosList.insert(0, data.dash!.flac!.audio!);
}
if (audiosList.isNotEmpty) {
final List<int> numbers = audiosList.map((map) => map.id!).toList();
int closestNumber = Utils.findClosestNumber(cacheAudioQa, numbers);
if (!numbers.contains(cacheAudioQa) &&
numbers.any((e) => e > cacheAudioQa)) {
closestNumber = 30280;
}
firstAudio = audiosList.firstWhere((e) => e.id == closestNumber);
} else {
firstAudio = AudioItem();
if (audiosList.isNotEmpty) {
final List<int> numbers = audiosList.map((map) => map.id!).toList();
int closestNumber = Utils.findClosestNumber(cacheAudioQa, numbers);
if (!numbers.contains(cacheAudioQa) &&
numbers.any((e) => e > cacheAudioQa)) {
closestNumber = 30280;
}
} catch (err) {
firstAudio = audiosList.isNotEmpty ? audiosList.first : AudioItem();
SmartDialog.showToast('firstAudio error: $err');
firstAudio = audiosList.firstWhere((e) => e.id == closestNumber,
orElse: () => audiosList.first);
} else {
firstAudio = AudioItem();
}
audioUrl = enableCDN

View File

@@ -18,7 +18,6 @@ import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import '../../../../utils/id_utils.dart';
import 'widgets/action_item.dart';
import 'widgets/action_row_item.dart';
import 'widgets/fav_panel.dart';

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
class ActionItem extends StatelessWidget {

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/models/video_detail_res.dart';
import 'package:PiliPalaX/pages/video/detail/index.dart';
import 'package:PiliPalaX/utils/id_utils.dart';
class SeasonPanel extends StatefulWidget {
const SeasonPanel({

View File

@@ -109,7 +109,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
@override
void didChangeMetrics() {
super.didChangeMetrics();
final String routePath = Get.currentRoute;
if (!mounted) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;

View File

@@ -66,8 +66,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
RxBool isFullScreen = false.obs;
late StreamSubscription<bool> fullScreenStatusListener;
late final MethodChannel onUserLeaveHintListener;
late AnimationController _animationController;
late Animation<double> _animation;
StreamSubscription<Duration>? _bufferedListener;
@override
@@ -292,29 +290,33 @@ class _VideoDetailPageState extends State<VideoDetailPage>
if (mounted) {
setState(() => {});
}
super.didPopNext();
videoDetailController.isFirstTime = false;
final bool autoplay = autoPlayEnable;
videoDetailController.playerInit(autoplay: autoplay);
await videoDetailController.playerInit(autoplay: autoplay);
/// 未开启自动播放时,未播放跳转下一页返回/播放后跳转下一页返回
videoDetailController.autoPlay.value =
!videoDetailController.isShowCover.value;
videoIntroController.isPaused = false;
if (autoplay) {
// await Future.delayed(const Duration(milliseconds: 300));
if (plPlayerController?.buffered.value == Duration.zero) {
_bufferedListener = plPlayerController?.buffered.listen((p0) {
if (p0 > Duration.zero) {
_bufferedListener!.cancel();
plPlayerController?.seekTo(videoDetailController.defaultST);
plPlayerController?.play();
}
});
} else {
plPlayerController?.seekTo(videoDetailController.defaultST);
plPlayerController?.play();
}
}
// if (autoplay) {
// // await Future.delayed(const Duration(milliseconds: 300));
// print(plPlayerController);
// if (plPlayerController?.buffered.value == Duration.zero) {
// _bufferedListener = plPlayerController?.buffered.listen((p0) {
// print("p0");
// print(p0);
// if (p0 > Duration.zero) {
// _bufferedListener!.cancel();
// plPlayerController?.seekTo(videoDetailController.defaultST);
// plPlayerController?.play();
// }
// });
// } else {
// plPlayerController?.seekTo(videoDetailController.defaultST);
// plPlayerController?.play();
// }
// }
Future.delayed(const Duration(milliseconds: 600), () {
AutoOrientation.fullAutoMode();
});
@@ -322,7 +324,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
if (plPlayerController != null) {
listenFullScreenStatus();
}
super.didPopNext();
}
@override
@@ -409,6 +410,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
// systemOverlayStyle: const SystemUiOverlayStyle(
// statusBarColor: Colors.transparent,
// statusBarIconBrightness: Brightness.light),
),
),
body: Column(
@@ -417,10 +421,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
() {
double videoheight = context.width * 9 / 16;
final double videowidth = context.width;
print(videoDetailController.tabCtr.index);
// print(videoDetailController.tabCtr.index);
if (enableVerticalExpand &&
plPlayerController?.direction.value == 'vertical' &&
videoDetailController.tabCtr.index != 1) {
plPlayerController?.direction.value == 'vertical') {
videoheight = context.width * 5 / 4;
}
if (MediaQuery.of(context).orientation ==
@@ -812,6 +815,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
// systemOverlayStyle: const SystemUiOverlayStyle(
// statusBarColor: Colors.transparent,
// statusBarIconBrightness: Brightness.dark),
),
),
body: childWhenDisabledLandscapeInner)

View File

@@ -20,10 +20,8 @@ import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/http/danmaku.dart';
import 'package:PiliPalaX/services/shutdown_timer_service.dart';
import '../../../../models/video_detail_res.dart';
import '../../../../services/service_locator.dart';
import '../introduction/index.dart';
import 'package:marquee/marquee.dart';
import '../../../danmaku/controller.dart';
class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
const HeaderControl({
@@ -440,6 +438,10 @@ class _HeaderControlState extends State<HeaderControl> {
/// 选择画质
void showSetVideoQa() {
if (videoInfo.dash == null) {
SmartDialog.showToast('当前视频不支持选择画质');
return;
}
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
final VideoQuality currentVideoQa = widget.videoDetailCtr!.currentVideoQa;
@@ -634,9 +636,13 @@ class _HeaderControlState extends State<HeaderControl> {
final VideoItem firstVideo = widget.videoDetailCtr!.firstVideo;
// 当前视频可用的解码格式
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
final List list = videoFormat
final List? list = videoFormat
.firstWhere((FormatItem e) => e.quality == firstVideo.quality!.code)
.codecs!;
.codecs;
if (list == null) {
SmartDialog.showToast('当前视频不支持选择解码格式');
return;
}
showModalBottomSheet(
context: context,