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