mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-12 04:57:41 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e293083492 | ||
|
|
7f39f36c75 | ||
|
|
565819febe | ||
|
|
af150118a1 | ||
|
|
470e519a2b | ||
|
|
d73588f1fd |
@@ -211,7 +211,6 @@ void importFromInput<T>(
|
||||
Future<void> showImportExportDialog<T>(
|
||||
BuildContext context, {
|
||||
required String title,
|
||||
String? label,
|
||||
required ValueGetter<String> onExport,
|
||||
required FutureOr<void> Function(T json) onImport,
|
||||
required ValueGetter<String> localFileName,
|
||||
|
||||
@@ -161,6 +161,7 @@ abstract final class DownloadHttp {
|
||||
dashDrmType: 0,
|
||||
),
|
||||
];
|
||||
entry.hasDashAudio = true;
|
||||
}
|
||||
return Type2(
|
||||
duration: dash.duration!,
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'package:get/route_manager.dart';
|
||||
|
||||
class BiliDownloadEntryInfo with MultiSelectData {
|
||||
int mediaType;
|
||||
final bool hasDashAudio;
|
||||
bool hasDashAudio;
|
||||
bool isCompleted;
|
||||
int totalBytes;
|
||||
int downloadedBytes;
|
||||
|
||||
@@ -267,7 +267,6 @@ Commit Hash: ${BuildConfig.commitHash}''',
|
||||
context,
|
||||
title: '设置',
|
||||
localFileName: () => 'setting_${context.platformName}',
|
||||
label: GStorage.setting.name,
|
||||
onExport: GStorage.exportAllSettings,
|
||||
onImport: GStorage.importAllJsonSettings,
|
||||
),
|
||||
|
||||
@@ -37,10 +37,9 @@ class _MyReplyState extends State<MyReply> with DynMixin {
|
||||
}
|
||||
|
||||
void _initReply() {
|
||||
_replies.assignAll(
|
||||
GStorage.reply!.values.map(ReplyInfo.fromBuffer).toList()
|
||||
..sort((a, b) => b.ctime.compareTo(a.ctime)), // rpid not aligned
|
||||
);
|
||||
_replies
|
||||
..assignAll(GStorage.reply!.values.map(ReplyInfo.fromBuffer))
|
||||
..sort((a, b) => b.ctime.compareTo(a.ctime)); // rpid not aligned;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -336,266 +336,258 @@ class _SavePanelState extends State<SavePanel> {
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
final maxWidth = context.mediaQueryShortestSide;
|
||||
late final coverSize = MediaQuery.textScalerOf(context).scale(65);
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: Get.back,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.only(
|
||||
top: 12 + padding.top,
|
||||
bottom: 80 + padding.bottom,
|
||||
),
|
||||
child: Listener(
|
||||
return Stack(
|
||||
clipBehavior: .none,
|
||||
alignment: .center,
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
hitTestBehavior: .deferToChild,
|
||||
padding: .only(
|
||||
top: 12 + padding.top,
|
||||
bottom: 80 + padding.bottom,
|
||||
),
|
||||
child: Container(
|
||||
width: maxWidth,
|
||||
padding: const .symmetric(horizontal: 12),
|
||||
child: RepaintBoundary(
|
||||
key: boundaryKey,
|
||||
child: Container(
|
||||
width: maxWidth,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: RepaintBoundary(
|
||||
key: boundaryKey,
|
||||
child: Container(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surface,
|
||||
borderRadius: const .all(.circular(12)),
|
||||
),
|
||||
child: AnimatedSize(
|
||||
curve: Curves.easeInOut,
|
||||
alignment: Alignment.topCenter,
|
||||
duration: const Duration(milliseconds: 255),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (_item case final ReplyInfo reply)
|
||||
IgnorePointer(
|
||||
child: ReplyItemGrpc(
|
||||
replyItem: reply,
|
||||
replyLevel: 0,
|
||||
needDivider: false,
|
||||
upMid: widget.upMid,
|
||||
clipBehavior: .hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surface,
|
||||
borderRadius: const .all(.circular(12)),
|
||||
),
|
||||
child: AnimatedSize(
|
||||
curve: Curves.easeInOut,
|
||||
alignment: .topCenter,
|
||||
duration: const Duration(milliseconds: 255),
|
||||
child: Column(
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
switch (_item) {
|
||||
ReplyInfo reply => IgnorePointer(
|
||||
child: ReplyItemGrpc(
|
||||
replyItem: reply,
|
||||
replyLevel: 0,
|
||||
needDivider: false,
|
||||
upMid: widget.upMid,
|
||||
),
|
||||
),
|
||||
DynamicItemModel dyn => IgnorePointer(
|
||||
child: DynamicPanel(
|
||||
item: dyn,
|
||||
isDetail: true,
|
||||
isSave: true,
|
||||
),
|
||||
),
|
||||
_ => throw UnsupportedError(_item.toString()),
|
||||
},
|
||||
if (cover?.isNotEmpty == true &&
|
||||
title?.isNotEmpty == true)
|
||||
Container(
|
||||
height: 81,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
margin: const .symmetric(horizontal: 12),
|
||||
padding: const .all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
borderRadius: const .all(.circular(8)),
|
||||
),
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
src: cover!,
|
||||
height: coverSize,
|
||||
width: coverType == .def16_9
|
||||
? coverSize * StyleString.aspectRatio16x9
|
||||
: coverSize,
|
||||
quality: 100,
|
||||
borderRadius: const .all(.circular(6)),
|
||||
),
|
||||
)
|
||||
else if (_item case final DynamicItemModel dyn)
|
||||
IgnorePointer(
|
||||
child: DynamicPanel(
|
||||
item: dyn,
|
||||
isDetail: true,
|
||||
isSave: true,
|
||||
),
|
||||
),
|
||||
if (cover?.isNotEmpty == true &&
|
||||
title?.isNotEmpty == true)
|
||||
Container(
|
||||
height: 81,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
margin: const .symmetric(horizontal: 12),
|
||||
padding: const .all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
borderRadius: const .all(.circular(8)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
src: cover!,
|
||||
height: coverSize,
|
||||
width: coverType == .def16_9
|
||||
? coverSize *
|
||||
StyleString.aspectRatio16x9
|
||||
: coverSize,
|
||||
quality: 100,
|
||||
borderRadius: const .all(.circular(6)),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
Text(
|
||||
'$title\n',
|
||||
maxLines: 2,
|
||||
overflow: .ellipsis,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'$title\n',
|
||||
maxLines: 2,
|
||||
overflow: .ellipsis,
|
||||
),
|
||||
),
|
||||
if (pubdate != null)
|
||||
Text(
|
||||
DateFormatUtils.format(
|
||||
pubdate,
|
||||
format: dateFormat,
|
||||
),
|
||||
if (pubdate != null) ...[
|
||||
const Spacer(),
|
||||
Text(
|
||||
DateFormatUtils.format(
|
||||
pubdate,
|
||||
format: dateFormat,
|
||||
),
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.outline,
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
showBottom
|
||||
? Stack(
|
||||
clipBehavior: .none,
|
||||
children: [
|
||||
if (uri.isNotEmpty)
|
||||
Align(
|
||||
alignment: .centerRight,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .end,
|
||||
spacing: 4,
|
||||
children: [
|
||||
if (uname?.isNotEmpty == true)
|
||||
Text(
|
||||
'@$uname',
|
||||
maxLines: 1,
|
||||
overflow: .ellipsis,
|
||||
style: TextStyle(
|
||||
color: theme
|
||||
.colorScheme
|
||||
.primary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'识别二维码,$viewType$itemType',
|
||||
textAlign: .end,
|
||||
style: TextStyle(
|
||||
color: theme
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
DateFormatUtils.longFormatDs
|
||||
.format(.now()),
|
||||
textAlign: .end,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color:
|
||||
theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Utils.copyText(uri),
|
||||
child: Container(
|
||||
width: 88,
|
||||
height: 88,
|
||||
margin: const .all(12),
|
||||
padding: const .all(3),
|
||||
color: theme.brightness.isDark
|
||||
? Colors.white
|
||||
: theme.colorScheme.surface,
|
||||
child: PrettyQrView.data(
|
||||
data: uri,
|
||||
decoration:
|
||||
const PrettyQrDecoration(
|
||||
shape:
|
||||
PrettyQrSquaresSymbol(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
showBottom
|
||||
? Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
if (uri.isNotEmpty)
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.end,
|
||||
spacing: 4,
|
||||
children: [
|
||||
if (uname?.isNotEmpty == true)
|
||||
Text(
|
||||
'@$uname',
|
||||
maxLines: 1,
|
||||
overflow: .ellipsis,
|
||||
style: TextStyle(
|
||||
color: theme
|
||||
.colorScheme
|
||||
.primary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'识别二维码,$viewType$itemType',
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: theme
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
DateFormatUtils.longFormatDs
|
||||
.format(.now()),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: theme
|
||||
.colorScheme
|
||||
.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Utils.copyText(uri),
|
||||
child: Container(
|
||||
width: 88,
|
||||
height: 88,
|
||||
margin: const .all(12),
|
||||
padding: const .all(3),
|
||||
color: theme.brightness.isDark
|
||||
? Colors.white
|
||||
: theme.colorScheme.surface,
|
||||
child: PrettyQrView.data(
|
||||
data: uri,
|
||||
decoration:
|
||||
const PrettyQrDecoration(
|
||||
shape:
|
||||
PrettyQrSquaresSymbol(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Image.asset(
|
||||
'assets/images/logo/logo_2.png',
|
||||
width: 100,
|
||||
cacheWidth: 100.cacheSize(context),
|
||||
color:
|
||||
theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: .centerLeft,
|
||||
child: Image.asset(
|
||||
'assets/images/logo/logo_2.png',
|
||||
width: 100,
|
||||
cacheWidth: 100.cacheSize(context),
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black54,
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: .topCenter,
|
||||
end: .bottomCenter,
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black54,
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: padding.left,
|
||||
right: padding.right,
|
||||
bottom: 25 + padding.bottom,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 40,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: padding.left,
|
||||
right: padding.right,
|
||||
bottom: 25 + padding.bottom,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 40,
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: '关闭',
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: Get.back,
|
||||
bgColor: theme.colorScheme.onInverseSurface,
|
||||
iconColor: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: showBottom ? '隐藏' : '显示',
|
||||
context: context,
|
||||
icon: showBottom
|
||||
? const Icon(Icons.visibility_off)
|
||||
: const Icon(Icons.visibility),
|
||||
onPressed: () => setState(() {
|
||||
showBottom = !showBottom;
|
||||
}),
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: '关闭',
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: Get.back,
|
||||
bgColor: theme.colorScheme.onInverseSurface,
|
||||
iconColor: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: showBottom ? '隐藏' : '显示',
|
||||
tooltip: '分享',
|
||||
context: context,
|
||||
icon: showBottom
|
||||
? const Icon(Icons.visibility_off)
|
||||
: const Icon(Icons.visibility),
|
||||
onPressed: () => setState(() {
|
||||
showBottom = !showBottom;
|
||||
}),
|
||||
icon: const Icon(Icons.share),
|
||||
onPressed: () => _onSaveOrSharePic(true),
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: '分享',
|
||||
context: context,
|
||||
icon: const Icon(Icons.share),
|
||||
onPressed: () => _onSaveOrSharePic(true),
|
||||
),
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: '保存',
|
||||
context: context,
|
||||
icon: const Icon(Icons.save_alt),
|
||||
onPressed: _onSaveOrSharePic,
|
||||
),
|
||||
],
|
||||
),
|
||||
iconButton(
|
||||
size: 42,
|
||||
tooltip: '保存',
|
||||
context: context,
|
||||
icon: const Icon(Icons.save_alt),
|
||||
onPressed: _onSaveOrSharePic,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,7 +663,9 @@ class VideoDetailController extends GetxController
|
||||
(isFileSource
|
||||
? true
|
||||
: videoPlayerKey.currentState?.mounted == true)) {
|
||||
return playerInit(autoFullScreenFlag: autoFullScreenFlag);
|
||||
return playerInit(
|
||||
autoFullScreenFlag: autoFullScreenFlag && _autoPlay.value,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -687,6 +689,7 @@ class VideoDetailController extends GetxController
|
||||
dir: args['dirPath'],
|
||||
typeTag: entry.typeTag!,
|
||||
isMp4: entry.mediaType == 1,
|
||||
hasDashAudio: entry.hasDashAudio,
|
||||
)
|
||||
: NetworkSource(
|
||||
videoSource: video ?? videoUrl!,
|
||||
|
||||
@@ -309,13 +309,17 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
return null;
|
||||
}
|
||||
}
|
||||
plPlayerController = videoDetailController.plPlayerController;
|
||||
final plPlayerController = this.plPlayerController =
|
||||
videoDetailController.plPlayerController;
|
||||
videoDetailController.autoPlay = true;
|
||||
plPlayerController!
|
||||
plPlayerController
|
||||
..addStatusLister(playerListener)
|
||||
..addPositionListener(positionListener);
|
||||
if (videoDetailController.plPlayerController.preInitPlayer) {
|
||||
return plPlayerController!.play();
|
||||
if (plPlayerController.preInitPlayer) {
|
||||
if (plPlayerController.autoEnterFullScreen) {
|
||||
plPlayerController.triggerFullScreen();
|
||||
}
|
||||
return plPlayerController.play();
|
||||
} else {
|
||||
return videoDetailController.playerInit(
|
||||
autoplay: true,
|
||||
|
||||
@@ -34,7 +34,6 @@ import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/asset_utils.dart';
|
||||
import 'package:PiliPlus/utils/extension/box_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/string_ext.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/image_utils.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
@@ -369,7 +368,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
late final showFsLockBtn = Pref.showFsLockBtn;
|
||||
late final keyboardControl = Pref.keyboardControl;
|
||||
|
||||
late final bool _autoEnterFullScreen = Pref.autoEnterFullScreen;
|
||||
late final bool autoEnterFullScreen = Pref.autoEnterFullScreen;
|
||||
late final bool autoExitFullscreen = Pref.autoExitFullscreen;
|
||||
late final bool autoPlayEnable = Pref.autoPlayEnable;
|
||||
late final bool enableVerticalExpand = Pref.enableVerticalExpand;
|
||||
@@ -630,7 +629,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
// 数据加载完成
|
||||
dataStatus.value = DataStatus.loaded;
|
||||
|
||||
if (autoFullScreenFlag && _autoEnterFullScreen) {
|
||||
if (autoFullScreenFlag && autoEnterFullScreen) {
|
||||
triggerFullScreen(status: true);
|
||||
}
|
||||
|
||||
@@ -774,10 +773,11 @@ class PlPlayerController with BlockConfigMixin {
|
||||
return;
|
||||
}
|
||||
_videoPlayerController = player;
|
||||
if (isAnim && superResolutionType.value != .disable) {
|
||||
await setShader();
|
||||
}
|
||||
}
|
||||
|
||||
if (isAnim) await setShader();
|
||||
|
||||
final Map<String, String> extras = {};
|
||||
|
||||
String video = dataSource.videoSource;
|
||||
@@ -788,33 +788,32 @@ class PlPlayerController with BlockConfigMixin {
|
||||
extras['audio-files'] =
|
||||
'"${Platform.isWindows ? audio.replaceAll(';', r'\;') : audio.replaceAll(':', r'\:')}"';
|
||||
}
|
||||
}
|
||||
|
||||
if (kDebugMode || Platform.isAndroid) {
|
||||
String audioNormalization = AudioNormalization.getParamFromConfig(
|
||||
Pref.audioNormalization,
|
||||
);
|
||||
if (volume != null && volume.isNotEmpty) {
|
||||
audioNormalization = audioNormalization.replaceFirstMapped(
|
||||
loudnormRegExp,
|
||||
(i) =>
|
||||
'loudnorm=${volume.format(
|
||||
Map.fromEntries(
|
||||
i.group(1)!.split(':').map((item) {
|
||||
final parts = item.split('=');
|
||||
return MapEntry(parts[0].toLowerCase(), num.parse(parts[1]));
|
||||
}),
|
||||
),
|
||||
)}',
|
||||
if (kDebugMode || Platform.isAndroid) {
|
||||
String audioNormalization = AudioNormalization.getParamFromConfig(
|
||||
Pref.audioNormalization,
|
||||
);
|
||||
} else {
|
||||
audioNormalization = audioNormalization.replaceFirst(
|
||||
loudnormRegExp,
|
||||
AudioNormalization.getParamFromConfig(Pref.fallbackNormalization),
|
||||
);
|
||||
}
|
||||
if (audioNormalization.isNotEmpty) {
|
||||
extras['lavfi-complex'] = '"[aid1] $audioNormalization [ao]"';
|
||||
if (volume != null && volume.isNotEmpty) {
|
||||
audioNormalization = audioNormalization.replaceFirstMapped(
|
||||
loudnormRegExp,
|
||||
(i) =>
|
||||
'loudnorm=${volume.format(
|
||||
Map.fromEntries(
|
||||
i.group(1)!.split(':').map((item) {
|
||||
final parts = item.split('=');
|
||||
return MapEntry(parts[0].toLowerCase(), num.parse(parts[1]));
|
||||
}),
|
||||
),
|
||||
)}',
|
||||
);
|
||||
} else {
|
||||
audioNormalization = audioNormalization.replaceFirst(
|
||||
loudnormRegExp,
|
||||
AudioNormalization.getParamFromConfig(Pref.fallbackNormalization),
|
||||
);
|
||||
}
|
||||
if (audioNormalization.isNotEmpty) {
|
||||
extras['lavfi-complex'] = '"[aid1] $audioNormalization [ao]"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,38 +827,17 @@ class PlPlayerController with BlockConfigMixin {
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> refreshPlayer() async {
|
||||
Future<void>? refreshPlayer() {
|
||||
if (dataSource is FileSource) {
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
if (_videoPlayerController == null) {
|
||||
// SmartDialog.showToast('视频播放器为空,请重新进入本页面');
|
||||
return false;
|
||||
if (_videoPlayerController?.current.isNotEmpty ?? false) {
|
||||
return _videoPlayerController!.open(
|
||||
_videoPlayerController!.current.last.copyWith(start: position),
|
||||
play: true,
|
||||
);
|
||||
}
|
||||
if (dataSource.videoSource.isNullOrEmpty) {
|
||||
SmartDialog.showToast('视频源为空,请重新进入本页面');
|
||||
return false;
|
||||
}
|
||||
String? audioUri;
|
||||
if (!isLive) {
|
||||
if (dataSource.audioSource.isNullOrEmpty) {
|
||||
SmartDialog.showToast('音频源为空');
|
||||
} else {
|
||||
audioUri = Platform.isWindows
|
||||
? dataSource.audioSource!.replaceAll(';', '\\;')
|
||||
: dataSource.audioSource!.replaceAll(':', '\\:');
|
||||
}
|
||||
}
|
||||
await _videoPlayerController!.open(
|
||||
Media(
|
||||
dataSource.videoSource,
|
||||
start: position,
|
||||
extras: audioUri == null ? null : {'audio-files': '"$audioUri"'},
|
||||
),
|
||||
play: true,
|
||||
);
|
||||
return true;
|
||||
// seekTo(currentPos);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 开始播放
|
||||
@@ -1000,7 +978,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
'controllerStream.error.listen',
|
||||
const Duration(milliseconds: 10000),
|
||||
() {
|
||||
Future.delayed(const Duration(milliseconds: 3000), () async {
|
||||
Future.delayed(const Duration(milliseconds: 3000), () {
|
||||
// if (kDebugMode) {
|
||||
// debugPrint("isBuffering.value: ${isBuffering.value}");
|
||||
// }
|
||||
@@ -1012,9 +990,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
'视频链接打开失败,重试中',
|
||||
displayTime: const Duration(milliseconds: 500),
|
||||
);
|
||||
if (!await refreshPlayer()) {
|
||||
if (kDebugMode) debugPrint("failed");
|
||||
}
|
||||
refreshPlayer();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -25,6 +25,7 @@ class FileSource extends DataSource {
|
||||
FileSource({
|
||||
required this.dir,
|
||||
required this.isMp4,
|
||||
required bool hasDashAudio,
|
||||
required String typeTag,
|
||||
}) : super(
|
||||
videoSource: path.join(
|
||||
@@ -32,7 +33,7 @@ class FileSource extends DataSource {
|
||||
typeTag,
|
||||
isMp4 ? PathUtils.videoNameType1 : PathUtils.videoNameType2,
|
||||
),
|
||||
audioSource: isMp4
|
||||
audioSource: isMp4 || !hasDashAudio
|
||||
? null
|
||||
: path.join(dir, typeTag, PathUtils.audioNameType2),
|
||||
);
|
||||
|
||||
@@ -138,7 +138,7 @@ class DownloadService extends GetxService {
|
||||
final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
final entry = BiliDownloadEntryInfo(
|
||||
mediaType: 2,
|
||||
hasDashAudio: true,
|
||||
hasDashAudio: false,
|
||||
isCompleted: false,
|
||||
totalBytes: 0,
|
||||
downloadedBytes: 0,
|
||||
@@ -206,7 +206,7 @@ class DownloadService extends GetxService {
|
||||
);
|
||||
final entry = BiliDownloadEntryInfo(
|
||||
mediaType: 2,
|
||||
hasDashAudio: true,
|
||||
hasDashAudio: false,
|
||||
isCompleted: false,
|
||||
totalBytes: 0,
|
||||
downloadedBytes: 0,
|
||||
|
||||
Reference in New Issue
Block a user