// ignore_for_file: depend_on_referenced_packages import 'dart:io'; import 'package:isar/isar.dart'; import 'package:mangayomi/eval/model/source_preference.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/changed.dart'; import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/custom_button.dart'; import 'package:mangayomi/models/download.dart'; import 'package:mangayomi/models/update.dart'; import 'package:mangayomi/models/history.dart'; import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/sync_preference.dart'; import 'package:mangayomi/models/track.dart'; import 'package:mangayomi/models/track_preference.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:path/path.dart' as path; class StorageProvider { static bool _hasPermission = false; Future requestPermission() async { if (_hasPermission) return true; if (Platform.isAndroid) { Permission permission = Permission.manageExternalStorage; if (await permission.isGranted) { return true; } else { final result = await permission.request(); if (result == PermissionStatus.granted) { _hasPermission = true; return true; } return false; } } return true; } Future deleteBtDirectory() async { final d = await getBtDirectory(); await Directory(d!.path).delete(recursive: true); } Future deleteTmpDirectory() async { final d = await getTmpDirectory(); await Directory(d!.path).delete(recursive: true); } Future getDefaultDirectory() async { Directory? directory; if (Platform.isAndroid) { directory = Directory("/storage/emulated/0/Mangayomi/"); } else { final dir = await getApplicationDocumentsDirectory(); directory = Directory(path.join(dir.path, 'Mangayomi')); } return directory; } Future getMpvDirectory() async { final defaultDirectory = await getDefaultDirectory(); String dbDir = path.join(defaultDirectory!.path, 'mpv'); await Directory(dbDir).create(recursive: true); return Directory(dbDir); } Future getBtDirectory() async { final gefaultDirectory = await getDefaultDirectory(); String dbDir = path.join(gefaultDirectory!.path, 'torrents'); await Directory(dbDir).create(recursive: true); return Directory(dbDir); } Future getTmpDirectory() async { final gefaultDirectory = await getDirectory(); String dbDir = path.join(gefaultDirectory!.path, 'tmp'); await Directory(dbDir).create(recursive: true); return Directory(dbDir); } Future getIosBackupDirectory() async { final gefaultDirectory = await getDefaultDirectory(); String dbDir = path.join(gefaultDirectory!.path, 'backup'); await Directory(dbDir).create(recursive: true); return Directory(dbDir); } Future getDirectory() async { Directory? directory; String dPath = isar.settings.getSync(227)!.downloadLocation ?? ""; if (Platform.isAndroid) { directory = Directory( dPath.isEmpty ? "/storage/emulated/0/Mangayomi/" : "$dPath/", ); } else { final dir = await getApplicationDocumentsDirectory(); final p = dPath.isEmpty ? dir.path : dPath; directory = Directory(path.join(p, 'Mangayomi')); } return directory; } Future getMangaMainDirectory(Chapter chapter) async { final manga = chapter.manga.value!; final itemType = chapter.manga.value!.itemType; final itemTypePath = itemType == ItemType.manga ? "Manga" : itemType == ItemType.anime ? "Anime" : "Novel"; final dir = await getDirectory(); return Directory( path.join( dir!.path, 'downloads', itemTypePath, '${manga.source} (${manga.lang!.toUpperCase()})', manga.name!.replaceForbiddenCharacters('_'), ), ); } Future getMangaChapterDirectory( Chapter chapter, { Directory? mangaMainDirectory, }) async { final basedir = mangaMainDirectory ?? await getMangaMainDirectory(chapter); String scanlator = chapter.scanlator?.isNotEmpty ?? false ? "${chapter.scanlator!.replaceForbiddenCharacters('_')}_" : ""; return Directory( path.join( basedir!.path, scanlator + chapter.name!.replaceForbiddenCharacters('_').trim(), ), ); } Future getDatabaseDirectory() async { final dir = await getApplicationDocumentsDirectory(); if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) { return dir; } else { String dbDir = path.join(dir.path, 'Mangayomi', 'databases'); await Directory(dbDir).create(recursive: true); return Directory(dbDir); } } Future getGalleryDirectory() async { String gPath = (await getDirectory())!.path; if (Platform.isAndroid) { gPath = "/storage/emulated/0/Pictures/Mangayomi/"; } else { gPath = path.join(gPath, 'Pictures'); } await Directory(gPath).create(recursive: true); return Directory(gPath); } Future initDB(String? path, {bool? inspector = false}) async { Directory? dir; if (path == null) { dir = await getDatabaseDirectory(); } else { dir = Directory(path); } final isar = await Isar.open( [ MangaSchema, ChangedPartSchema, ChapterSchema, CategorySchema, CustomButtonSchema, UpdateSchema, HistorySchema, DownloadSchema, SourceSchema, SettingsSchema, TrackPreferenceSchema, TrackSchema, SyncPreferenceSchema, SourcePreferenceSchema, SourcePreferenceStringValueSchema, ], directory: dir!.path, name: "mangayomiDb", inspector: inspector!, ); final settings = await isar.settings.filter().idEqualTo(227).findFirst(); if (settings == null) { await isar.writeTxn(() async { isar.settings.put(Settings()); }); } final prefs = await isar.trackPreferences .filter() .syncIdIsNotNull() .findAll(); await isar.writeTxn(() async { for (final pref in prefs) { await isar.trackPreferences.put(pref..refreshing = true); } }); final customButton = await isar.customButtons .filter() .idIsNotNull() .findFirst(); if (customButton == null) { await isar.writeTxn(() async { await isar.customButtons.put( CustomButton( title: "+85 s", codePress: """local intro_length = mp.get_property_native("user-data/current-anime/intro-length") aniyomi.right_seek_by(intro_length)""", codeLongPress: """aniyomi.int_picker("Change intro length", "%ds", 0, 255, 1, "user-data/current-anime/intro-length")""", codeStartup: """function update_button(_, length) if length ~= nil then if length == 0 then aniyomi.hide_button() return else aniyomi.show_button() end aniyomi.set_button_title("+" .. length .. " s") end end if \$isPrimary then mp.observe_property("user-data/current-anime/intro-length", "number", update_button) end""", isFavourite: true, pos: 0, updatedAt: DateTime.now().millisecondsSinceEpoch, ), ); }); } return isar; } }