Merge branch 'main' into feature-minePage

This commit is contained in:
guozhigq
2024-10-16 14:17:24 +08:00
parent 676b2f18eb
commit 174eff7151
62 changed files with 1738 additions and 1371 deletions

View File

@ -1,3 +1,4 @@
import 'package:app_links/app_links.dart';
import 'package:appscheme/appscheme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -10,22 +11,29 @@ import 'url_utils.dart';
import 'utils.dart';
class PiliSchame {
static late AppLinks appLinks;
static AppScheme appScheme = AppSchemeImpl.getInstance()!;
static Future<void> init() async {
///
final SchemeEntity? value = await appScheme.getInitScheme();
if (value != null) {
_routePush(value);
}
appLinks = AppLinks();
appLinks.uriLinkStream.listen((Uri uri) {
final String scheme = uri.scheme;
if (RegExp(r'^pili', caseSensitive: false).hasMatch(scheme)) {
piliScheme(uri);
}
});
appScheme.getInitScheme().then((SchemeEntity? value) {
if (value != null) {
_routePush(value);
}
});
/// 完整链接进入 b23.无效
appScheme.getLatestScheme().then((SchemeEntity? value) {
if (value != null) {
_routePush(value);
}
});
/// 注册从外部打开的Scheme监听信息 #
appScheme.registerSchemeListener().listen((SchemeEntity? event) {
if (event != null) {
_routePush(event);
@ -36,88 +44,11 @@ class PiliSchame {
/// 路由跳转
static void _routePush(value) async {
final String scheme = value.scheme;
final String host = value.host;
final String path = value.path;
if (scheme == 'bilibili') {
switch (host) {
case 'root':
Navigator.popUntil(
Get.context!, (Route<dynamic> route) => route.isFirst);
break;
case 'space':
final String mid = path.split('/').last;
Get.toNamed<dynamic>(
'/member?mid=$mid',
arguments: <String, dynamic>{'face': null},
);
break;
case 'video':
String pathQuery = path.split('/').last;
final numericRegex = RegExp(r'^[0-9]+$');
if (numericRegex.hasMatch(pathQuery)) {
pathQuery = 'AV$pathQuery';
}
Map map = IdUtils.matchAvorBv(input: pathQuery);
if (map.containsKey('AV')) {
_videoPush(map['AV'], null);
} else if (map.containsKey('BV')) {
_videoPush(null, map['BV']);
} else {
SmartDialog.showToast('投稿匹配失败');
}
break;
case 'live':
final String roomId = path.split('/').last;
Get.toNamed<dynamic>(
'/liveRoom?roomid=$roomId',
arguments: <String, String?>{'liveItem': null, 'heroTag': roomId},
);
break;
case 'bangumi':
if (path.startsWith('/season')) {
final String seasonId = path.split('/').last;
RoutePush.bangumiPush(int.parse(seasonId), null);
}
break;
case 'opus':
if (path.startsWith('/detail')) {
var opusId = path.split('/').last;
Get.toNamed('/opus', parameters: {
'title': '',
'id': opusId,
'articleType': 'opus',
});
}
break;
case 'search':
Get.toNamed('/searchResult', parameters: {'keyword': ''});
break;
case 'article':
final String id = path.split('/').last.split('?').first;
Get.toNamed(
'/read',
parameters: {
'title': 'cv$id',
'id': id,
'dynamicType': 'read',
},
);
break;
case 'pgc':
if (path.contains('ep')) {
final String lastPathSegment = path.split('/').last;
RoutePush.bangumiPush(
null, int.parse(lastPathSegment.split('?').first));
}
break;
default:
SmartDialog.showToast('未匹配地址,请联系开发者');
Clipboard.setData(ClipboardData(text: value.toJson().toString()));
break;
}
biliScheme(value);
}
if (scheme == 'https') {
fullPathPush(value);
httpsScheme(value);
}
}
@ -148,7 +79,7 @@ class PiliSchame {
}
}
static Future<void> fullPathPush(SchemeEntity value) async {
static Future<void> httpsScheme(SchemeEntity value) async {
// https://m.bilibili.com/bangumi/play/ss39708
// https | m.bilibili.com | /bangumi/play/ss39708
// final String scheme = value.scheme!;
@ -175,6 +106,11 @@ class PiliSchame {
if (lastPathSegment.contains('ep')) {
RoutePush.bangumiPush(null, Utils.matchNum(lastPathSegment).first);
}
} else if (path.startsWith('/BV')) {
final String bvid = path.split('?').first.split('/').last;
_videoPush(null, bvid);
} else if (path.startsWith('/av')) {
_videoPush(Utils.matchNum(path.split('?').first).first, null);
}
} else if (host.contains('live')) {
int roomId = int.parse(path!.split('/').last);
@ -276,6 +212,140 @@ class PiliSchame {
}
}
static Future<void> biliScheme(SchemeEntity value) async {
final String host = value.host!;
final String path = value.path!;
switch (host) {
case 'root':
Navigator.popUntil(
Get.context!, (Route<dynamic> route) => route.isFirst);
break;
case 'space':
final String mid = path.split('/').last;
Get.toNamed<dynamic>(
'/member?mid=$mid',
arguments: <String, dynamic>{'face': null},
);
break;
case 'video':
String pathQuery = path.split('/').last;
final numericRegex = RegExp(r'^[0-9]+$');
if (numericRegex.hasMatch(pathQuery)) {
pathQuery = 'AV$pathQuery';
}
Map map = IdUtils.matchAvorBv(input: pathQuery);
if (map.containsKey('AV')) {
_videoPush(map['AV'], null);
} else if (map.containsKey('BV')) {
_videoPush(null, map['BV']);
} else {
SmartDialog.showToast('投稿匹配失败');
}
break;
case 'live':
final String roomId = path.split('/').last;
Get.toNamed<dynamic>(
'/liveRoom?roomid=$roomId',
arguments: <String, String?>{'liveItem': null, 'heroTag': roomId},
);
break;
case 'bangumi':
if (path.startsWith('/season')) {
final String seasonId = path.split('/').last;
RoutePush.bangumiPush(int.parse(seasonId), null);
}
break;
case 'opus':
if (path.startsWith('/detail')) {
var opusId = path.split('/').last;
Get.toNamed('/opus', parameters: {
'title': '',
'id': opusId,
'articleType': 'opus',
});
}
break;
case 'search':
Get.toNamed('/searchResult', parameters: {'keyword': ''});
break;
case 'article':
final String id = path.split('/').last.split('?').first;
Get.toNamed(
'/read',
parameters: {
'title': 'cv$id',
'id': id,
'dynamicType': 'read',
},
);
break;
case 'pgc':
if (path.contains('ep')) {
final String lastPathSegment = path.split('/').last;
RoutePush.bangumiPush(
null, int.parse(lastPathSegment.split('?').first));
}
break;
default:
SmartDialog.showToast('未匹配地址,请联系开发者');
Clipboard.setData(ClipboardData(text: value.toJson().toString()));
break;
}
}
static Future<void> piliScheme(Uri value) async {
final String host = value.host;
final String path = value.path;
final String arg = path.split('/').last;
switch (host) {
case 'home':
case 'root':
Get.toNamed('/');
break;
case 'member':
if (arg != '') {
final int? mid = int.tryParse(arg);
if (mid == null) {
SmartDialog.showToast('用户id有误');
return;
}
Get.toNamed<dynamic>(
'/member?mid=$mid',
arguments: <String, dynamic>{'face': null},
);
} else {
Get.toNamed('/mine');
}
break;
case 'search':
if (arg != '') {
final String encodedArg = Uri.decodeComponent(arg);
Get.toNamed('/searchResult', parameters: {'keyword': encodedArg});
} else {
Get.toNamed('/search');
}
break;
case 'setting':
Get.toNamed('/setting');
break;
case 'fav':
Get.toNamed('/fav');
break;
case 'history':
Get.toNamed('/history');
break;
case 'later':
Get.toNamed('/later');
break;
case 'msg':
Get.toNamed('/whisper');
break;
default:
Get.toNamed('/');
break;
}
}
static void _handleEpisodePath(String lastPathSegment, String redirectUrl) {
final String seasonId = _extractIdFromPath(lastPathSegment);
RoutePush.bangumiPush(null, Utils.matchNum(seasonId).first);

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@ -50,13 +51,17 @@ class CacheManage {
Future<double> getTotalSizeOfFilesInDir(final FileSystemEntity file) async {
if (file is File) {
int length = await file.length();
return double.parse(length.toString());
return length.toDouble();
}
if (file is Directory) {
final List<FileSystemEntity> children = file.listSync();
double total = 0;
for (final FileSystemEntity child in children) {
total += await getTotalSizeOfFilesInDir(child);
try {
await for (final FileSystemEntity child in file.list()) {
total += await getTotalSizeOfFilesInDir(child);
}
} catch (e) {
// 处理错误,例如记录日志或显示错误消息
print('读取目录时出错: $e');
}
return total;
}
@ -77,16 +82,17 @@ class CacheManage {
// 清除缓存
Future<bool> clearCacheAll() async {
bool cleanStatus = await SmartDialog.show(
useSystem: true,
animationType: SmartAnimationType.centerFade_otherSlide,
bool? cleanStatus = await showDialog<bool>(
context: Get.context!,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: const Text('该操作将清除图片及网络请求缓存数据,确认清除?'),
actions: [
TextButton(
onPressed: (() => {SmartDialog.dismiss()}),
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
@ -94,40 +100,45 @@ class CacheManage {
),
TextButton(
onPressed: () async {
SmartDialog.dismiss();
SmartDialog.showLoading(msg: '正在清除...');
try {
// 清除缓存 图片缓存
await clearLibraryCache();
SmartDialog.dismiss().then((res) {
SmartDialog.showToast('清除完成');
});
} catch (err) {
SmartDialog.dismiss();
SmartDialog.showToast(err.toString());
}
Navigator.of(context).pop(true);
},
child: const Text('确认'),
)
),
],
);
},
).then((res) {
return true;
});
return cleanStatus;
);
if (cleanStatus != null && cleanStatus) {
SmartDialog.showLoading(msg: '正在清除...');
try {
// 清除缓存 图片缓存
await clearLibraryCache();
SmartDialog.dismiss().then((res) {
SmartDialog.showToast('清除完成');
});
} catch (err) {
SmartDialog.dismiss();
SmartDialog.showToast(err.toString());
}
}
return cleanStatus!;
}
/// 清除 Documents 目录下的 DioCache.db
Future clearApplicationCache() async {
Directory directory = await getApplicationDocumentsDirectory();
if (directory.existsSync()) {
String dioCacheFileName =
'${directory.path}${Platform.pathSeparator}DioCache.db';
var dioCacheFile = File(dioCacheFileName);
if (dioCacheFile.existsSync()) {
dioCacheFile.delete();
Future<void> clearApplicationCache() async {
try {
Directory directory = await getApplicationDocumentsDirectory();
if (directory.existsSync()) {
String dioCacheFileName =
'${directory.path}${Platform.pathSeparator}DioCache.db';
File dioCacheFile = File(dioCacheFileName);
if (await dioCacheFile.exists()) {
await dioCacheFile.delete();
}
}
} catch (e) {
// 处理错误,例如记录日志或显示错误消息
print('清除缓存时出错: $e');
}
}

View File

@ -15,6 +15,7 @@ class GlobalDataCache {
late FullScreenGestureMode fullScreenGestureMode;
late bool enablePlayerControlAnimation;
late List<String> actionTypeSort;
String? wWebid;
/// 播放器相关
// 弹幕开关
@ -59,7 +60,7 @@ class GlobalDataCache {
defaultValue: 10); // 设置全局变量
fullScreenGestureMode = FullScreenGestureMode.values[setting.get(
SettingBoxKey.fullScreenGestureMode,
defaultValue: FullScreenGestureMode.values.last.index) as int];
defaultValue: FullScreenGestureMode.fromBottomtoTop.index)];
enablePlayerControlAnimation = setting
.get(SettingBoxKey.enablePlayerControlAnimation, defaultValue: true);
actionTypeSort = await setting.get(SettingBoxKey.actionTypeSort,

View File

@ -1,21 +1,51 @@
import 'dart:async';
import 'dart:isolate';
class SubTitleUtils {
// 格式整理
static String convertToWebVTT(List jsonData) {
String webVTTContent = 'WEBVTT FILE\n\n';
static Future<String> convertToWebVTT(List jsonData) async {
final receivePort = ReceivePort();
await Isolate.spawn(_convertToWebVTTIsolate, receivePort.sendPort);
for (int i = 0; i < jsonData.length; i++) {
final item = jsonData[i];
double from = double.parse(item['from'].toString());
double to = double.parse(item['to'].toString());
int sid = (item['sid'] ?? 0) as int;
String content = item['content'] as String;
final sendPort = await receivePort.first as SendPort;
final response = ReceivePort();
sendPort.send([jsonData, response.sendPort]);
webVTTContent += '$sid\n';
webVTTContent += '${formatTime(from)} --> ${formatTime(to)}\n';
webVTTContent += '$content\n\n';
return await response.first as String;
}
static void _convertToWebVTTIsolate(SendPort sendPort) async {
final port = ReceivePort();
sendPort.send(port.sendPort);
await for (final message in port) {
final List jsonData = message[0];
final SendPort replyTo = message[1];
String webVTTContent = 'WEBVTT FILE\n\n';
int chunkSize = 100; // 每次处理100条数据
int totalChunks = (jsonData.length / chunkSize).ceil();
for (int chunk = 0; chunk < totalChunks; chunk++) {
int start = chunk * chunkSize;
int end = start + chunkSize;
if (end > jsonData.length) end = jsonData.length;
for (int i = start; i < end; i++) {
final item = jsonData[i];
double from = double.parse(item['from'].toString());
double to = double.parse(item['to'].toString());
int sid = (item['sid'] ?? 0) as int;
String content = item['content'] as String;
webVTTContent += '$sid\n';
webVTTContent += '${formatTime(from)} --> ${formatTime(to)}\n';
webVTTContent += '$content\n\n';
}
}
replyTo.send(webVTTContent);
}
return webVTTContent;
}
static String formatTime(num seconds) {

View File

@ -306,7 +306,7 @@ class Utils {
onPressed: () async {
await SmartDialog.dismiss();
launchUrl(
Uri.parse('https://www.123pan.com/s/9sVqVv-flu0A.html'),
Uri.parse('https://www.123684.com/s/9sVqVv-DEZ0A'),
mode: LaunchMode.externalApplication,
);
},