diff --git a/.gitignore b/.gitignore index 24476c5d..ed16b55a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,11 @@ migrate_working_dir/ .pub/ /build/ +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +.vscode/ + # Symbolication related app.*.symbols @@ -42,3 +47,9 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# FVM Version Cache +.fvm/ + +# FVM Version +.fvmrc \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 69b2d045..49f672fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,13 +1,14 @@ { - "java.configuration.updateBuildConfiguration": "automatic", - "githubPullRequests.ignoredPullRequestBranches": [ - "main" - ], - "rust-analyzer.linkedProjects": [ - ".\\rust\\Cargo.toml" - ], - "files.associations": { - "*.html.erb": "erb", - "cstring": "cpp" - } + "java.configuration.updateBuildConfiguration": "automatic", + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ], + "rust-analyzer.linkedProjects": [ + ".\\rust\\Cargo.toml" + ], + "files.associations": { + "*.html.erb": "erb", + "cstring": "cpp" + }, + "dart.flutterSdkPath": ".fvm/versions/3.22.3" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index baad466e..49effa0b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,6 +20,7 @@ import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:mangayomi/src/rust/frb_generated.dart'; import 'package:media_kit/media_kit.dart'; +import 'package:rhttp/rhttp.dart'; import 'package:window_manager/window_manager.dart'; late Isar isar; @@ -33,6 +34,7 @@ void main(List args) async { } MediaKit.ensureInitialized(); await RustLib.init(); + await Rhttp.init(); if (!(Platform.isAndroid || Platform.isIOS)) { await windowManager.ensureInitialized(); } diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 274711a1..19e6cca5 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -188,8 +188,6 @@ class Settings { bool? useLibass; - bool? useNativeHttpClient; - Settings( {this.id = 227, this.displayType = DisplayType.compactGrid, @@ -272,8 +270,7 @@ class Settings { this.mangaGridSize, this.animeGridSize, this.disableSectionType = SectionType.all, - this.useLibass = true, - this.useNativeHttpClient = false}); + this.useLibass = true}); Settings.fromJson(Map json) { animatePageTransitions = json['animatePageTransitions']; @@ -423,7 +420,6 @@ class Settings { disableSectionType = SectionType.values[json['disableSectionType'] ?? SectionType.all]; useLibass = json['useLibass']; - useNativeHttpClient = json['useNativeHttpClient']; } Map toJson() => { @@ -532,8 +528,7 @@ class Settings { 'mangaGridSize': mangaGridSize, 'animeGridSize': animeGridSize, 'disableSectionType': disableSectionType.index, - 'useLibass': useLibass, - 'useNativeHttpClient': useNativeHttpClient + 'useLibass': useLibass }; } diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index 018a81b2..d1305e66 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -456,18 +456,13 @@ const SettingsSchema = CollectionSchema( name: r'useLibass', type: IsarType.bool, ), - r'useNativeHttpClient': PropertySchema( - id: 83, - name: r'useNativeHttpClient', - type: IsarType.bool, - ), r'usePageTapZones': PropertySchema( - id: 84, + id: 83, name: r'usePageTapZones', type: IsarType.bool, ), r'userAgent': PropertySchema( - id: 85, + id: 84, name: r'userAgent', type: IsarType.string, ) @@ -922,9 +917,8 @@ void _settingsSerialize( writer.writeBool(offsets[80], object.themeIsDark); writer.writeBool(offsets[81], object.updateProgressAfterReading); writer.writeBool(offsets[82], object.useLibass); - writer.writeBool(offsets[83], object.useNativeHttpClient); - writer.writeBool(offsets[84], object.usePageTapZones); - writer.writeString(offsets[85], object.userAgent); + writer.writeBool(offsets[83], object.usePageTapZones); + writer.writeString(offsets[84], object.userAgent); } Settings _settingsDeserialize( @@ -1086,9 +1080,8 @@ Settings _settingsDeserialize( themeIsDark: reader.readBoolOrNull(offsets[80]), updateProgressAfterReading: reader.readBoolOrNull(offsets[81]), useLibass: reader.readBoolOrNull(offsets[82]), - useNativeHttpClient: reader.readBoolOrNull(offsets[83]), - usePageTapZones: reader.readBoolOrNull(offsets[84]), - userAgent: reader.readStringOrNull(offsets[85]), + usePageTapZones: reader.readBoolOrNull(offsets[83]), + userAgent: reader.readStringOrNull(offsets[84]), ); object.chapterFilterBookmarkedList = reader.readObjectList( @@ -1382,8 +1375,6 @@ P _settingsDeserializeProp

