mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-03-11 17:25:32 +00:00
refactor: streamline archive import process and enhance cover image handling
This commit is contained in:
parent
75d5013179
commit
fd615bd44b
9 changed files with 432 additions and 274 deletions
|
|
@ -23,6 +23,7 @@ import 'package:mangayomi/modules/anime/providers/anime_player_controller_provid
|
|||
import 'package:mangayomi/modules/anime/widgets/aniskip_countdown_btn.dart';
|
||||
import 'package:mangayomi/modules/anime/widgets/desktop.dart';
|
||||
import 'package:mangayomi/modules/anime/widgets/play_or_pause_button.dart';
|
||||
import 'package:mangayomi/modules/library/providers/local_archive.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/widgets/btn_chapter_list_dialog.dart';
|
||||
import 'package:mangayomi/modules/anime/widgets/mobile.dart';
|
||||
import 'package:mangayomi/modules/anime/widgets/subtitle_view.dart';
|
||||
|
|
@ -2223,7 +2224,8 @@ mp.register_script_message('call_button_${button.id}_long', button${button.id}lo
|
|||
..updatedAt = DateTime.now()
|
||||
.millisecondsSinceEpoch
|
||||
..customCoverImage =
|
||||
imageBytes,
|
||||
imageBytes
|
||||
?.getCoverImage,
|
||||
);
|
||||
});
|
||||
if (context.mounted) {
|
||||
|
|
|
|||
|
|
@ -1131,6 +1131,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
// Downloaded Chapters
|
||||
if (downloadedChapsList.isNotEmpty) {
|
||||
for (var manga in mangasList) {
|
||||
if (!(manga.isLocalArchive ?? false)) {
|
||||
String mangaDirectory = "";
|
||||
if (manga.isLocalArchive ?? false) {
|
||||
mangaDirectory = _deleteImport(
|
||||
|
|
@ -1159,6 +1160,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ref.read(mangasListStateProvider.notifier).clear();
|
||||
ref
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io'; // For I/O-operations
|
||||
import 'dart:typed_data';
|
||||
import 'package:epubx/epubx.dart';
|
||||
import 'package:isar_community/isar.dart'; // Isar database package for local storage
|
||||
import 'package:mangayomi/main.dart'; // Exposes the global `isar` instance
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/library/providers/local_archive.dart';
|
||||
import 'package:mangayomi/utils/extensions/others.dart';
|
||||
import 'package:path/path.dart' as p; // For manipulating file system paths
|
||||
import 'package:bot_toast/bot_toast.dart'; // For Exceptions
|
||||
|
|
@ -182,7 +184,7 @@ Future<void> _scanDirectory(Ref ref, Directory? dir) async {
|
|||
final bytes = await File(imageFiles.first.path).readAsBytes();
|
||||
final byteList = bytes.toList();
|
||||
if (manga.customCoverImage != byteList) {
|
||||
manga.customCoverImage = byteList;
|
||||
manga.customCoverImage = Uint8List.fromList(byteList).getCoverImage;
|
||||
manga.lastUpdate = dateNow;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -299,7 +301,9 @@ Future<void> _scanDirectory(Ref ref, Directory? dir) async {
|
|||
book.Content!.Images!.containsKey("media/file0.png")
|
||||
? book.Content!.Images!["media/file0.png"]!.Content
|
||||
: book.Content!.Images!.values.first.Content;
|
||||
manga.customCoverImage = coverImage;
|
||||
manga.customCoverImage = coverImage == null
|
||||
? null
|
||||
: Uint8List.fromList(coverImage).getCoverImage;
|
||||
saveManga++;
|
||||
}
|
||||
for (var chapter in book.Chapters ?? []) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ Future importArchivesFromFile(
|
|||
required ItemType itemType,
|
||||
required bool init,
|
||||
}) async {
|
||||
final keepAlile = ref.keepAlive();
|
||||
try {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
allowMultiple: true,
|
||||
type: FileType.custom,
|
||||
|
|
@ -53,14 +55,17 @@ Future importArchivesFromFile(
|
|||
for (var file in result.files.reversed.toList()) {
|
||||
(String, LocalExtensionType, Uint8List, String)? data =
|
||||
itemType == ItemType.manga
|
||||
? await ref.watch(getArchivesDataFromFileProvider(file.path!).future)
|
||||
? await ref.watch(
|
||||
getArchivesDataFromFileProvider(file.path!).future,
|
||||
)
|
||||
: null;
|
||||
String name = _getName(file.path!);
|
||||
|
||||
if (init) {
|
||||
manga.customCoverImage = itemType == ItemType.manga ? data!.$3 : null;
|
||||
if (itemType == ItemType.manga) {
|
||||
manga.customCoverImage = data!.$3.getCoverImage;
|
||||
}
|
||||
}
|
||||
|
||||
await isar.writeTxn(() async {
|
||||
final mangaId = await isar.mangas.put(manga);
|
||||
final List<Chapter> chapters = [];
|
||||
|
|
@ -72,7 +77,12 @@ Future importArchivesFromFile(
|
|||
book.Content!.Images!.containsKey("media/file0.png")
|
||||
? book.Content!.Images!["media/file0.png"]!.Content
|
||||
: book.Content!.Images!.values.first.Content;
|
||||
await isar.mangas.put(manga..customCoverImage = coverImage);
|
||||
await isar.mangas.put(
|
||||
manga
|
||||
..customCoverImage = coverImage == null
|
||||
? null
|
||||
: Uint8List.fromList(coverImage).getCoverImage,
|
||||
);
|
||||
}
|
||||
for (var chapter in book.Chapters ?? []) {
|
||||
chapters.add(
|
||||
|
|
@ -103,7 +113,12 @@ Future importArchivesFromFile(
|
|||
});
|
||||
}
|
||||
}
|
||||
keepAlile.close();
|
||||
return "";
|
||||
} catch (e) {
|
||||
keepAlile.close();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
String _getName(String path) {
|
||||
|
|
@ -117,3 +132,13 @@ String _getName(String path) {
|
|||
'',
|
||||
);
|
||||
}
|
||||
|
||||
extension Uint8ListExtensions on Uint8List {
|
||||
Uint8List? get getCoverImage {
|
||||
final length = lengthInBytes / (1024 * 1024);
|
||||
if (length < 5) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ final class ImportArchivesFromFileProvider
|
|||
}
|
||||
|
||||
String _$importArchivesFromFileHash() =>
|
||||
r'784b9d45958695faffdf04ee7c105c9b486122de';
|
||||
r'a3fbf9d9ba7eacfa52366bfb10ba9f5f9117585b';
|
||||
|
||||
final class ImportArchivesFromFileFamily extends $Family
|
||||
with
|
||||
|
|
|
|||
|
|
@ -6,10 +6,20 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
import 'package:path/path.dart' as p;
|
||||
part 'archive_reader_providers.g.dart';
|
||||
|
||||
// Constants for supported file types
|
||||
const List<String> _kImageExtensions = [
|
||||
'.png',
|
||||
'.jpg',
|
||||
'.jpeg',
|
||||
'.gif',
|
||||
'.webp',
|
||||
];
|
||||
const List<String> _kArchiveExtensions = ['.cbz', '.zip', '.cbt', '.tar'];
|
||||
|
||||
@riverpod
|
||||
Future<List<(String, LocalExtensionType, Uint8List, String)>>
|
||||
getArchivesDataFromDirectory(Ref ref, String path) async {
|
||||
return compute(_extractOnly, path);
|
||||
return compute(_extractArchiveMetadataFromDirectory, path);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
|
@ -17,7 +27,7 @@ Future<List<LocalArchive>> getArchiveDataFromDirectory(
|
|||
Ref ref,
|
||||
String path,
|
||||
) async {
|
||||
return compute(_extract, path);
|
||||
return compute(_extractArchivesFromDirectory, path);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
|
@ -25,7 +35,7 @@ Future<(String, LocalExtensionType, Uint8List, String)> getArchivesDataFromFile(
|
|||
Ref ref,
|
||||
String path,
|
||||
) async {
|
||||
return compute(_extractArchiveOnly, path);
|
||||
return compute(_extractArchiveMetadata, path);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
|
@ -33,200 +43,315 @@ Future<LocalArchive> getArchiveDataFromFile(Ref ref, String path) async {
|
|||
return compute(_extractArchive, path);
|
||||
}
|
||||
|
||||
Future<List<LocalArchive>> _extract(String data) async {
|
||||
return await _searchForArchive(Directory(data));
|
||||
}
|
||||
|
||||
Future<List<(String, LocalExtensionType, Uint8List, String)>> _extractOnly(
|
||||
String data,
|
||||
/// Extract full archive data from all archives in a directory (recursive)
|
||||
Future<List<LocalArchive>> _extractArchivesFromDirectory(
|
||||
String directoryPath,
|
||||
) async {
|
||||
return await _searchForArchiveOnly(Directory(data));
|
||||
}
|
||||
final archives = <LocalArchive>[];
|
||||
|
||||
List<LocalArchive> _list = [];
|
||||
List<(String, LocalExtensionType, Uint8List, String)> _listOnly = [];
|
||||
Future<List<LocalArchive>> _searchForArchive(Directory dir) async {
|
||||
List<FileSystemEntity> entities = dir.listSync();
|
||||
for (FileSystemEntity entity in entities) {
|
||||
if (entity is Directory) {
|
||||
_searchForArchive(entity);
|
||||
} else if (entity is File) {
|
||||
String path = entity.path;
|
||||
if (_isArchiveFile(path)) {
|
||||
final dd = await compute(_extractArchive, path);
|
||||
_list.add(dd);
|
||||
try {
|
||||
final dir = Directory(directoryPath);
|
||||
if (!dir.existsSync()) {
|
||||
return archives;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _list;
|
||||
}
|
||||
|
||||
Future<List<(String, LocalExtensionType, Uint8List, String)>>
|
||||
_searchForArchiveOnly(Directory dir) async {
|
||||
List<FileSystemEntity> entities = dir.listSync();
|
||||
for (FileSystemEntity entity in entities) {
|
||||
if (entity is Directory) {
|
||||
_searchForArchive(entity);
|
||||
} else if (entity is File) {
|
||||
String path = entity.path;
|
||||
if (_isArchiveFile(path)) {
|
||||
final dd = await compute(_extractArchiveOnly, path);
|
||||
_listOnly.add(dd);
|
||||
await _scanDirectoryRecursive(
|
||||
dir,
|
||||
onArchiveFound: (path) async {
|
||||
try {
|
||||
final archive = await _extractArchive(path);
|
||||
archives.add(archive);
|
||||
} catch (e) {
|
||||
debugPrint('Error extracting archive at $path: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
return _listOnly;
|
||||
}
|
||||
|
||||
bool _isImageFile(String path) {
|
||||
List<String> imageExtensions = ['.png', '.jpg', '.jpeg'];
|
||||
String extension = path.toLowerCase();
|
||||
for (String imageExtension in imageExtensions) {
|
||||
if (extension.endsWith(imageExtension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _isArchiveFile(String path) {
|
||||
List<String> archiveExtensions = ['.cbz', '.zip', 'cbt', 'tar'];
|
||||
String extension = path.toLowerCase();
|
||||
for (String archiveExtension in archiveExtensions) {
|
||||
if (extension.endsWith(archiveExtension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalArchive _extractArchive(String path) {
|
||||
// Folder of images?
|
||||
if (Directory(path).existsSync()) {
|
||||
final dir = Directory(path);
|
||||
final pages =
|
||||
dir.listSync().whereType<File>().where((f) => _isImageFile(f.path)).map(
|
||||
(f) {
|
||||
return LocalImage()
|
||||
..image = f.readAsBytesSync()
|
||||
..name = p.basename(f.path);
|
||||
},
|
||||
).toList()..sort((a, b) => a.name!.compareTo(b.name!));
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Error scanning directory $directoryPath: $e');
|
||||
}
|
||||
|
||||
final localArchive = LocalArchive()
|
||||
return archives;
|
||||
}
|
||||
|
||||
/// Extract only metadata (cover) from all archives in a directory (recursive)
|
||||
Future<List<(String, LocalExtensionType, Uint8List, String)>>
|
||||
_extractArchiveMetadataFromDirectory(String directoryPath) async {
|
||||
final metadata = <(String, LocalExtensionType, Uint8List, String)>[];
|
||||
|
||||
try {
|
||||
final dir = Directory(directoryPath);
|
||||
if (!dir.existsSync()) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
await _scanDirectoryRecursive(
|
||||
dir,
|
||||
onArchiveFound: (path) async {
|
||||
try {
|
||||
final data = await _extractArchiveMetadata(path);
|
||||
metadata.add(data);
|
||||
} catch (e) {
|
||||
debugPrint('Error extracting metadata at $path: $e');
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Error scanning directory $directoryPath: $e');
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/// Recursively scan directory for archive files
|
||||
Future<void> _scanDirectoryRecursive(
|
||||
Directory dir, {
|
||||
required Future<void> Function(String path) onArchiveFound,
|
||||
}) async {
|
||||
try {
|
||||
final entities = dir.listSync();
|
||||
|
||||
for (final entity in entities) {
|
||||
if (entity is Directory) {
|
||||
// Recursive scan
|
||||
await _scanDirectoryRecursive(entity, onArchiveFound: onArchiveFound);
|
||||
} else if (entity is File) {
|
||||
if (_isArchiveFile(entity.path)) {
|
||||
await onArchiveFound(entity.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error scanning directory ${dir.path}: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a file is an image based on extension
|
||||
bool _isImageFile(String path) {
|
||||
final extension = p.extension(path).toLowerCase();
|
||||
return _kImageExtensions.contains(extension);
|
||||
}
|
||||
|
||||
/// Check if a file is a supported archive based on extension
|
||||
bool _isArchiveFile(String path) {
|
||||
final extension = p.extension(path).toLowerCase();
|
||||
return _kArchiveExtensions.any((ext) => extension.endsWith(ext));
|
||||
}
|
||||
|
||||
/// Extract full archive with all images
|
||||
Future<LocalArchive> _extractArchive(String path) async {
|
||||
try {
|
||||
// Handle directory of images
|
||||
if (Directory(path).existsSync()) {
|
||||
return await _extractFromImageFolder(path);
|
||||
}
|
||||
|
||||
// Handle archive file
|
||||
return _extractFromArchiveFile(path);
|
||||
} catch (e) {
|
||||
debugPrint('Error extracting archive from $path: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract images from a folder
|
||||
Future<LocalArchive> _extractFromImageFolder(String path) async {
|
||||
final dir = Directory(path);
|
||||
final imageFiles =
|
||||
await dir
|
||||
.list()
|
||||
.where((entity) => entity is File && _isImageFile(entity.path))
|
||||
.cast<File>()
|
||||
.toList()
|
||||
..sort((a, b) => a.path.compareTo(b.path));
|
||||
|
||||
if (imageFiles.isEmpty) {
|
||||
throw Exception('No images found in folder: $path');
|
||||
}
|
||||
|
||||
final images = imageFiles.map((file) {
|
||||
return LocalImage()
|
||||
..image = file.readAsBytesSync()
|
||||
..name = p.basename(file.path);
|
||||
}).toList();
|
||||
|
||||
return LocalArchive()
|
||||
..path = path
|
||||
..extensionType = LocalExtensionType.folder
|
||||
..name = p.basename(path)
|
||||
..images = pages
|
||||
..coverImage = pages.first.image;
|
||||
..images = images
|
||||
..coverImage = images.first.image;
|
||||
}
|
||||
|
||||
return localArchive;
|
||||
}
|
||||
/// Extract images from an archive file
|
||||
LocalArchive _extractFromArchiveFile(String path) {
|
||||
final extensionType = _getArchiveType(path);
|
||||
final localArchive = LocalArchive()
|
||||
..path = path
|
||||
..extensionType = setTypeExtension(p.extension(path).replaceFirst(".", ""))
|
||||
..name = p.basenameWithoutExtension(path);
|
||||
Archive? archive;
|
||||
final inputStream = InputFileStream(path);
|
||||
final extensionType = localArchive.extensionType;
|
||||
if (extensionType == LocalExtensionType.cbt ||
|
||||
extensionType == LocalExtensionType.tar) {
|
||||
archive = TarDecoder().decodeStream(inputStream);
|
||||
} else {
|
||||
archive = ZipDecoder().decodeStream(inputStream);
|
||||
..extensionType = extensionType
|
||||
..name = p.basenameWithoutExtension(path)
|
||||
..images = [];
|
||||
|
||||
InputFileStream? inputStream;
|
||||
|
||||
try {
|
||||
inputStream = InputFileStream(path);
|
||||
final archive = _decodeArchive(inputStream, extensionType);
|
||||
|
||||
final imageFiles =
|
||||
archive.files
|
||||
.where(
|
||||
(file) =>
|
||||
file.isFile &&
|
||||
_isImageFile(file.name) &&
|
||||
!file.name.startsWith('.'),
|
||||
)
|
||||
.toList()
|
||||
..sort((a, b) => a.name.compareTo(b.name));
|
||||
|
||||
if (imageFiles.isEmpty) {
|
||||
throw Exception('No images found in archive: $path');
|
||||
}
|
||||
|
||||
for (final file in archive.files) {
|
||||
// Extract images
|
||||
for (final file in imageFiles) {
|
||||
final filename = file.name;
|
||||
if (file.isFile) {
|
||||
if (_isImageFile(filename) && !filename.startsWith('.')) {
|
||||
final data = file.content;
|
||||
if (filename.contains("cover")) {
|
||||
|
||||
if (filename.toLowerCase().contains('cover')) {
|
||||
localArchive.coverImage = data;
|
||||
} else {
|
||||
}
|
||||
|
||||
localArchive.images!.add(
|
||||
LocalImage()
|
||||
..image = data
|
||||
..name = p.basename(filename),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
localArchive.images!.sort((a, b) => a.name!.compareTo(b.name!));
|
||||
|
||||
// Set cover image if not explicitly found
|
||||
localArchive.coverImage ??= localArchive.images!.first.image;
|
||||
|
||||
return localArchive;
|
||||
} finally {
|
||||
inputStream?.close();
|
||||
}
|
||||
}
|
||||
|
||||
(String, LocalExtensionType, Uint8List, String) _extractArchiveOnly(
|
||||
/// Extract only metadata (name, type, cover) from archive
|
||||
Future<(String, LocalExtensionType, Uint8List, String)> _extractArchiveMetadata(
|
||||
String path,
|
||||
) {
|
||||
// If it's a directory, just read its images:
|
||||
if (Directory(path).existsSync()) {
|
||||
) async {
|
||||
try {
|
||||
// Handle directory of images
|
||||
if (await Directory(path).exists()) {
|
||||
return await _extractMetadataFromImageFolder(path);
|
||||
}
|
||||
|
||||
// Handle archive file
|
||||
return _extractMetadataFromArchiveFile(path);
|
||||
} catch (e) {
|
||||
debugPrint('Error extracting metadata from $path: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract metadata from image folder
|
||||
Future<(String, LocalExtensionType, Uint8List, String)>
|
||||
_extractMetadataFromImageFolder(String path) async {
|
||||
final dir = Directory(path);
|
||||
final images =
|
||||
dir
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.where((f) => _isImageFile(f.path))
|
||||
await dir
|
||||
.list()
|
||||
.where((entity) => entity is File && _isImageFile(entity.path))
|
||||
.cast<File>()
|
||||
.toList()
|
||||
..sort((a, b) => a.path.compareTo(b.path));
|
||||
|
||||
if (images.isEmpty) {
|
||||
throw Exception('No images found in folder: $path');
|
||||
}
|
||||
|
||||
final cover = images.first.readAsBytesSync();
|
||||
return (p.basename(path), LocalExtensionType.folder, cover, path);
|
||||
}
|
||||
final extensionType = setTypeExtension(
|
||||
p.extension(path).replaceFirst('.', ''),
|
||||
);
|
||||
}
|
||||
|
||||
/// Extract metadata from archive file
|
||||
(String, LocalExtensionType, Uint8List, String) _extractMetadataFromArchiveFile(
|
||||
String path,
|
||||
) {
|
||||
final extensionType = _getArchiveType(path);
|
||||
final name = p.basenameWithoutExtension(path);
|
||||
Uint8List? coverImage;
|
||||
|
||||
Archive? archive;
|
||||
final inputStream = InputFileStream(path);
|
||||
InputFileStream? inputStream;
|
||||
|
||||
if (extensionType == LocalExtensionType.cbt ||
|
||||
extensionType == LocalExtensionType.tar) {
|
||||
archive = TarDecoder().decodeStream(inputStream);
|
||||
} else {
|
||||
archive = ZipDecoder().decodeStream(inputStream);
|
||||
}
|
||||
try {
|
||||
inputStream = InputFileStream(path);
|
||||
final archive = _decodeArchive(inputStream, extensionType);
|
||||
|
||||
final cover = archive.files.where(
|
||||
// Look for cover image first
|
||||
final coverFile = archive.files.firstWhere(
|
||||
(file) =>
|
||||
file.isFile && _isImageFile(file.name) && file.name.contains("cover"),
|
||||
);
|
||||
|
||||
if (cover.isNotEmpty) {
|
||||
coverImage = cover.first.content;
|
||||
} else {
|
||||
List<ArchiveFile> lArchive = archive.files
|
||||
file.isFile &&
|
||||
_isImageFile(file.name) &&
|
||||
file.name.toLowerCase().contains('cover') &&
|
||||
!file.name.startsWith('.'),
|
||||
orElse: () {
|
||||
// If no cover, get first image alphabetically
|
||||
final imageFiles =
|
||||
archive.files
|
||||
.where(
|
||||
(file) =>
|
||||
file.isFile &&
|
||||
_isImageFile(file.name) &&
|
||||
!file.name.contains("cover"),
|
||||
!file.name.startsWith('.'),
|
||||
)
|
||||
.toList();
|
||||
lArchive.sort((a, b) => a.name.compareTo(b.name));
|
||||
coverImage = lArchive.first.content;
|
||||
.toList()
|
||||
..sort((a, b) => a.name.compareTo(b.name));
|
||||
|
||||
if (imageFiles.isEmpty) {
|
||||
throw Exception('No images found in archive: $path');
|
||||
}
|
||||
|
||||
return imageFiles.first;
|
||||
},
|
||||
);
|
||||
|
||||
final coverImage = coverFile.content;
|
||||
return (name, extensionType, coverImage, path);
|
||||
} finally {
|
||||
inputStream?.close();
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode archive based on type
|
||||
Archive _decodeArchive(InputFileStream stream, LocalExtensionType type) {
|
||||
switch (type) {
|
||||
case LocalExtensionType.cbt:
|
||||
case LocalExtensionType.tar:
|
||||
return TarDecoder().decodeStream(stream);
|
||||
case LocalExtensionType.zip:
|
||||
case LocalExtensionType.cbz:
|
||||
case LocalExtensionType.folder:
|
||||
return ZipDecoder().decodeStream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get archive type from file extension
|
||||
LocalExtensionType _getArchiveType(String path) {
|
||||
final extension = p.extension(path).toLowerCase().replaceFirst('.', '');
|
||||
return setTypeExtension(extension);
|
||||
}
|
||||
|
||||
String getTypeExtension(LocalExtensionType type) {
|
||||
return switch (type) {
|
||||
LocalExtensionType.cbt => type.name,
|
||||
LocalExtensionType.zip => type.name,
|
||||
LocalExtensionType.tar => type.name,
|
||||
_ => type.name,
|
||||
};
|
||||
return type.name;
|
||||
}
|
||||
|
||||
LocalExtensionType setTypeExtension(String extension) {
|
||||
return switch (extension) {
|
||||
"cbt" => LocalExtensionType.cbt,
|
||||
"zip" => LocalExtensionType.zip,
|
||||
"tar" => LocalExtensionType.tar,
|
||||
return switch (extension.toLowerCase()) {
|
||||
'cbt' => LocalExtensionType.cbt,
|
||||
'zip' => LocalExtensionType.zip,
|
||||
'tar' => LocalExtensionType.tar,
|
||||
'cbz' => LocalExtensionType.cbz,
|
||||
_ => LocalExtensionType.cbz,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ final class GetArchivesDataFromDirectoryProvider
|
|||
}
|
||||
|
||||
String _$getArchivesDataFromDirectoryHash() =>
|
||||
r'2a4d1a11e2b028e569ffd8a2700e4a1779bb9264';
|
||||
r'2f343dfe03bb479e80e6343f389fce8830998f0e';
|
||||
|
||||
final class GetArchivesDataFromDirectoryFamily extends $Family
|
||||
with
|
||||
|
|
@ -154,7 +154,7 @@ final class GetArchiveDataFromDirectoryProvider
|
|||
}
|
||||
|
||||
String _$getArchiveDataFromDirectoryHash() =>
|
||||
r'49aa47895feafd9fa0c4f20e25d7674a3d54b212';
|
||||
r'81705a8d04d4f4d1454a82b35e55eb2e0397ea6f';
|
||||
|
||||
final class GetArchiveDataFromDirectoryFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<LocalArchive>>, String> {
|
||||
|
|
@ -232,7 +232,7 @@ final class GetArchivesDataFromFileProvider
|
|||
}
|
||||
|
||||
String _$getArchivesDataFromFileHash() =>
|
||||
r'79874b548614b4410c19bca5f74978ec761742c5';
|
||||
r'04d8ce722c077a7def61dda20ff18b23090fb646';
|
||||
|
||||
final class GetArchivesDataFromFileFamily extends $Family
|
||||
with
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/anime/widgets/desktop.dart';
|
||||
import 'package:mangayomi/modules/library/providers/local_archive.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/crop_borders_provider.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/u_chap_data_preload.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/widgets/btn_chapter_list_dialog.dart';
|
||||
|
|
@ -389,7 +390,7 @@ class _MangaChapterPageGalleryState
|
|||
isar.mangas.putSync(
|
||||
manga
|
||||
..customCoverImage =
|
||||
imageBytes
|
||||
imageBytes.getCoverImage
|
||||
..updatedAt = DateTime.now()
|
||||
.millisecondsSinceEpoch,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -176,9 +176,8 @@ class _CreateBackupState extends ConsumerState<CreateBackup> {
|
|||
result = await FilePicker.platform
|
||||
.getDirectoryPath();
|
||||
}
|
||||
|
||||
if (result != null && context.mounted) {
|
||||
ref.watch(
|
||||
ref.read(
|
||||
doBackUpProvider(
|
||||
list: indexList,
|
||||
path: result,
|
||||
|
|
|
|||
Loading…
Reference in a new issue