From b8bdda16c6148514d78d53c9a7a39b13a4976f98 Mon Sep 17 00:00:00 2001 From: nyne Date: Mon, 2 Dec 2024 20:55:47 +0800 Subject: [PATCH] fix cbz import --- lib/utils/cbz.dart | 17 +++-- lib/utils/file_type.dart | 2 +- lib/utils/import_comic.dart | 126 ++++++++++++++++++------------------ lib/utils/io.dart | 9 +++ 4 files changed, 81 insertions(+), 73 deletions(-) diff --git a/lib/utils/cbz.dart b/lib/utils/cbz.dart index 7bc6ba1..f6c3b67 100644 --- a/lib/utils/cbz.dart +++ b/lib/utils/cbz.dart @@ -104,14 +104,14 @@ abstract class CBZ { FilePath.join(LocalManager().path, sanitizeFileName(metaData.title)), ); dest.createSync(); - coverFile.copy( - FilePath.join(dest.path, 'cover.${coverFile.path.split('.').last}')); + coverFile.copyMem( + FilePath.join(dest.path, 'cover.${coverFile.extension}')); if (metaData.chapters == null) { for (var i = 0; i < files.length; i++) { var src = files[i]; var dst = File( FilePath.join(dest.path, '${i + 1}.${src.path.split('.').last}')); - await src.copy(dst.path); + await src.copyMem(dst.path); } } else { dest.createSync(); @@ -129,7 +129,7 @@ abstract class CBZ { var src = chapter.value[i]; var dst = File(FilePath.join( chapterDir.path, '${i + 1}.${src.path.split('.').last}')); - await src.copy(dst.path); + await src.copyMem(dst.path); } } } @@ -142,10 +142,9 @@ abstract class CBZ { directory: dest.name, chapters: cpMap, downloadedChapters: cpMap?.keys.toList() ?? [], - cover: 'cover.${coverFile.path.split('.').last}', + cover: 'cover.${coverFile.extension}', createdAt: DateTime.now(), ); - LocalManager().add(comic); await cache.delete(recursive: true); return comic; } @@ -164,7 +163,7 @@ abstract class CBZ { var dstName = '${i.toString().padLeft(width, '0')}.${image.split('.').last}'; var dst = File(FilePath.join(cache.path, dstName)); - await src.copy(dst.path); + await src.copyMem(dst.path); i++; } } else { @@ -192,13 +191,13 @@ abstract class CBZ { var dstName = '${i.toString().padLeft(width, '0')}.${image.split('.').last}'; var dst = File(FilePath.join(cache.path, dstName)); - await src.copy(dst.path); + await src.copyMem(dst.path); i++; } } var cover = comic.coverFile; await cover - .copy(FilePath.join(cache.path, 'cover.${cover.path.split('.').last}')); + .copyMem(FilePath.join(cache.path, 'cover.${cover.path.split('.').last}')); await File(FilePath.join(cache.path, 'metadata.json')).writeAsString( jsonEncode( ComicMetaData( diff --git a/lib/utils/file_type.dart b/lib/utils/file_type.dart index f75ddf0..86538e1 100644 --- a/lib/utils/file_type.dart +++ b/lib/utils/file_type.dart @@ -13,7 +13,7 @@ class FileType { var mime = lookupMimeType('no-file.$ext') ?? 'application/octet-stream'; // Android doesn't support some mime types mime = switch(mime) { - 'text/javascript' => 'application/javascript', + 'text/javascript' => 'application/octet-stream', 'application/x-cbr' => 'application/octet-stream', _ => mime, }; diff --git a/lib/utils/import_comic.dart b/lib/utils/import_comic.dart index 157e306..d2db6ff 100644 --- a/lib/utils/import_comic.dart +++ b/lib/utils/import_comic.dart @@ -22,7 +22,7 @@ class ImportComic { Future cbz() async { var file = await selectFile(ext: ['cbz', 'zip']); Map> imported = {}; - if(file == null) { + if (file == null) { return false; } var controller = showLoadingDialog(App.rootContext, allowCancel: false); @@ -34,7 +34,7 @@ class ImportComic { App.rootContext.showMessage(message: e.toString()); } controller.close(); - return registerComics(imported, true); + return registerComics(imported, false); } Future ehViewer() async { @@ -63,7 +63,7 @@ class ImportComic { var comicDir = Directory( FilePath.join(comicSrc.path, comic['DIRNAME'] as String)); String titleJP = - comic['TITLE_JPN'] == null ? "" : comic['TITLE_JPN'] as String; + comic['TITLE_JPN'] == null ? "" : comic['TITLE_JPN'] as String; String title = titleJP == "" ? comic['TITLE'] as String : titleJP; int timeStamp = comic['TIME'] as int; DateTime downloadTime = timeStamp != 0 @@ -105,8 +105,7 @@ class ImportComic { if (cancelled) { break; } - var folderName = - tag == '' ? '(EhViewer)Default'.tl : '(EhViewer)$tag'; + var folderName = tag == '' ? '(EhViewer)Default'.tl : '(EhViewer)$tag'; var comicList = db.select(""" SELECT * FROM DOWNLOAD_DIRNAME DN @@ -133,7 +132,7 @@ class ImportComic { App.rootContext.showMessage(message: e.toString()); } controller.close(); - if(cancelled) return false; + if (cancelled) return false; return registerComics(imported, copyToLocal); } @@ -173,11 +172,10 @@ class ImportComic { //Automatically search for cover image and chapters Future _checkSingleComic(Directory directory, {String? id, - String? title, - String? subtitle, - List? tags, - DateTime? createTime}) - async { + String? title, + String? subtitle, + List? tags, + DateTime? createTime}) async { if (!(await directory.exists())) return null; var name = title ?? directory.name; if (LocalManager().findByName(name) != null) { @@ -207,12 +205,13 @@ class ImportComic { } } - if(fileList.isEmpty) { + if (fileList.isEmpty) { return null; } fileList.sort(); - coverPath = fileList.firstWhereOrNull((l) => l.startsWith('cover')) ?? fileList.first; + coverPath = fileList.firstWhereOrNull((l) => l.startsWith('cover')) ?? + fileList.first; chapters.sort(); if (hasChapters && coverPath == '') { @@ -243,26 +242,29 @@ class ImportComic { ); } - static Future> _copyDirectories(Map data) async { - var toBeCopied = data['toBeCopied'] as List; - var destination = data['destination'] as String; - Map result = {}; - for (var dir in toBeCopied) { - var source = Directory(dir); - var dest = Directory("$destination/${source.name}"); - if (dest.existsSync()) { - // The destination directory already exists, and it is not managed by the app. - // Rename the old directory to avoid conflicts. - Log.info("Import Comic", - "Directory already exists: ${source.name}\nRenaming the old directory."); - await dest.rename( - findValidDirectoryName(dest.parent.path, "${dest.path}_old")); + static Future> _copyDirectories( + Map data) async { + return overrideIO(() async { + var toBeCopied = data['toBeCopied'] as List; + var destination = data['destination'] as String; + Map result = {}; + for (var dir in toBeCopied) { + var source = Directory(dir); + var dest = Directory("$destination/${source.name}"); + if (dest.existsSync()) { + // The destination directory already exists, and it is not managed by the app. + // Rename the old directory to avoid conflicts. + Log.info("Import Comic", + "Directory already exists: ${source.name}\nRenaming the old directory."); + dest.renameSync( + findValidDirectoryName(dest.parent.path, "${dest.path}_old")); + } + dest.createSync(); + await copyDirectory(source, dest); + result[source.path] = dest.path; } - dest.createSync(); - await copyDirectory(source, dest); - result[source.path] = dest.path; - } - return result; + return result; + }); } Future>> _copyComicsToLocalDir( @@ -284,36 +286,36 @@ class ImportComic { // copy the comics to the local directory var pathMap = await compute, Map>( _copyDirectories, { - 'toBeCopied': comics[favoriteFolder]!.map((e) => e.directory).toList(), + 'toBeCopied': + comics[favoriteFolder]!.map((e) => e.directory).toList(), 'destination': destPath, }); //Construct a new object since LocalComic.directory is a final String for (var c in comics[favoriteFolder]!) { - result[favoriteFolder]!.add( - LocalComic( - id: c.id, - title: c.title, - subtitle: c.subtitle, - tags: c.tags, - directory: pathMap[c.directory]!, - chapters: c.chapters, - cover: c.cover, - comicType: c.comicType, - downloadedChapters: c.downloadedChapters, - createdAt: c.createdAt - ) - ); + result[favoriteFolder]!.add(LocalComic( + id: c.id, + title: c.title, + subtitle: c.subtitle, + tags: c.tags, + directory: pathMap[c.directory]!, + chapters: c.chapters, + cover: c.cover, + comicType: c.comicType, + downloadedChapters: c.downloadedChapters, + createdAt: c.createdAt, + )); } - } catch (e) { + } catch (e, s) { App.rootContext.showMessage(message: "Failed to copy comics".tl); - Log.error("Import Comic", e.toString()); + Log.error("Import Comic", e.toString(), s); return result; } } return result; } - Future registerComics(Map> importedComics, bool copy) async { + Future registerComics( + Map> importedComics, bool copy) async { try { if (copy) { importedComics = await _copyComicsToLocalDir(importedComics); @@ -328,25 +330,23 @@ class ImportComic { LocalFavoritesManager().addComic( folder, FavoriteItem( - id: id, - name: comic.title, - coverPath: comic.cover, - author: comic.subtitle, - type: comic.comicType, - tags: comic.tags, - favoriteTime: comic.createdAt - ) - ); + id: id, + name: comic.title, + coverPath: comic.cover, + author: comic.subtitle, + type: comic.comicType, + tags: comic.tags, + favoriteTime: comic.createdAt)); } } } App.rootContext.showMessage( message: "Imported @a comics".tlParams({ - 'a': importedCount, - })); - } catch(e) { + 'a': importedCount, + })); + } catch (e, s) { App.rootContext.showMessage(message: "Failed to register comics".tl); - Log.error("Import Comic", e.toString()); + Log.error("Import Comic", e.toString(), s); return false; } return true; diff --git a/lib/utils/io.dart b/lib/utils/io.dart index 12617b9..b577eeb 100644 --- a/lib/utils/io.dart +++ b/lib/utils/io.dart @@ -73,6 +73,15 @@ extension FileSystemEntityExt on FileSystemEntity { extension FileExtension on File { String get extension => path.split('.').last; + + /// Copy the file to the specified path using memory. + /// + /// This method prevents errors caused by files from different file systems. + Future copyMem(String newPath) async { + var newFile = File(newPath); + // Stream is not usable since [AndroidFile] does not support [openRead]. + await newFile.writeAsBytes(await readAsBytes()); + } } extension DirectoryExtension on Directory {