( case 83: return (reader.readBoolOrNull(offset)) as P; case 84: - return (reader.readBoolOrNull(offset)) as P; - case 85: return (reader.readStringOrNull(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -6849,34 +6840,6 @@ extension SettingsQueryFilter }); } - QueryBuilder - useNativeHttpClientIsNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'useNativeHttpClient', - )); - }); - } - - QueryBuilder - useNativeHttpClientIsNotNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'useNativeHttpClient', - )); - }); - } - - QueryBuilder - useNativeHttpClientEqualTo(bool? value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'useNativeHttpClient', - value: value, - )); - }); - } - QueryBuilder usePageTapZonesIsNull() { return QueryBuilder.apply(this, (query) { @@ -8092,19 +8055,6 @@ extension SettingsQuerySortBy on QueryBuilder { }); } - QueryBuilder sortByUseNativeHttpClient() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'useNativeHttpClient', Sort.asc); - }); - } - - QueryBuilder - sortByUseNativeHttpClientDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'useNativeHttpClient', Sort.desc); - }); - } - QueryBuilder sortByUsePageTapZones() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'usePageTapZones', Sort.asc); @@ -9005,19 +8955,6 @@ extension SettingsQuerySortThenBy }); } - QueryBuilder thenByUseNativeHttpClient() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'useNativeHttpClient', Sort.asc); - }); - } - - QueryBuilder - thenByUseNativeHttpClientDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'useNativeHttpClient', Sort.desc); - }); - } - QueryBuilder thenByUsePageTapZones() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'usePageTapZones', Sort.asc); @@ -9486,12 +9423,6 @@ extension SettingsQueryWhereDistinct }); } - QueryBuilder distinctByUseNativeHttpClient() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'useNativeHttpClient'); - }); - } - QueryBuilder distinctByUsePageTapZones() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'usePageTapZones'); @@ -10068,13 +9999,6 @@ extension SettingsQueryProperty }); } - QueryBuilder - useNativeHttpClientProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'useNativeHttpClient'); - }); - } - QueryBuilder usePageTapZonesProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'usePageTapZones'); diff --git a/lib/modules/manga/download/providers/download_provider.dart b/lib/modules/manga/download/providers/download_provider.dart index f88149c6..7db31770 100644 --- a/lib/modules/manga/download/providers/download_provider.dart +++ b/lib/modules/manga/download/providers/download_provider.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:io'; import 'package:mangayomi/models/page.dart'; -import 'package:mangayomi/modules/more/settings/advanced/providers/native_http_client.dart'; import 'package:mangayomi/services/background_downloader/background_downloader.dart'; import 'package:isar/isar.dart'; import 'package:mangayomi/main.dart'; @@ -38,14 +37,16 @@ Future> downloadChapter( bool isOk = false; final manga = chapter.manga.value!; final path1 = await storageProvider.getDirectory(); - final regExp = RegExp(r'[^a-zA-Z0-9 .()\-\s]'); + final forbiddenCharacters = + RegExp(r'[\\/:*?"<>|\0]|(^CON$|^PRN$|^AUX$|^NUL$|^COM[1-9]$|^LPT[1-9]$)'); String scanlator = chapter.scanlator!.isNotEmpty - ? "${chapter.scanlator!.replaceAll(regExp, '_')}_" + ? "${chapter.scanlator!.replaceAll(forbiddenCharacters, '_')}_" : ""; + final chapterName = chapter.name!.replaceAll(forbiddenCharacters, ' '); final isManga = chapter.manga.value!.isManga!; final finalPath = - "downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceAll(regExp, '_')}${isManga ? "/$scanlator${chapter.name!.replaceAll(regExp, '_')}" : ""}"; + "downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceAll(forbiddenCharacters, '_')}${isManga ? "/$scanlator${chapter.name!.replaceAll(forbiddenCharacters, '_')}" : ""}"; path = Directory("${path1!.path}$finalPath/"); Map videoHeader = {}; @@ -110,8 +111,7 @@ Future> downloadChapter( bool cbzFileExist = await File("${mangaDir!.path}${chapter.name}.cbz").exists() && ref.watch(saveAsCBZArchiveStateProvider); - bool mp4FileExist = - await File("${mangaDir.path}${chapter.name}.mp4").exists(); + bool mp4FileExist = await File("${mangaDir.path}$chapterName.mp4").exists(); if (!cbzFileExist && isManga || !mp4FileExist && !isManga) { for (var index = 0; index < pageUrls.length; index++) { final path2 = Directory("${path1.path}downloads/"); @@ -119,8 +119,8 @@ Future> downloadChapter( Directory("${path1.path}downloads/${isManga ? "Manga" : "Anime"}/"); final path4 = Directory( "${path5.path}${manga.source} (${manga.lang!.toUpperCase()})/"); - final path3 = - Directory("${path4.path}${manga.name!.replaceAll(regExp, '_')}/"); + final path3 = Directory( + "${path4.path}${manga.name!.replaceAll(forbiddenCharacters, '_')}/"); if (!(await path1.exists())) { await path1.create(); @@ -153,80 +153,89 @@ Future> downloadChapter( headers.addAll(cookie); headers[HttpHeaders.userAgentHeader] = userAgent; } + Map pageHeaders = headers; + pageHeaders.addAll(page.headers ?? {}); + if (isManga) { - if ((await path.exists())) { - if (await File("${path.path}" "${padIndex(index + 1)}.jpg") - .exists()) { - } else { - Map pageHeaders = headers; - pageHeaders.addAll(page.headers ?? {}); - tasks.add(DownloadTask( - taskId: page.url, - headers: pageHeaders, - url: page.url.trim().trimLeft().trimRight(), - filename: "${padIndex(index + 1)}.jpg", - baseDirectory: BaseDirectory.temporary, - directory: 'Mangayomi/$finalPath', - updates: Updates.statusAndProgress, - retries: 3, - allowPause: true, - requiresWiFi: onlyOnWifi)); - } + final file = File( + "${tempDir.path}/Mangayomi/$finalPath/${padIndex(index + 1)}.jpg"); + if (file.existsSync()) { + await file.copy("${path.path}${padIndex(index + 1)}.jpg"); + await file.delete(); } else { - await path.create(); - if (await File("${path.path}" "${padIndex(index + 1)}.jpg") - .exists()) { + if ((await path.exists())) { + if (await File("${path.path}${padIndex(index + 1)}.jpg") + .exists()) { + } else { + tasks.add(DownloadTask( + taskId: page.url, + headers: pageHeaders, + url: page.url.trim().trimLeft().trimRight(), + filename: "${padIndex(index + 1)}.jpg", + baseDirectory: BaseDirectory.temporary, + directory: 'Mangayomi/$finalPath', + updates: Updates.statusAndProgress, + retries: 3, + allowPause: true, + requiresWiFi: onlyOnWifi)); + } } else { - Map pageHeaders = headers; - pageHeaders.addAll(page.headers ?? {}); - tasks.add(DownloadTask( - taskId: page.url, - headers: pageHeaders, - url: page.url.trim().trimLeft().trimRight(), - filename: "${padIndex(index + 1)}.jpg", - baseDirectory: BaseDirectory.temporary, - directory: 'Mangayomi/$finalPath', - updates: Updates.statusAndProgress, - allowPause: true, - retries: 3, - requiresWiFi: onlyOnWifi)); + await path.create(); + if (await File("${path.path}" "${padIndex(index + 1)}.jpg") + .exists()) { + } else { + tasks.add(DownloadTask( + taskId: page.url, + headers: pageHeaders, + url: page.url.trim().trimLeft().trimRight(), + filename: "${padIndex(index + 1)}.jpg", + baseDirectory: BaseDirectory.temporary, + directory: 'Mangayomi/$finalPath', + updates: Updates.statusAndProgress, + allowPause: true, + retries: 3, + requiresWiFi: onlyOnWifi)); + } } } } else { - if ((await path.exists())) { - if (await File("${path.path}${chapter.name}.mp4").exists()) { - } else { - Map pageHeaders = headers; - pageHeaders.addAll(page.headers ?? {}); - tasks.add(DownloadTask( - taskId: page.url, - headers: pageHeaders, - url: page.url.trim().trimLeft().trimRight(), - filename: "${chapter.name}.mp4", - baseDirectory: BaseDirectory.temporary, - directory: 'Mangayomi/$finalPath', - updates: Updates.statusAndProgress, - allowPause: true, - retries: 3, - requiresWiFi: onlyOnWifi)); - } + final file = + File("${tempDir.path}/Mangayomi/$finalPath/$chapterName.mp4"); + if (file.existsSync()) { + await file.copy("${path.path}$chapterName.mp4"); + await file.delete(); } else { - await path.create(); - if (await File("${path.path}${chapter.name}.mp4").exists()) { + if ((await path.exists())) { + if (await File("${path.path}$chapterName.mp4").exists()) { + } else { + tasks.add(DownloadTask( + taskId: page.url, + headers: pageHeaders, + url: page.url.trim().trimLeft().trimRight(), + filename: "$chapterName.mp4", + baseDirectory: BaseDirectory.temporary, + directory: 'Mangayomi/$finalPath', + updates: Updates.statusAndProgress, + allowPause: true, + retries: 3, + requiresWiFi: onlyOnWifi)); + } } else { - Map pageHeaders = headers; - pageHeaders.addAll(page.headers ?? {}); - tasks.add(DownloadTask( - taskId: page.url, - headers: pageHeaders, - url: page.url.trim().trimLeft().trimRight(), - filename: "${chapter.name}.mp4", - baseDirectory: BaseDirectory.temporary, - directory: 'Mangayomi/$finalPath', - updates: Updates.statusAndProgress, - allowPause: true, - retries: 3, - requiresWiFi: onlyOnWifi)); + await path.create(); + if (await File("${path.path}$chapterName.mp4").exists()) { + } else { + tasks.add(DownloadTask( + taskId: page.url, + headers: pageHeaders, + url: page.url.trim().trimLeft().trimRight(), + filename: "$chapterName.mp4", + baseDirectory: BaseDirectory.temporary, + directory: 'Mangayomi/$finalPath', + updates: Updates.statusAndProgress, + allowPause: true, + retries: 3, + requiresWiFi: onlyOnWifi)); + } } } } @@ -249,24 +258,16 @@ Future> downloadChapter( isar.downloads.putSync(download..chapter.value = chapter); }); } else { - if (isManga) { - await FileDownloader( - useNativeHttpClient: - ref.watch(useNativeHttpClientStateProvider)) - .downloadBatch( - tasks, - batchProgressCallback: (succeeded, failed) async { + await FileDownloader().downloadBatch( + tasks, + batchProgressCallback: (succeeded, failed) async { + if (isManga) { if (succeeded == tasks.length) { - if (isManga) { - savePageUrls(); - if (ref.watch(saveAsCBZArchiveStateProvider)) { - await ref.watch(convertToCBZProvider( - path!.path, - mangaDir.path, - chapter.name!, - pageUrls.map((e) => e.url).toList()) - .future); - } + savePageUrls(); + if (ref.watch(saveAsCBZArchiveStateProvider)) { + await ref.watch(convertToCBZProvider(path!.path, mangaDir.path, + chapter.name!, pageUrls.map((e) => e.url).toList()) + .future); } } bool isEmpty = isar.downloads @@ -298,20 +299,11 @@ Future> downloadChapter( ..isDownload = (succeeded == tasks.length)); }); } - }, - taskProgressCallback: (taskProgress) async { - if (taskProgress.progress == 1.0) { - final file = File( - "${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}"); - await file.copy("${path!.path}/${taskProgress.task.filename}"); - await file.delete(); - } - }, - ); - } else { - await FileDownloader(useNativeHttpClient: false).download( - tasks.first, - onProgress: (progress) async { + } + }, + taskProgressCallback: (taskProgress) async { + final progress = taskProgress.progress; + if (!isManga) { bool isEmpty = isar.downloads .filter() .chapterIdEqualTo(chapter.id!) @@ -341,17 +333,15 @@ Future> downloadChapter( ..isDownload = (progress == 1.0)); }); } - }, - onStatus: (status) async { - if (status == TaskStatus.complete) { - final file = File( - "${tempDir.path}/${tasks.first.directory}/${tasks.first.filename}"); - await file.copy("${path!.path}/${tasks.first.filename}"); - await file.delete(); - } - }, - ); - } + } + if (progress == 1.0) { + final file = File( + "${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}"); + await file.copy("${path!.path}${taskProgress.task.filename}"); + await file.delete(); + } + }, + ); } } return pageUrls; diff --git a/lib/modules/manga/download/providers/download_provider.g.dart b/lib/modules/manga/download/providers/download_provider.g.dart index 38f603c4..8900d397 100644 --- a/lib/modules/manga/download/providers/download_provider.g.dart +++ b/lib/modules/manga/download/providers/download_provider.g.dart @@ -6,7 +6,7 @@ part of 'download_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$downloadChapterHash() => r'a2ba0ce07800518f35f47fa2272049357141a854'; +String _$downloadChapterHash() => r'eca8ccbe5f93f07c3471af81355fe9b3a8ec11e8'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/modules/more/download_queue/download_queue_screen.dart b/lib/modules/more/download_queue/download_queue_screen.dart index 17d8ade9..77529fb8 100644 --- a/lib/modules/more/download_queue/download_queue_screen.dart +++ b/lib/modules/more/download_queue/download_queue_screen.dart @@ -149,8 +149,8 @@ class DownloadQueueScreen extends ConsumerWidget { }); } else if (value.toString() == 'CancelAll') { final chapterIds = entries - .where((element) => - element.chapter.value!.name == + .where((e) => + e.chapter.value!.name == element.chapter.value!.name) .map((e) => e.chapterId) .toList(); diff --git a/lib/modules/more/settings/advanced/advanced.dart b/lib/modules/more/settings/advanced/advanced.dart deleted file mode 100644 index 5d79ffea..00000000 --- a/lib/modules/more/settings/advanced/advanced.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:mangayomi/modules/more/settings/advanced/providers/native_http_client.dart'; -import 'package:mangayomi/providers/l10n_providers.dart'; -import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; - -class AdvancedScreen extends ConsumerWidget { - const AdvancedScreen({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final l10n = l10nLocalizations(context)!; - final useNativeHttpClient = ref.watch(useNativeHttpClientStateProvider); - - return Scaffold( - appBar: AppBar( - title: Text(l10n.advanced), - ), - body: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: SwitchListTile( - title: Text(l10n.use_native_http_client), - subtitle: Text( - l10n.use_native_http_client_info, - style: - TextStyle(fontSize: 11, color: context.secondaryColor), - ), - value: useNativeHttpClient, - onChanged: (value) { - ref - .read(useNativeHttpClientStateProvider.notifier) - .set(value); - }), - ), - ], - ), - ), - ); - } -} diff --git a/lib/modules/more/settings/advanced/providers/native_http_client.dart b/lib/modules/more/settings/advanced/providers/native_http_client.dart deleted file mode 100644 index 23c22098..00000000 --- a/lib/modules/more/settings/advanced/providers/native_http_client.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:mangayomi/main.dart'; -import 'package:mangayomi/models/settings.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'native_http_client.g.dart'; - -@riverpod -class UseNativeHttpClientState extends _$UseNativeHttpClientState { - @override - bool build() { - return isar.settings.getSync(227)!.useNativeHttpClient ?? false; - } - - void set(bool value) { - final settings = isar.settings.getSync(227); - state = value; - isar.writeTxnSync( - () => isar.settings.putSync(settings!..useNativeHttpClient = value)); - } -} diff --git a/lib/modules/more/settings/advanced/providers/native_http_client.g.dart b/lib/modules/more/settings/advanced/providers/native_http_client.g.dart deleted file mode 100644 index 4fa0318e..00000000 --- a/lib/modules/more/settings/advanced/providers/native_http_client.g.dart +++ /dev/null @@ -1,27 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'native_http_client.dart'; - -// ************************************************************************** -// RiverpodGenerator -// ************************************************************************** - -String _$useNativeHttpClientStateHash() => - r'477bc54ed73067db40dc291532818108a2a37536'; - -/// See also [UseNativeHttpClientState]. -@ProviderFor(UseNativeHttpClientState) -final useNativeHttpClientStateProvider = - AutoDisposeNotifierProvider.internal( - UseNativeHttpClientState.new, - name: r'useNativeHttpClientStateProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$useNativeHttpClientStateHash, - dependencies: null, - allTransitiveDependencies: null, -); - -typedef _$UseNativeHttpClientState = AutoDisposeNotifier; -// ignore_for_file: type=lint -// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/modules/more/settings/settings_screen.dart b/lib/modules/more/settings/settings_screen.dart index e44f0bab..fbf4a00f 100644 --- a/lib/modules/more/settings/settings_screen.dart +++ b/lib/modules/more/settings/settings_screen.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart'; @@ -48,12 +46,6 @@ class SettingsScreen extends StatelessWidget { subtitle: l10n.browse_subtitle, icon: Icons.explore_rounded, onTap: () => context.push('/browseS')), - if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) - ListTileWidget( - title: l10n.advanced, - subtitle: l10n.browse_subtitle, - icon: Icons.code_rounded, - onTap: () => context.push('/advancedScreen')), ListTileWidget( onTap: () { context.push('/about'); diff --git a/lib/modules/widgets/custom_draggable_tabbar.dart b/lib/modules/widgets/custom_draggable_tabbar.dart index 66e809c4..9b3ecf3f 100644 --- a/lib/modules/widgets/custom_draggable_tabbar.dart +++ b/lib/modules/widgets/custom_draggable_tabbar.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:draggable_menu/draggable_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -119,7 +121,7 @@ Future customDraggableTabBar( } : 0; return Scaffold( - backgroundColor: Colors.transparent, + backgroundColor: Platform.isLinux ? null : Colors.transparent, body: Container( width: context.width(1) - width, decoration: BoxDecoration( diff --git a/lib/providers/storage_provider.dart b/lib/providers/storage_provider.dart index c5f690f1..51b28c33 100644 --- a/lib/providers/storage_provider.dart +++ b/lib/providers/storage_provider.dart @@ -17,7 +17,9 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:path/path.dart' as path; class StorageProvider { - final RegExp _regExpChar = RegExp(r'[^a-zA-Z0-9 .()\-\s]'); + final _forbiddenCharacters = + RegExp(r'[\\/:*?"<>|\0]|(^CON$|^PRN$|^AUX$|^NUL$|^COM[1-9]$|^LPT[1-9]$)'); + Future requestPermission() async { Permission permission = Permission.manageExternalStorage; if (Platform.isAndroid) { @@ -78,12 +80,12 @@ class StorageProvider { ) async { final manga = chapter.manga.value!; String scanlator = chapter.scanlator?.isNotEmpty ?? false - ? "${chapter.scanlator!.replaceAll(_regExpChar, '_')}_" + ? "${chapter.scanlator!.replaceAll(_forbiddenCharacters, '_')}_" : ""; final isManga = chapter.manga.value!.isManga!; final dir = await getDirectory(); return Directory( - "${dir!.path}/downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceAll(_regExpChar, '_')}/$scanlator${chapter.name!.replaceAll(_regExpChar, '_')}/"); + "${dir!.path}/downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceAll(_forbiddenCharacters, '_')}/$scanlator${chapter.name!.replaceAll(_forbiddenCharacters, '_')}/"); } Future getMangaMainDirectory(Chapter chapter) async { @@ -91,7 +93,7 @@ class StorageProvider { final isManga = chapter.manga.value!.isManga!; final dir = await getDirectory(); return Directory( - "${dir!.path}/downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceAll(_regExpChar, '_')}/"); + "${dir!.path}/downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceAll(_forbiddenCharacters, '_')}/"); } Future getDatabaseDirectory() async { diff --git a/lib/router/router.dart b/lib/router/router.dart index 8455bb6e..48aed1cf 100644 --- a/lib/router/router.dart +++ b/lib/router/router.dart @@ -12,7 +12,6 @@ import 'package:mangayomi/modules/browse/extension/widgets/create_extension.dart import 'package:mangayomi/modules/browse/sources/sources_filter_screen.dart'; import 'package:mangayomi/modules/more/backup_and_restore/backup_and_restore.dart'; import 'package:mangayomi/modules/more/categories/categories_screen.dart'; -import 'package:mangayomi/modules/more/settings/advanced/advanced.dart'; import 'package:mangayomi/modules/more/settings/downloads/downloads_screen.dart'; import 'package:mangayomi/modules/more/settings/player/player_screen.dart'; import 'package:mangayomi/modules/more/settings/track/track.dart'; @@ -534,19 +533,6 @@ class RouterNotifier extends ChangeNotifier { ); }, ), - GoRoute( - path: "/advancedScreen", - name: "advancedScreen", - builder: (context, state) { - return const AdvancedScreen(); - }, - pageBuilder: (context, state) { - return transitionPage( - key: state.pageKey, - child: const AdvancedScreen(), - ); - }, - ), ]; } diff --git a/lib/services/anime_extractors/dood_extractor.dart b/lib/services/anime_extractors/dood_extractor.dart index 2a9f5ad9..b0d410f0 100644 --- a/lib/services/anime_extractors/dood_extractor.dart +++ b/lib/services/anime_extractors/dood_extractor.dart @@ -10,7 +10,8 @@ class DoodExtractor { String? quality, bool redirect = true, }) async { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); final newQuality = quality ?? ('Doodstream ${redirect ? ' mirror' : ''}'); try { diff --git a/lib/services/anime_extractors/filemoon.dart b/lib/services/anime_extractors/filemoon.dart index 48660e01..4022e0dd 100644 --- a/lib/services/anime_extractors/filemoon.dart +++ b/lib/services/anime_extractors/filemoon.dart @@ -7,7 +7,8 @@ import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/xpath_selector.dart'; class FilemoonExtractor { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); Future> videosFromUrl( String url, String prefix, String suffix) async { diff --git a/lib/services/anime_extractors/gogocdn_extractor.dart b/lib/services/anime_extractors/gogocdn_extractor.dart index 97dfd178..1f8de516 100644 --- a/lib/services/anime_extractors/gogocdn_extractor.dart +++ b/lib/services/anime_extractors/gogocdn_extractor.dart @@ -8,7 +8,8 @@ import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; class GogoCdnExtractor { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); final JsonCodec json = const JsonCodec(); Future> videosFromUrl(String serverUrl) async { diff --git a/lib/services/anime_extractors/mp4upload_extractor.dart b/lib/services/anime_extractors/mp4upload_extractor.dart index 51c5bd07..4e9c00c3 100644 --- a/lib/services/anime_extractors/mp4upload_extractor.dart +++ b/lib/services/anime_extractors/mp4upload_extractor.dart @@ -8,7 +8,8 @@ import 'package:mangayomi/utils/xpath_selector.dart'; class Mp4uploadExtractor { static final RegExp qualityRegex = RegExp(r'\WHEIGHT=(\d+)'); static const String referer = "https://mp4upload.com/"; - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); Future> videosFromUrl(String url, Map headers, {String prefix = '', String suffix = ''}) async { final newHeaders = Map.from(headers) diff --git a/lib/services/anime_extractors/mystream_extractor.dart b/lib/services/anime_extractors/mystream_extractor.dart index 423ede99..b93017fe 100644 --- a/lib/services/anime_extractors/mystream_extractor.dart +++ b/lib/services/anime_extractors/mystream_extractor.dart @@ -9,7 +9,8 @@ class MyStreamExtractor { String url, Map headers) async { final host = url.substringBefore("/watch"); - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); try { final response = await client.get(Uri.parse(url), headers: headers); diff --git a/lib/services/anime_extractors/mytv_extractor.dart b/lib/services/anime_extractors/mytv_extractor.dart index ad923cdf..2fda770c 100644 --- a/lib/services/anime_extractors/mytv_extractor.dart +++ b/lib/services/anime_extractors/mytv_extractor.dart @@ -5,7 +5,8 @@ import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; class MytvExtractor { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); Future> videosFromUrl(String url) async { try { diff --git a/lib/services/anime_extractors/okru_extractor.dart b/lib/services/anime_extractors/okru_extractor.dart index 0f4908dd..9d884b04 100644 --- a/lib/services/anime_extractors/okru_extractor.dart +++ b/lib/services/anime_extractors/okru_extractor.dart @@ -6,7 +6,8 @@ import 'package:mangayomi/utils/extensions/dom_extensions.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; class OkruExtractor { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); Future> videosFromUrl(String url, {String prefix = "", bool fixQualities = true}) async { diff --git a/lib/services/anime_extractors/sendvid_extractor.dart b/lib/services/anime_extractors/sendvid_extractor.dart index 332093a1..5a20b9db 100644 --- a/lib/services/anime_extractors/sendvid_extractor.dart +++ b/lib/services/anime_extractors/sendvid_extractor.dart @@ -5,7 +5,8 @@ import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; class SendvidExtractor { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); final Map headers; SendvidExtractor(this.headers); diff --git a/lib/services/anime_extractors/sibnet_extractor.dart b/lib/services/anime_extractors/sibnet_extractor.dart index 85147010..230a7c01 100644 --- a/lib/services/anime_extractors/sibnet_extractor.dart +++ b/lib/services/anime_extractors/sibnet_extractor.dart @@ -4,7 +4,8 @@ import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; class SibnetExtractor { - final InterceptedClient client = MClient.init(); + final InterceptedClient client = + MClient.init(reqcopyWith: {'useDartHttpClient': true}); Future> videosFromUrl(String url, {String prefix = ""}) async { List