mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
@@ -453,15 +453,15 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
|
||||
String info = [
|
||||
"Select a directory which contains the comic files.".tl,
|
||||
"Select a directory which contains the comic directories.".tl,
|
||||
"Select a cbz/zip file.".tl,
|
||||
"Select a directory which contains multiple cbz/zip files.".tl,
|
||||
"Select an archive file (cbz, zip, 7z, cb7)".tl,
|
||||
"Select a directory which contains multiple archive files.".tl,
|
||||
"Select an EhViewer database and a download folder.".tl
|
||||
][type];
|
||||
List<String> importMethods = [
|
||||
"Single Comic".tl,
|
||||
"Multiple Comics".tl,
|
||||
"A cbz file".tl,
|
||||
"Multiple cbz files".tl,
|
||||
"An archive file".tl,
|
||||
"Multiple archive files".tl,
|
||||
"EhViewer downloads".tl
|
||||
];
|
||||
|
||||
@@ -493,7 +493,7 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
|
||||
},
|
||||
);
|
||||
}),
|
||||
if (type != 3)
|
||||
if (type != 4)
|
||||
ListTile(
|
||||
title: Text("Add to favorites".tl),
|
||||
trailing: Select(
|
||||
@@ -507,7 +507,7 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
|
||||
},
|
||||
),
|
||||
).paddingHorizontal(8),
|
||||
if (!App.isIOS && !App.isMacOS)
|
||||
if (!App.isIOS && !App.isMacOS && type != 2 && type != 3)
|
||||
CheckboxListTile(
|
||||
enabled: true,
|
||||
title: Text("Copy to app local path".tl),
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_7zip/flutter_7zip.dart';
|
||||
import 'package:venera/foundation/app.dart';
|
||||
import 'package:venera/foundation/comic_type.dart';
|
||||
import 'package:venera/foundation/local.dart';
|
||||
import 'package:venera/utils/ext.dart';
|
||||
import 'package:venera/utils/file_type.dart';
|
||||
import 'package:venera/utils/io.dart';
|
||||
import 'package:zip_flutter/zip_flutter.dart';
|
||||
|
||||
@@ -57,12 +58,33 @@ class ComicChapter {
|
||||
ComicChapter({required this.title, required this.start, required this.end});
|
||||
}
|
||||
|
||||
/// Comic Book Archive. Currently supports CBZ, ZIP and 7Z formats.
|
||||
abstract class CBZ {
|
||||
static Future<FileType> checkType(File file) async {
|
||||
var header = <int>[];
|
||||
await for (var bytes in file.openRead()) {
|
||||
header.addAll(bytes);
|
||||
if (header.length >= 32) break;
|
||||
}
|
||||
return detectFileType(header);
|
||||
}
|
||||
|
||||
static Future<void> extractArchive(File file, Directory out) async {
|
||||
var fileType = await checkType(file);
|
||||
if (fileType.mime == 'application/zip') {
|
||||
await ZipFile.openAndExtractAsync(file.path, out.path, 4);
|
||||
} else if (fileType.mime == "application/x-7z-compressed") {
|
||||
await SZArchive.extractIsolates(file.path, out.path, 4);
|
||||
} else {
|
||||
throw Exception('Unsupported archive type');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<LocalComic> import(File file) async {
|
||||
var cache = Directory(FilePath.join(App.cachePath, 'cbz_import'));
|
||||
if (cache.existsSync()) cache.deleteSync(recursive: true);
|
||||
cache.createSync();
|
||||
await ZipFile.openAndExtractAsync(file.path, cache.path, 4);
|
||||
await extractArchive(file, cache);
|
||||
var metaDataFile = File(FilePath.join(cache.path, 'metadata.json'));
|
||||
ComicMetaData? metaData;
|
||||
if (metaDataFile.existsSync()) {
|
||||
@@ -72,7 +94,7 @@ abstract class CBZ {
|
||||
} catch (_) {}
|
||||
}
|
||||
metaData ??= ComicMetaData(
|
||||
title: file.name.replaceLast('.cbz', ''),
|
||||
title: file.name.substring(0, file.name.lastIndexOf('.')),
|
||||
author: "",
|
||||
tags: [],
|
||||
);
|
||||
@@ -86,6 +108,7 @@ abstract class CBZ {
|
||||
return !['jpg', 'jpeg', 'png', 'webp', 'gif', 'jpe'].contains(ext);
|
||||
});
|
||||
if(files.isEmpty) {
|
||||
cache.deleteSync(recursive: true);
|
||||
throw Exception('No images found in the archive');
|
||||
}
|
||||
files.sort((a, b) => a.path.compareTo(b.path));
|
||||
|
@@ -21,8 +21,17 @@ class FileType {
|
||||
}
|
||||
}
|
||||
|
||||
final _resolver = MimeTypeResolver()
|
||||
// zip
|
||||
..addMagicNumber([0x50, 0x4B], 'application/zip')
|
||||
// 7z
|
||||
..addMagicNumber([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C], 'application/x-7z-compressed')
|
||||
// rar
|
||||
..addMagicNumber([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07], 'application/vnd.rar')
|
||||
;
|
||||
|
||||
FileType detectFileType(List<int> data) {
|
||||
var mime = lookupMimeType('no-file', headerBytes: data);
|
||||
var mime = _resolver.lookup('no-file', headerBytes: data);
|
||||
var ext = mime == null ? '' : extensionFromMime(mime);
|
||||
if(ext == 'jpe') {
|
||||
ext = 'jpg';
|
||||
|
@@ -20,7 +20,7 @@ class ImportComic {
|
||||
const ImportComic({this.selectedFolder, this.copyToLocal = true});
|
||||
|
||||
Future<bool> cbz() async {
|
||||
var file = await selectFile(ext: ['cbz', 'zip']);
|
||||
var file = await selectFile(ext: ['cbz', 'zip', '7z', 'cb7']);
|
||||
Map<String?, List<LocalComic>> imported = {};
|
||||
if (file == null) {
|
||||
return false;
|
||||
@@ -42,7 +42,8 @@ class ImportComic {
|
||||
var dir = await picker.pickDirectory(directAccess: true);
|
||||
if (dir != null) {
|
||||
var files = (await dir.list().toList()).whereType<File>().toList();
|
||||
files.removeWhere((e) => e.extension != 'cbz' && e.extension != 'zip');
|
||||
const supportedExtensions = ['cbz', 'zip', '7z', 'cb7'];
|
||||
files.removeWhere((e) => !supportedExtensions.contains(e.extension));
|
||||
Map<String?, List<LocalComic>> imported = {};
|
||||
var controller = showLoadingDialog(App.rootContext, allowCancel: false);
|
||||
var comics = <LocalComic>[];
|
||||
|
Reference in New Issue
Block a user