mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 03:06:59 +08:00
feat: video download
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -36,6 +36,7 @@ import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/image_utils.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart' show PageUtils;
|
||||
import 'package:PiliPlus/utils/path_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
@@ -55,7 +56,6 @@ import 'package:hive/hive.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class PlPlayerController {
|
||||
@@ -629,6 +629,12 @@ class PlPlayerController {
|
||||
bool _processing = false;
|
||||
bool get processing => _processing;
|
||||
|
||||
// offline
|
||||
bool isFileSource = false;
|
||||
String? dirPath;
|
||||
String? typeTag;
|
||||
int? mediaType;
|
||||
|
||||
// 初始化资源
|
||||
Future<void> setDataSource(
|
||||
DataSource dataSource, {
|
||||
@@ -655,8 +661,15 @@ class PlPlayerController {
|
||||
VideoType? videoType,
|
||||
VoidCallback? callback,
|
||||
Volume? volume,
|
||||
String? dirPath,
|
||||
String? typeTag,
|
||||
int? mediaType,
|
||||
}) async {
|
||||
try {
|
||||
this.dirPath = dirPath;
|
||||
this.typeTag = typeTag;
|
||||
this.mediaType = mediaType;
|
||||
isFileSource = dataSource.type == DataSourceType.file;
|
||||
_processing = true;
|
||||
this.isLive = isLive;
|
||||
_videoType = videoType ?? VideoType.ugc;
|
||||
@@ -723,30 +736,25 @@ class PlPlayerController {
|
||||
}
|
||||
}
|
||||
|
||||
Directory? shadersDirectory;
|
||||
Future<Directory?> copyShadersToExternalDirectory() async {
|
||||
if (shadersDirectory != null) {
|
||||
return shadersDirectory;
|
||||
}
|
||||
final manifestContent = await rootBundle.loadString('AssetManifest.json');
|
||||
final Map<String, dynamic> manifestMap = json.decode(manifestContent);
|
||||
final directory = await getApplicationSupportDirectory();
|
||||
shadersDirectory = Directory(path.join(directory.path, 'anime_shaders'));
|
||||
|
||||
if (!shadersDirectory!.existsSync()) {
|
||||
await shadersDirectory!.create(recursive: true);
|
||||
String? shadersDirPath;
|
||||
Future<String> get copyShadersToExternalDirectory async {
|
||||
if (shadersDirPath != null) {
|
||||
return shadersDirPath!;
|
||||
}
|
||||
|
||||
final shaderFiles = manifestMap.keys.where(
|
||||
(String key) =>
|
||||
key.startsWith('assets/shaders/') && key.endsWith('.glsl'),
|
||||
);
|
||||
final dir = Directory(path.join(appSupportDirPath, 'anime_shaders'));
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create(recursive: true);
|
||||
}
|
||||
|
||||
// int copiedFilesCount = 0;
|
||||
final shaderFilesPath =
|
||||
(Constants.mpvAnime4KShaders + Constants.mpvAnime4KShadersLite)
|
||||
.map((e) => 'assets/shaders/$e')
|
||||
.toList();
|
||||
|
||||
for (var filePath in shaderFiles) {
|
||||
for (final filePath in shaderFilesPath) {
|
||||
final fileName = filePath.split('/').last;
|
||||
final targetFile = File(path.join(shadersDirectory!.path, fileName));
|
||||
final targetFile = File(path.join(dir.path, fileName));
|
||||
if (targetFile.existsSync()) {
|
||||
continue;
|
||||
}
|
||||
@@ -755,12 +763,11 @@ class PlPlayerController {
|
||||
final data = await rootBundle.load(filePath);
|
||||
final List<int> bytes = data.buffer.asUint8List();
|
||||
await targetFile.writeAsBytes(bytes);
|
||||
// copiedFilesCount++;
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('$e');
|
||||
}
|
||||
}
|
||||
return shadersDirectory;
|
||||
return shadersDirPath = dir.path;
|
||||
}
|
||||
|
||||
late final isAnim = _pgcType == 1 || _pgcType == 4;
|
||||
@@ -786,8 +793,8 @@ class PlPlayerController {
|
||||
'change-list',
|
||||
'glsl-shaders',
|
||||
'set',
|
||||
Utils.buildShadersAbsolutePath(
|
||||
(await copyShadersToExternalDirectory())?.path ?? '',
|
||||
PathUtils.buildShadersAbsolutePath(
|
||||
await copyShadersToExternalDirectory,
|
||||
Constants.mpvAnime4KShadersLite,
|
||||
),
|
||||
]);
|
||||
@@ -796,8 +803,8 @@ class PlPlayerController {
|
||||
'change-list',
|
||||
'glsl-shaders',
|
||||
'set',
|
||||
Utils.buildShadersAbsolutePath(
|
||||
(await copyShadersToExternalDirectory())?.path ?? '',
|
||||
PathUtils.buildShadersAbsolutePath(
|
||||
await copyShadersToExternalDirectory,
|
||||
Constants.mpvAnime4KShaders,
|
||||
),
|
||||
]);
|
||||
@@ -861,29 +868,19 @@ class PlPlayerController {
|
||||
}
|
||||
|
||||
// 音轨
|
||||
if (dataSource.audioSource?.isNotEmpty == true) {
|
||||
await pp.setProperty(
|
||||
'audio-files',
|
||||
Platform.isWindows
|
||||
? dataSource.audioSource!.replaceAll(';', '\\;')
|
||||
: dataSource.audioSource!.replaceAll(':', '\\:'),
|
||||
);
|
||||
late final String audioUri;
|
||||
if (isFileSource) {
|
||||
audioUri = onlyPlayAudio.value || mediaType == 1
|
||||
? ''
|
||||
: path.join(dirPath!, typeTag!, PathUtils.audioNameType2);
|
||||
} else if (dataSource.audioSource?.isNotEmpty == true) {
|
||||
audioUri = Platform.isWindows
|
||||
? dataSource.audioSource!.replaceAll(';', '\\;')
|
||||
: dataSource.audioSource!.replaceAll(':', '\\:');
|
||||
} else {
|
||||
await pp.setProperty('audio-files', '');
|
||||
}
|
||||
|
||||
// 字幕
|
||||
if (dataSource.subFiles?.isNotEmpty == true) {
|
||||
await pp.setProperty(
|
||||
'sub-files',
|
||||
Platform.isWindows
|
||||
? dataSource.subFiles!.replaceAll(';', '\\;')
|
||||
: dataSource.subFiles!.replaceAll(':', '\\:'),
|
||||
);
|
||||
await pp.setProperty("subs-with-matching-audio", "no");
|
||||
await pp.setProperty("sub-forced-only", "yes");
|
||||
await pp.setProperty("blend-subtitles", "video");
|
||||
audioUri = '';
|
||||
}
|
||||
await pp.setProperty('audio-files', audioUri);
|
||||
|
||||
_videoController ??= VideoController(
|
||||
player,
|
||||
@@ -928,41 +925,39 @@ class PlPlayerController {
|
||||
filters = null;
|
||||
}
|
||||
|
||||
if (kDebugMode) debugPrint(filters.toString());
|
||||
// if (kDebugMode) debugPrint(filters.toString());
|
||||
|
||||
if (dataSource.type == DataSourceType.asset) {
|
||||
final assetUrl = dataSource.videoSource!.startsWith("asset://")
|
||||
? dataSource.videoSource!
|
||||
: "asset://${dataSource.videoSource!}";
|
||||
await player.open(
|
||||
Media(
|
||||
assetUrl,
|
||||
httpHeaders: dataSource.httpHeaders,
|
||||
start: seekTo,
|
||||
extras: filters,
|
||||
),
|
||||
play: false,
|
||||
late final String videoUri;
|
||||
if (isFileSource) {
|
||||
videoUri = path.join(
|
||||
dirPath!,
|
||||
typeTag!,
|
||||
mediaType == 1
|
||||
? PathUtils.videoNameType1
|
||||
: onlyPlayAudio.value
|
||||
? PathUtils.audioNameType2
|
||||
: PathUtils.videoNameType2,
|
||||
);
|
||||
} else {
|
||||
await player.open(
|
||||
Media(
|
||||
dataSource.videoSource!,
|
||||
httpHeaders: dataSource.httpHeaders,
|
||||
start: seekTo,
|
||||
extras: filters,
|
||||
),
|
||||
play: false,
|
||||
);
|
||||
videoUri = dataSource.videoSource!;
|
||||
}
|
||||
// 音轨
|
||||
// player.setAudioTrack(
|
||||
// AudioTrack.uri(dataSource.audioSource!),
|
||||
// );
|
||||
await player.open(
|
||||
Media(
|
||||
videoUri,
|
||||
httpHeaders: dataSource.httpHeaders,
|
||||
start: seekTo,
|
||||
extras: filters,
|
||||
),
|
||||
play: false,
|
||||
);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
Future<bool> refreshPlayer() async {
|
||||
if (isFileSource) {
|
||||
return true;
|
||||
}
|
||||
if (_videoPlayerController == null) {
|
||||
// SmartDialog.showToast('视频播放器为空,请重新进入本页面');
|
||||
return false;
|
||||
@@ -1123,7 +1118,12 @@ class PlPlayerController {
|
||||
debugPrint(log.toString());
|
||||
})),
|
||||
videoPlayerController!.stream.error.listen((String event) {
|
||||
debugPrint('MPV Exception: $event');
|
||||
if (kDebugMode) {
|
||||
debugPrint('MPV Exception: $event');
|
||||
}
|
||||
if (isFileSource && event.startsWith("Failed to open file")) {
|
||||
return;
|
||||
}
|
||||
if (isLive) {
|
||||
if (event.startsWith('tcp: ffurl_read returned ') ||
|
||||
event.startsWith("Failed to open https://") ||
|
||||
|
||||
Reference in New Issue
Block a user