mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 23:22:07 +00:00
parent
18d6079420
commit
5a18d5f0f0
6 changed files with 127 additions and 82 deletions
|
|
@ -58,21 +58,20 @@ void main(List<String> args) async {
|
|||
);
|
||||
}
|
||||
}
|
||||
isar = await StorageProvider().initDB(null, inspector: kDebugMode);
|
||||
if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {
|
||||
await Hive.initFlutter("databases");
|
||||
} else {
|
||||
await Hive.initFlutter(p.join("Mangayomi", "databases"));
|
||||
}
|
||||
Hive.registerAdapter(TrackSearchAdapter());
|
||||
|
||||
final storage = StorageProvider();
|
||||
await storage.requestPermission();
|
||||
isar = await storage.initDB(null, inspector: kDebugMode);
|
||||
runApp(const ProviderScope(child: MyApp()));
|
||||
unawaited(_postLaunchInit()); // Defer non-essential async operations
|
||||
unawaited(_postLaunchInit(storage)); // Defer non-essential async operations
|
||||
}
|
||||
|
||||
Future<void> _postLaunchInit() async {
|
||||
await StorageProvider().requestPermission();
|
||||
await StorageProvider().deleteBtDirectory();
|
||||
Future<void> _postLaunchInit(StorageProvider storage) async {
|
||||
final hivePath = (Platform.isIOS || Platform.isMacOS || Platform.isAndroid)
|
||||
? "databases"
|
||||
: p.join("Mangayomi", "databases");
|
||||
await Hive.initFlutter(hivePath);
|
||||
Hive.registerAdapter(TrackSearchAdapter());
|
||||
await storage.deleteBtDirectory();
|
||||
}
|
||||
|
||||
class MyApp extends ConsumerStatefulWidget {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ Future<void> downloadChapter(
|
|||
chapter,
|
||||
mangaMainDirectory: mangaMainDirectory,
|
||||
))!;
|
||||
await Directory(chapterDirectory.path).create(recursive: true);
|
||||
await storageProvider.createDirectorySafely(chapterDirectory.path);
|
||||
Map<String, String> videoHeader = {};
|
||||
Map<String, String> htmlHeader = {
|
||||
"Priority": "u=0, i",
|
||||
|
|
@ -258,6 +258,7 @@ Future<void> downloadChapter(
|
|||
!mp4FileExist && itemType == ItemType.anime ||
|
||||
!htmlFileExist && itemType == ItemType.novel) {
|
||||
final mainDirectory = (await storageProvider.getDirectory())!;
|
||||
storageProvider.createDirectorySafely(mainDirectory.path);
|
||||
for (var index = 0; index < pageUrls.length; index++) {
|
||||
if (Platform.isAndroid) {
|
||||
if (!(await File(p.join(mainDirectory.path, ".nomedia")).exists())) {
|
||||
|
|
|
|||
|
|
@ -73,42 +73,35 @@ class AutoBackupLocationState extends _$AutoBackupLocationState {
|
|||
@riverpod
|
||||
Future<void> checkAndBackup(Ref ref) async {
|
||||
final settings = isar.settings.getSync(227);
|
||||
if (settings!.backupFrequency != null) {
|
||||
final backupFrequency = _duration(settings.backupFrequency);
|
||||
if (backupFrequency != null) {
|
||||
if (settings.startDatebackup != null) {
|
||||
final startDatebackup = DateTime.fromMillisecondsSinceEpoch(
|
||||
settings.startDatebackup!,
|
||||
);
|
||||
if (DateTime.now().isAfter(startDatebackup)) {
|
||||
_setBackupFrequency(settings.backupFrequency!);
|
||||
final storageProvider = StorageProvider();
|
||||
await storageProvider.requestPermission();
|
||||
final defaulteDirectory = await storageProvider.getDefaultDirectory();
|
||||
final backupLocation = ref.watch(autoBackupLocationStateProvider).$2;
|
||||
Directory? backupDirectory;
|
||||
backupDirectory = Directory(
|
||||
backupLocation.isEmpty
|
||||
? p.join(defaulteDirectory!.path, "backup")
|
||||
: backupLocation,
|
||||
);
|
||||
if (Platform.isIOS) {
|
||||
backupDirectory = await (storageProvider.getIosBackupDirectory());
|
||||
}
|
||||
if (!(await backupDirectory!.exists())) {
|
||||
backupDirectory.create();
|
||||
}
|
||||
ref.watch(
|
||||
doBackUpProvider(
|
||||
list: ref.watch(backupFrequencyOptionsStateProvider),
|
||||
path: backupDirectory.path,
|
||||
context: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
final backupFrequency = _duration(settings!.backupFrequency);
|
||||
if (backupFrequency == null || settings.startDatebackup == null) return;
|
||||
|
||||
final startDatebackup = DateTime.fromMillisecondsSinceEpoch(
|
||||
settings.startDatebackup!,
|
||||
);
|
||||
if (!DateTime.now().isAfter(startDatebackup)) return;
|
||||
_setBackupFrequency(settings.backupFrequency!);
|
||||
final storageProvider = StorageProvider();
|
||||
final backupLocation = ref.read(autoBackupLocationStateProvider).$2;
|
||||
Directory? backupDirectory;
|
||||
if (Platform.isIOS) {
|
||||
backupDirectory = await (storageProvider.getIosBackupDirectory());
|
||||
} else {
|
||||
final defaultDirectory = await storageProvider.getDefaultDirectory();
|
||||
backupDirectory = Directory(
|
||||
backupLocation.isEmpty
|
||||
? p.join(defaultDirectory!.path, "backup")
|
||||
: backupLocation,
|
||||
);
|
||||
}
|
||||
await storageProvider.createDirectorySafely(backupDirectory!.path);
|
||||
ref.read(
|
||||
doBackUpProvider(
|
||||
list: ref.read(backupFrequencyOptionsStateProvider),
|
||||
path: backupDirectory.path,
|
||||
context: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Duration? _duration(int? backupFrequency) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:extended_image_library/src/platform.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:http_client_helper/http_client_helper.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
|
@ -194,6 +195,7 @@ class CustomExtendedNetworkImageProvider
|
|||
),
|
||||
);
|
||||
Uint8List? data;
|
||||
await StorageProvider().createDirectorySafely(cacheImagesDirectory.path);
|
||||
final File cacheFile = File(join(cacheImagesDirectory.path, md5Key));
|
||||
// exist, try to find cache image file
|
||||
if (cacheFile.existsSync()) {
|
||||
|
|
@ -208,8 +210,6 @@ class CustomExtendedNetworkImageProvider
|
|||
} else {
|
||||
data = await cacheFile.readAsBytes();
|
||||
}
|
||||
} else if (!cacheImagesDirectory.existsSync()) {
|
||||
await cacheImagesDirectory.create(recursive: true);
|
||||
}
|
||||
// load from network
|
||||
if (data == null) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// ignore_for_file: depend_on_referenced_packages
|
||||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/eval/model/source_preference.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
|
|
@ -21,13 +22,15 @@ import 'package:permission_handler/permission_handler.dart';
|
|||
import 'package:path/path.dart' as path;
|
||||
|
||||
class StorageProvider {
|
||||
static bool _hasPermission = false;
|
||||
static final StorageProvider _instance = StorageProvider._internal();
|
||||
StorageProvider._internal();
|
||||
factory StorageProvider() => _instance;
|
||||
|
||||
Future<bool> requestPermission() async {
|
||||
if (_hasPermission || !Platform.isAndroid) return true;
|
||||
if (!Platform.isAndroid) return true;
|
||||
Permission permission = Permission.manageExternalStorage;
|
||||
if (await permission.isGranted) return true;
|
||||
if (await permission.request().isGranted) {
|
||||
_hasPermission = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -46,9 +49,13 @@ class StorageProvider {
|
|||
Future<Directory?> getDefaultDirectory() async {
|
||||
Directory? directory;
|
||||
if (Platform.isAndroid) {
|
||||
directory = Directory("/storage/emulated/0/Mangayomi/");
|
||||
final dir = await getExternalStorageDirectory();
|
||||
directory = Directory(path.join(dir!.path, 'Mangayomi'));
|
||||
} else {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
// The documents dir in iOS and macOS is already named "Mangayomi".
|
||||
// Appending "Mangayomi" to the documents dir would create
|
||||
// unnecessarily nested Mangayomi/Mangayomi/ folder.
|
||||
if (Platform.isIOS || Platform.isMacOS) return dir;
|
||||
directory = Directory(path.join(dir.path, 'Mangayomi'));
|
||||
}
|
||||
|
|
@ -56,8 +63,8 @@ class StorageProvider {
|
|||
}
|
||||
|
||||
Future<Directory?> getBtDirectory() async {
|
||||
String dbDir = await _btDirectoryPath();
|
||||
await Directory(dbDir).create(recursive: true);
|
||||
final dbDir = await _btDirectoryPath();
|
||||
await createDirectorySafely(dbDir);
|
||||
return Directory(dbDir);
|
||||
}
|
||||
|
||||
|
|
@ -67,8 +74,8 @@ class StorageProvider {
|
|||
}
|
||||
|
||||
Future<Directory?> getTmpDirectory() async {
|
||||
String tmpPath = await _tempDirectoryPath();
|
||||
await Directory(tmpPath).create(recursive: true);
|
||||
final tmpPath = await _tempDirectoryPath();
|
||||
await createDirectorySafely(tmpPath);
|
||||
return Directory(tmpPath);
|
||||
}
|
||||
|
||||
|
|
@ -80,20 +87,30 @@ class StorageProvider {
|
|||
Future<Directory?> getIosBackupDirectory() async {
|
||||
final defaultDirectory = await getDefaultDirectory();
|
||||
String dbDir = path.join(defaultDirectory!.path, 'backup');
|
||||
await Directory(dbDir).create(recursive: true);
|
||||
await createDirectorySafely(dbDir);
|
||||
return Directory(dbDir);
|
||||
}
|
||||
|
||||
Future<Directory?> getDirectory() async {
|
||||
Directory? directory;
|
||||
String dPath = isar.settings.getSync(227)!.downloadLocation ?? "";
|
||||
String dPath = "";
|
||||
try {
|
||||
final setting = isar.settings.getSync(227);
|
||||
dPath = setting?.downloadLocation ?? "";
|
||||
} catch (e) {
|
||||
debugPrint("Could not get downloadLocation from Isar settings: $e");
|
||||
}
|
||||
if (Platform.isAndroid) {
|
||||
final dir = await getExternalStorageDirectory();
|
||||
directory = Directory(
|
||||
dPath.isEmpty ? "/storage/emulated/0/Mangayomi/" : "$dPath/",
|
||||
dPath.isEmpty ? path.join(dir!.path, 'Mangayomi') : "$dPath/",
|
||||
);
|
||||
} else {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final p = dPath.isEmpty ? dir.path : dPath;
|
||||
// The documents dir in iOS and macOS is already named "Mangayomi".
|
||||
// Appending "Mangayomi" to the documents dir would create
|
||||
// unnecessarily nested Mangayomi/Mangayomi/ folder.
|
||||
if (Platform.isIOS || Platform.isMacOS) return Directory(p);
|
||||
directory = Directory(path.join(p, 'Mangayomi'));
|
||||
}
|
||||
|
|
@ -138,28 +155,48 @@ class StorageProvider {
|
|||
|
||||
Future<Directory?> getDatabaseDirectory() async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
String dbDir;
|
||||
if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {
|
||||
String dbDir = path.join(dir.path, 'databases');
|
||||
await Directory(dbDir).create(recursive: true);
|
||||
return Directory(dbDir);
|
||||
// The documents dir in iOS and macOS is already named "Mangayomi".
|
||||
// Appending "Mangayomi" to the documents dir would create
|
||||
// unnecessarily nested Mangayomi/Mangayomi/ folder.
|
||||
dbDir = path.join(dir.path, 'databases');
|
||||
} else {
|
||||
String dbDir = path.join(dir.path, 'Mangayomi', 'databases');
|
||||
await Directory(dbDir).create(recursive: true);
|
||||
return Directory(dbDir);
|
||||
dbDir = path.join(dir.path, 'Mangayomi', 'databases');
|
||||
}
|
||||
await createDirectorySafely(dbDir);
|
||||
return Directory(dbDir);
|
||||
}
|
||||
|
||||
Future<Directory?> getGalleryDirectory() async {
|
||||
String gPath = (await getDirectory())!.path;
|
||||
String gPath;
|
||||
if (Platform.isAndroid) {
|
||||
gPath = "/storage/emulated/0/Pictures/Mangayomi/";
|
||||
final dir = await getExternalStorageDirectory();
|
||||
gPath = path.join(dir!.path, 'Mangayomi', 'Pictures');
|
||||
} else {
|
||||
gPath = path.join(gPath, 'Pictures');
|
||||
gPath = path.join((await getDirectory())!.path, 'Pictures');
|
||||
}
|
||||
await Directory(gPath).create(recursive: true);
|
||||
await createDirectorySafely(gPath);
|
||||
return Directory(gPath);
|
||||
}
|
||||
|
||||
Future<void> createDirectorySafely(String dirPath) async {
|
||||
final dir = Directory(dirPath);
|
||||
try {
|
||||
await dir.create(recursive: true);
|
||||
} catch (_) {
|
||||
if (await requestPermission()) {
|
||||
try {
|
||||
await dir.create(recursive: true);
|
||||
} catch (e) {
|
||||
debugPrint('Initial directory creation failed for $dirPath: $e');
|
||||
}
|
||||
} else {
|
||||
debugPrint('Permission denied. Cannot create: $dirPath');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<Isar> initDB(String? path, {bool inspector = false}) async {
|
||||
Directory? dir;
|
||||
if (path == null) {
|
||||
|
|
@ -189,10 +226,27 @@ class StorageProvider {
|
|||
name: "mangayomiDb",
|
||||
inspector: inspector,
|
||||
);
|
||||
|
||||
final settings = await isar.settings.filter().idEqualTo(227).findFirst();
|
||||
if (settings == null) {
|
||||
await isar.writeTxn(() async => isar.settings.put(Settings()));
|
||||
try {
|
||||
final settings = await isar.settings.filter().idEqualTo(227).findFirst();
|
||||
if (settings == null) {
|
||||
await isar.writeTxn(() async => isar.settings.put(Settings()));
|
||||
}
|
||||
} catch (_) {
|
||||
if (await requestPermission()) {
|
||||
try {
|
||||
final settings = await isar.settings
|
||||
.filter()
|
||||
.idEqualTo(227)
|
||||
.findFirst();
|
||||
if (settings == null) {
|
||||
await isar.writeTxn(() async => isar.settings.put(Settings()));
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Failed after retry with permission: $e");
|
||||
}
|
||||
} else {
|
||||
debugPrint("Permission denied during Database init fallback.");
|
||||
}
|
||||
}
|
||||
|
||||
return isar;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:http/http.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:mangayomi/services/http/rhttp/src/model/settings.dart';
|
||||
import 'package:mangayomi/services/download_manager/m3u8/models/download.dart';
|
||||
|
|
@ -122,21 +123,18 @@ class M3u8Downloader {
|
|||
}
|
||||
|
||||
Future<void> download(void Function(DownloadProgress) onProgress) async {
|
||||
final tempDir = Directory(path.join(downloadDir, 'temp'));
|
||||
final tempDir = path.join(downloadDir, 'temp');
|
||||
await StorageProvider().createDirectorySafely(tempDir);
|
||||
|
||||
try {
|
||||
await tempDir.create(recursive: true);
|
||||
final (tsList, key, iv, mediaSequence) = await _getTsList();
|
||||
|
||||
final tsListToDownload = await _filterExistingSegments(
|
||||
tsList,
|
||||
tempDir.path,
|
||||
);
|
||||
final tsListToDownload = await _filterExistingSegments(tsList, tempDir);
|
||||
_log('Downloading ${tsListToDownload.length} segments...');
|
||||
|
||||
await _downloadSegmentsWithProgress(
|
||||
tsListToDownload,
|
||||
tempDir.path,
|
||||
tempDir,
|
||||
key,
|
||||
iv,
|
||||
mediaSequence,
|
||||
|
|
|
|||
Loading…
Reference in a new issue