* tweak

* opt: async

* tweak

* opt: PopularSeries tile

* tweak

* opt: sc

* mod: more account type

* tweak

* opt: qrcode

* tweak

* partial revert: opt: sc

* fix

* fix

* mod: window enqueue
This commit is contained in:
My-Responsitories
2025-09-26 00:02:55 +08:00
committed by GitHub
parent 67c25bd130
commit 4ae3bd2845
29 changed files with 520 additions and 554 deletions

View File

@@ -55,6 +55,25 @@ class AccountManager extends Interceptor {
Api.searchByType,
Api.dynSearch,
Api.searchArchive,
// Api.memberInfo,
// Api.bgmDetail,
// Api.space,
// Api.spaceAudio,
// Api.spaceComic,
// Api.spaceArchive,
// Api.spaceChargingArchive,
// Api.spaceSeason,
// Api.spaceSeries,
// Api.spaceBangumi,
// Api.spaceOpus,
// Api.spaceFav,
// Api.seasonSeries,
// Api.matchInfo,
// Api.articleList,
// Api.opusDetail,
// Api.articleView,
// Api.articleInfo,
},
AccountType.recommend: {
Api.recommendListWeb,
@@ -81,6 +100,11 @@ class AccountManager extends Interceptor {
Api.liveSecondList,
Api.liveRoomAreaList,
Api.liveSearch,
Api.videoRelation,
Api.bgmRecommend,
Api.dynTopicRcmd,
Api.topicFeed,
Api.topicTop,
},
// progress
AccountType.video: {

View File

@@ -748,12 +748,12 @@ abstract class PiliScheme {
return false;
case 'video':
// if (kDebugMode) debugPrint('投稿');
final Map<String, dynamic> map = IdUtils.matchAvorBv(input: path);
if (map.isNotEmpty) {
final res = IdUtils.matchAvorBv(input: path);
if (res.isNotEmpty) {
final queryParameters = uri.queryParameters;
videoPush(
map['AV'],
map['BV'],
res.av,
res.bv,
off: off,
progress: queryParameters['dm_progress'],
part: queryParameters['p'],
@@ -910,11 +910,11 @@ abstract class PiliScheme {
launchURL();
return false;
default:
Map map = IdUtils.matchAvorBv(input: area?.split('?').first);
if (map.isNotEmpty) {
final res = IdUtils.matchAvorBv(input: area?.split('?').first);
if (res.isNotEmpty) {
videoPush(
map['AV'],
map['BV'],
res.av,
res.bv,
off: off,
);
return true;

View File

@@ -8,7 +8,9 @@ import 'package:path_provider/path_provider.dart';
abstract class CacheManage {
// 获取缓存目录
static Future<int> loadApplicationCache() async {
static Future<int> loadApplicationCache([
final num maxSize = double.infinity,
]) async {
/// clear all of image in memory
// clearMemoryImageCache();
/// get ImageCache
@@ -20,55 +22,39 @@ abstract class CacheManage {
if (Utils.isDesktop) {
final dir = Directory('${tempDirectory.path}/libCachedImageData');
if (dir.existsSync()) {
return await getTotalSizeOfFilesInDir(dir);
return await getTotalSizeOfFilesInDir(dir, maxSize);
} else {
return 0;
}
}
// get_storage directory
Directory docDirectory = await getApplicationDocumentsDirectory();
int cacheSize = 0;
// 获取缓存大小
if (tempDirectory.existsSync()) {
cacheSize += await getTotalSizeOfFilesInDir(tempDirectory);
return await getTotalSizeOfFilesInDir(tempDirectory, maxSize);
}
/// 获取缓存大小 dioCache
if (docDirectory.existsSync()) {
String dioCacheFileName =
'${docDirectory.path}${Platform.pathSeparator}DioCache.db';
var dioCacheFile = File(dioCacheFileName);
if (dioCacheFile.existsSync()) {
cacheSize += await getTotalSizeOfFilesInDir(dioCacheFile);
}
}
return cacheSize;
return 0;
}
// 循环计算文件的大小(递归)
// 循环计算文件的大小
static Future<int> getTotalSizeOfFilesInDir(
final FileSystemEntity file,
) async {
if (file is File) {
int length = await file.length();
return int.parse(length.toString());
}
if (file is Directory) {
final List<FileSystemEntity> children = file.listSync();
int total = 0;
for (final FileSystemEntity child in children) {
total += await getTotalSizeOfFilesInDir(child);
final Directory file, [
final num maxSize = double.infinity,
]) async {
final children = file.list(recursive: true);
int total = 0;
await for (final child in children) {
if (child is File) {
total += await child.length();
if (total >= maxSize) break;
}
return total;
}
return 0;
return total;
}
// 缓存大小格式转换
static String formatSize(num value) {
List<String> unitArr = const ['B', 'K', 'M', 'G', 'T', 'P'];
const unitArr = ['B', 'K', 'M', 'G', 'T', 'P'];
int index = 0;
while (value >= 1024) {
index++;
@@ -78,19 +64,6 @@ abstract class CacheManage {
return size + unitArr.getOrElse(index, orElse: () => '');
}
/// 清除 Documents 目录下的 DioCache.db
static Future<void> 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();
}
}
}
// 清除 Library/Caches 目录及文件缓存
static Future<void> clearLibraryCache() async {
var tempDirectory = await getTemporaryDirectory();
@@ -103,33 +76,20 @@ abstract class CacheManage {
}
if (tempDirectory.existsSync()) {
// await appDocDir.delete(recursive: true);
final List<FileSystemEntity> children = tempDirectory.listSync(
recursive: false,
);
for (final FileSystemEntity file in children) {
final children = tempDirectory.list(recursive: false);
await for (final file in children) {
await file.delete(recursive: true);
}
}
}
/// 递归方式删除目录及文件
static Future<void> deleteDirectory(FileSystemEntity file) async {
if (file is Directory) {
final List<FileSystemEntity> children = file.listSync();
for (final FileSystemEntity child in children) {
await deleteDirectory(child);
}
}
await file.delete();
}
static Future<void> autoClearCache() async {
if (Pref.autoClearCache) {
await clearLibraryCache();
} else {
final maxCacheSize = Pref.maxCacheSize;
if (maxCacheSize != 0) {
final currCache = await loadApplicationCache();
final currCache = await loadApplicationCache(maxCacheSize);
if (currCache >= maxCacheSize) {
await clearLibraryCache();
}

View File

@@ -15,9 +15,9 @@ abstract class IdUtils {
'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';
static final invData = {for (var (i, c) in data.codeUnits.indexed) c: i};
static final bvRegex = RegExp(r'bv[0-9a-zA-Z]{10}', caseSensitive: false);
static final bvRegex = RegExp(r'bv1[0-9a-zA-Z]{9}', caseSensitive: false);
static final bvRegexExact = RegExp(
r'^bv[0-9a-zA-Z]{10}$',
r'^bv1[0-9a-zA-Z]{9}$',
caseSensitive: false,
);
static final avRegex = RegExp(r'av(\d+)', caseSensitive: false);
@@ -54,26 +54,25 @@ abstract class IdUtils {
swap(bvidArr, 4, 7);
bvidArr.removeRange(0, 3);
int tmp = bvidArr.fold(0, (pre, char) => pre * BASE + invData[char]!);
return ((tmp & MASK_CODE) ^ XOR_CODE).toInt();
final tmp = bvidArr.fold(0, (pre, char) => pre * BASE + invData[char]!);
return (tmp & MASK_CODE) ^ XOR_CODE;
}
// 匹配
static Map<String, dynamic> matchAvorBv({String? input}) {
final Map<String, dynamic> result = {};
static AvBvRes matchAvorBv({String? input}) {
if (input == null || input.isEmpty) {
return result;
return const (av: null, bv: null);
}
String? bvid = bvRegex.firstMatch(input)?.group(0);
late String? aid = avRegex.firstMatch(input)?.group(1);
if (bvid != null) {
result['BV'] = bvid;
return (av: null, bv: bvid);
} else if (aid != null) {
result['AV'] = int.parse(aid);
return (av: int.parse(aid), bv: null);
}
return result;
return const (av: null, bv: null);
}
static String genBuvid3() {
@@ -114,3 +113,9 @@ abstract class IdUtils {
return '${randomTraceId.toString()}:${randomTraceId.toString().substring(16, 32)}:0:0';
}
}
typedef AvBvRes = ({int? av, String? bv});
extension AvBvExt on AvBvRes {
bool get isNotEmpty => this != const (av: null, bv: null);
}

View File

@@ -24,33 +24,36 @@ abstract class GStorage {
final String path = dir.path;
await Hive.initFlutter('$path/hive');
regAdapter();
// 登录用户信息
userInfo = await Hive.openBox<UserInfoData>(
'userInfo',
compactionStrategy: (int entries, int deletedEntries) {
return deletedEntries > 2;
},
);
// 本地缓存
localCache = await Hive.openBox(
'localCache',
compactionStrategy: (int entries, int deletedEntries) {
return deletedEntries > 4;
},
);
// 设置
setting = await Hive.openBox('setting');
// 搜索历史
historyWord = await Hive.openBox(
'historyWord',
compactionStrategy: (int entries, int deletedEntries) {
return deletedEntries > 10;
},
);
// 视频设置
video = await Hive.openBox('video');
await Accounts.init();
await Future.wait([
// 登录用户信息
Hive.openBox<UserInfoData>(
'userInfo',
compactionStrategy: (int entries, int deletedEntries) {
return deletedEntries > 2;
},
).then((res) => userInfo = res),
// 本地缓存
Hive.openBox(
'localCache',
compactionStrategy: (int entries, int deletedEntries) {
return deletedEntries > 4;
},
).then((res) => localCache = res),
// 设置
Hive.openBox('setting').then((res) => setting = res),
// 搜索历史
Hive.openBox(
'historyWord',
compactionStrategy: (int entries, int deletedEntries) {
return deletedEntries > 10;
},
).then((res) => historyWord = res),
// 视频设置
Hive.openBox('video').then((res) => video = res),
Accounts.init(),
]);
}
static String exportAllSettings() {

View File

@@ -819,10 +819,10 @@ abstract class Pref {
static bool get minimizeOnExit =>
_setting.get(SettingBoxKey.minimizeOnExit, defaultValue: true);
static List<double> get windowSize => _setting.get(
SettingBoxKey.windowSize,
defaultValue: const [1180.0, 720.0],
);
static Size get windowSize {
final List<double>? size = _setting.get(SettingBoxKey.windowSize);
return size == null ? const Size(1180.0, 720.0) : Size(size[0], size[1]);
}
static List<double>? get windowPosition =>
_setting.get(SettingBoxKey.windowPosition);

View File

@@ -115,9 +115,9 @@ abstract class Update {
static Future<void> onDownload(Map data) async {
SmartDialog.dismiss();
try {
void download(plat) {
void download(String plat) {
if (data['assets'].isNotEmpty) {
for (dynamic i in data['assets']) {
for (Map<String, dynamic> i in data['assets']) {
if (i['name'].contains(plat)) {
PageUtils.launchURL(i['browser_download_url']);
return;
@@ -132,14 +132,8 @@ abstract class Update {
AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
// [arm64-v8a]
download(androidInfo.supportedAbis.first);
} else if (Platform.isIOS) {
download('ios');
} else if (Platform.isWindows) {
download('windows');
} else {
throw UnsupportedError(
'unsupported platform: ${Platform.operatingSystem}',
);
download(Platform.operatingSystem);
}
} catch (e) {
if (kDebugMode) debugPrint('download error: $e');

View File

@@ -44,10 +44,10 @@ abstract class UrlUtils {
String pathSegment,
String redirectUrl,
) async {
final Map matchRes = IdUtils.matchAvorBv(input: pathSegment);
final matchRes = IdUtils.matchAvorBv(input: pathSegment);
if (matchRes.isNotEmpty) {
int? aid = matchRes['AV'];
String? bvid = matchRes['BV'];
final aid = matchRes.av;
String? bvid = matchRes.bv;
bvid ??= IdUtils.av2bv(aid!);
final int? cid = await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid != null) {

View File

@@ -28,17 +28,15 @@ abstract class Utils {
static final bool isDesktop =
Platform.isWindows || Platform.isMacOS || Platform.isLinux;
static Future<({double left, double top})> get windowOffset async {
static Future<Offset> get windowOffset async {
final windowPosition = Pref.windowPosition;
if (windowPosition != null) {
return (left: windowPosition[0], top: windowPosition[1]);
return Offset(windowPosition[0], windowPosition[1]);
}
final Size windowSize = await windowManager.getSize();
final Offset position = await calcWindowPosition(
windowSize,
return await calcWindowPosition(
await windowManager.getSize(),
Alignment.center,
);
return (left: position.dx, top: position.dy);
}
static Future<bool> get isWiFi async {