fix cbz import

This commit is contained in:
2024-12-02 20:55:47 +08:00
parent 867b2a4b64
commit 9b821f1b46
4 changed files with 81 additions and 73 deletions

View File

@@ -104,14 +104,14 @@ abstract class CBZ {
FilePath.join(LocalManager().path, sanitizeFileName(metaData.title)), FilePath.join(LocalManager().path, sanitizeFileName(metaData.title)),
); );
dest.createSync(); dest.createSync();
coverFile.copy( coverFile.copyMem(
FilePath.join(dest.path, 'cover.${coverFile.path.split('.').last}')); FilePath.join(dest.path, 'cover.${coverFile.extension}'));
if (metaData.chapters == null) { if (metaData.chapters == null) {
for (var i = 0; i < files.length; i++) { for (var i = 0; i < files.length; i++) {
var src = files[i]; var src = files[i];
var dst = File( var dst = File(
FilePath.join(dest.path, '${i + 1}.${src.path.split('.').last}')); FilePath.join(dest.path, '${i + 1}.${src.path.split('.').last}'));
await src.copy(dst.path); await src.copyMem(dst.path);
} }
} else { } else {
dest.createSync(); dest.createSync();
@@ -129,7 +129,7 @@ abstract class CBZ {
var src = chapter.value[i]; var src = chapter.value[i];
var dst = File(FilePath.join( var dst = File(FilePath.join(
chapterDir.path, '${i + 1}.${src.path.split('.').last}')); 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, directory: dest.name,
chapters: cpMap, chapters: cpMap,
downloadedChapters: cpMap?.keys.toList() ?? [], downloadedChapters: cpMap?.keys.toList() ?? [],
cover: 'cover.${coverFile.path.split('.').last}', cover: 'cover.${coverFile.extension}',
createdAt: DateTime.now(), createdAt: DateTime.now(),
); );
LocalManager().add(comic);
await cache.delete(recursive: true); await cache.delete(recursive: true);
return comic; return comic;
} }
@@ -164,7 +163,7 @@ abstract class CBZ {
var dstName = var dstName =
'${i.toString().padLeft(width, '0')}.${image.split('.').last}'; '${i.toString().padLeft(width, '0')}.${image.split('.').last}';
var dst = File(FilePath.join(cache.path, dstName)); var dst = File(FilePath.join(cache.path, dstName));
await src.copy(dst.path); await src.copyMem(dst.path);
i++; i++;
} }
} else { } else {
@@ -192,13 +191,13 @@ abstract class CBZ {
var dstName = var dstName =
'${i.toString().padLeft(width, '0')}.${image.split('.').last}'; '${i.toString().padLeft(width, '0')}.${image.split('.').last}';
var dst = File(FilePath.join(cache.path, dstName)); var dst = File(FilePath.join(cache.path, dstName));
await src.copy(dst.path); await src.copyMem(dst.path);
i++; i++;
} }
} }
var cover = comic.coverFile; var cover = comic.coverFile;
await cover 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( await File(FilePath.join(cache.path, 'metadata.json')).writeAsString(
jsonEncode( jsonEncode(
ComicMetaData( ComicMetaData(

View File

@@ -13,7 +13,7 @@ class FileType {
var mime = lookupMimeType('no-file.$ext') ?? 'application/octet-stream'; var mime = lookupMimeType('no-file.$ext') ?? 'application/octet-stream';
// Android doesn't support some mime types // Android doesn't support some mime types
mime = switch(mime) { mime = switch(mime) {
'text/javascript' => 'application/javascript', 'text/javascript' => 'application/octet-stream',
'application/x-cbr' => 'application/octet-stream', 'application/x-cbr' => 'application/octet-stream',
_ => mime, _ => mime,
}; };

View File

@@ -22,7 +22,7 @@ class ImportComic {
Future<bool> cbz() async { Future<bool> cbz() async {
var file = await selectFile(ext: ['cbz', 'zip']); var file = await selectFile(ext: ['cbz', 'zip']);
Map<String?, List<LocalComic>> imported = {}; Map<String?, List<LocalComic>> imported = {};
if(file == null) { if (file == null) {
return false; return false;
} }
var controller = showLoadingDialog(App.rootContext, allowCancel: false); var controller = showLoadingDialog(App.rootContext, allowCancel: false);
@@ -34,7 +34,7 @@ class ImportComic {
App.rootContext.showMessage(message: e.toString()); App.rootContext.showMessage(message: e.toString());
} }
controller.close(); controller.close();
return registerComics(imported, true); return registerComics(imported, false);
} }
Future<bool> ehViewer() async { Future<bool> ehViewer() async {
@@ -105,8 +105,7 @@ class ImportComic {
if (cancelled) { if (cancelled) {
break; break;
} }
var folderName = var folderName = tag == '' ? '(EhViewer)Default'.tl : '(EhViewer)$tag';
tag == '' ? '(EhViewer)Default'.tl : '(EhViewer)$tag';
var comicList = db.select(""" var comicList = db.select("""
SELECT * SELECT *
FROM DOWNLOAD_DIRNAME DN FROM DOWNLOAD_DIRNAME DN
@@ -133,7 +132,7 @@ class ImportComic {
App.rootContext.showMessage(message: e.toString()); App.rootContext.showMessage(message: e.toString());
} }
controller.close(); controller.close();
if(cancelled) return false; if (cancelled) return false;
return registerComics(imported, copyToLocal); return registerComics(imported, copyToLocal);
} }
@@ -176,8 +175,7 @@ class ImportComic {
String? title, String? title,
String? subtitle, String? subtitle,
List<String>? tags, List<String>? tags,
DateTime? createTime}) DateTime? createTime}) async {
async {
if (!(await directory.exists())) return null; if (!(await directory.exists())) return null;
var name = title ?? directory.name; var name = title ?? directory.name;
if (LocalManager().findByName(name) != null) { if (LocalManager().findByName(name) != null) {
@@ -207,12 +205,13 @@ class ImportComic {
} }
} }
if(fileList.isEmpty) { if (fileList.isEmpty) {
return null; return null;
} }
fileList.sort(); fileList.sort();
coverPath = fileList.firstWhereOrNull((l) => l.startsWith('cover')) ?? fileList.first; coverPath = fileList.firstWhereOrNull((l) => l.startsWith('cover')) ??
fileList.first;
chapters.sort(); chapters.sort();
if (hasChapters && coverPath == '') { if (hasChapters && coverPath == '') {
@@ -243,7 +242,9 @@ class ImportComic {
); );
} }
static Future<Map<String, String>> _copyDirectories(Map<String, dynamic> data) async { static Future<Map<String, String>> _copyDirectories(
Map<String, dynamic> data) async {
return overrideIO(() async {
var toBeCopied = data['toBeCopied'] as List<String>; var toBeCopied = data['toBeCopied'] as List<String>;
var destination = data['destination'] as String; var destination = data['destination'] as String;
Map<String, String> result = {}; Map<String, String> result = {};
@@ -255,7 +256,7 @@ class ImportComic {
// Rename the old directory to avoid conflicts. // Rename the old directory to avoid conflicts.
Log.info("Import Comic", Log.info("Import Comic",
"Directory already exists: ${source.name}\nRenaming the old directory."); "Directory already exists: ${source.name}\nRenaming the old directory.");
await dest.rename( dest.renameSync(
findValidDirectoryName(dest.parent.path, "${dest.path}_old")); findValidDirectoryName(dest.parent.path, "${dest.path}_old"));
} }
dest.createSync(); dest.createSync();
@@ -263,6 +264,7 @@ class ImportComic {
result[source.path] = dest.path; result[source.path] = dest.path;
} }
return result; return result;
});
} }
Future<Map<String?, List<LocalComic>>> _copyComicsToLocalDir( Future<Map<String?, List<LocalComic>>> _copyComicsToLocalDir(
@@ -284,13 +286,13 @@ class ImportComic {
// copy the comics to the local directory // copy the comics to the local directory
var pathMap = await compute<Map<String, dynamic>, Map<String, String>>( var pathMap = await compute<Map<String, dynamic>, Map<String, String>>(
_copyDirectories, { _copyDirectories, {
'toBeCopied': comics[favoriteFolder]!.map((e) => e.directory).toList(), 'toBeCopied':
comics[favoriteFolder]!.map((e) => e.directory).toList(),
'destination': destPath, 'destination': destPath,
}); });
//Construct a new object since LocalComic.directory is a final String //Construct a new object since LocalComic.directory is a final String
for (var c in comics[favoriteFolder]!) { for (var c in comics[favoriteFolder]!) {
result[favoriteFolder]!.add( result[favoriteFolder]!.add(LocalComic(
LocalComic(
id: c.id, id: c.id,
title: c.title, title: c.title,
subtitle: c.subtitle, subtitle: c.subtitle,
@@ -300,20 +302,20 @@ class ImportComic {
cover: c.cover, cover: c.cover,
comicType: c.comicType, comicType: c.comicType,
downloadedChapters: c.downloadedChapters, downloadedChapters: c.downloadedChapters,
createdAt: c.createdAt createdAt: c.createdAt,
) ));
);
} }
} catch (e) { } catch (e, s) {
App.rootContext.showMessage(message: "Failed to copy comics".tl); 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;
} }
} }
return result; return result;
} }
Future<bool> registerComics(Map<String?, List<LocalComic>> importedComics, bool copy) async { Future<bool> registerComics(
Map<String?, List<LocalComic>> importedComics, bool copy) async {
try { try {
if (copy) { if (copy) {
importedComics = await _copyComicsToLocalDir(importedComics); importedComics = await _copyComicsToLocalDir(importedComics);
@@ -334,9 +336,7 @@ class ImportComic {
author: comic.subtitle, author: comic.subtitle,
type: comic.comicType, type: comic.comicType,
tags: comic.tags, tags: comic.tags,
favoriteTime: comic.createdAt favoriteTime: comic.createdAt));
)
);
} }
} }
} }
@@ -344,9 +344,9 @@ class ImportComic {
message: "Imported @a comics".tlParams({ message: "Imported @a comics".tlParams({
'a': importedCount, 'a': importedCount,
})); }));
} catch(e) { } catch (e, s) {
App.rootContext.showMessage(message: "Failed to register comics".tl); 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 false;
} }
return true; return true;

View File

@@ -73,6 +73,15 @@ extension FileSystemEntityExt on FileSystemEntity {
extension FileExtension on File { extension FileExtension on File {
String get extension => path.split('.').last; 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<void> 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 { extension DirectoryExtension on Directory {