mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Add ComicInfo.xml to cbz file. Close #333
This commit is contained in:
@@ -306,7 +306,8 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// prevent dirty data
|
// prevent dirty data
|
||||||
var comic = LocalManager().find(c.id, ComicType.fromKey(c.sourceKey))!;
|
var comic =
|
||||||
|
LocalManager().find(c.id, ComicType.fromKey(c.sourceKey))!;
|
||||||
comic.read();
|
comic.read();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -444,7 +445,10 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
var fileName = "";
|
var fileName = "";
|
||||||
// For each comic, export it to a file
|
// For each comic, export it to a file
|
||||||
for (var comic in comics) {
|
for (var comic in comics) {
|
||||||
fileName = FilePath.join(cacheDir, sanitizeFileName(comic.title) + ext);
|
fileName = FilePath.join(
|
||||||
|
cacheDir,
|
||||||
|
sanitizeFileName(comic.title, maxLength: 100) + ext,
|
||||||
|
);
|
||||||
await export(comic, fileName);
|
await export(comic, fileName);
|
||||||
current++;
|
current++;
|
||||||
if (comics.length > 1) {
|
if (comics.length > 1) {
|
||||||
|
@@ -112,7 +112,7 @@ abstract class CBZ {
|
|||||||
var ext = e.path.split('.').last;
|
var ext = e.path.split('.').last;
|
||||||
return !['jpg', 'jpeg', 'png', 'webp', 'gif', 'jpe'].contains(ext);
|
return !['jpg', 'jpeg', 'png', 'webp', 'gif', 'jpe'].contains(ext);
|
||||||
});
|
});
|
||||||
if(files.isEmpty) {
|
if (files.isEmpty) {
|
||||||
cache.deleteSync(recursive: true);
|
cache.deleteSync(recursive: true);
|
||||||
throw Exception('No images found in the archive');
|
throw Exception('No images found in the archive');
|
||||||
}
|
}
|
||||||
@@ -141,8 +141,7 @@ abstract class CBZ {
|
|||||||
FilePath.join(LocalManager().path, sanitizeFileName(metaData.title)),
|
FilePath.join(LocalManager().path, sanitizeFileName(metaData.title)),
|
||||||
);
|
);
|
||||||
dest.createSync();
|
dest.createSync();
|
||||||
coverFile.copyMem(
|
coverFile.copyMem(FilePath.join(dest.path, 'cover.${coverFile.extension}'));
|
||||||
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];
|
||||||
@@ -233,17 +232,19 @@ abstract class CBZ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var cover = comic.coverFile;
|
var cover = comic.coverFile;
|
||||||
await cover
|
await cover.copyMem(
|
||||||
.copyMem(FilePath.join(cache.path, 'cover.${cover.path.split('.').last}'));
|
FilePath.join(cache.path, 'cover.${cover.path.split('.').last}'));
|
||||||
|
final metaData = ComicMetaData(
|
||||||
|
title: comic.title,
|
||||||
|
author: comic.subtitle,
|
||||||
|
tags: comic.tags,
|
||||||
|
chapters: chapters,
|
||||||
|
);
|
||||||
await File(FilePath.join(cache.path, 'metadata.json')).writeAsString(
|
await File(FilePath.join(cache.path, 'metadata.json')).writeAsString(
|
||||||
jsonEncode(
|
jsonEncode(metaData),
|
||||||
ComicMetaData(
|
);
|
||||||
title: comic.title,
|
await File(FilePath.join(cache.path, 'ComicInfo.xml')).writeAsString(
|
||||||
author: comic.subtitle,
|
_buildComicInfoXml(metaData),
|
||||||
tags: comic.tags,
|
|
||||||
chapters: chapters,
|
|
||||||
).toJson(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
var cbz = File(outFilePath);
|
var cbz = File(outFilePath);
|
||||||
if (cbz.existsSync()) cbz.deleteSync();
|
if (cbz.existsSync()) cbz.deleteSync();
|
||||||
@@ -252,7 +253,54 @@ abstract class CBZ {
|
|||||||
return cbz;
|
return cbz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String _buildComicInfoXml(ComicMetaData data) {
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
buffer.writeln('<?xml version="1.0" encoding="utf-8"?>');
|
||||||
|
buffer.writeln('<ComicInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">');
|
||||||
|
|
||||||
|
buffer.writeln(' <Title>${_escapeXml(data.title)}</Title>');
|
||||||
|
buffer.writeln(' <Series>${_escapeXml(data.title)}</Series>');
|
||||||
|
|
||||||
|
if (data.author.isNotEmpty) {
|
||||||
|
buffer.writeln(' <Writer>${_escapeXml(data.author)}</Writer>');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.tags.isNotEmpty) {
|
||||||
|
var tags = data.tags;
|
||||||
|
if (tags.length > 5) {
|
||||||
|
tags = tags.sublist(0, 5);
|
||||||
|
}
|
||||||
|
buffer.writeln(' <Genre>${_escapeXml(tags.join(', '))}</Genre>');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.chapters != null && data.chapters!.isNotEmpty) {
|
||||||
|
final chaptersInfo = data.chapters!.map((chapter) =>
|
||||||
|
'${_escapeXml(chapter.title)}: ${chapter.start}-${chapter.end}'
|
||||||
|
).join('; ');
|
||||||
|
buffer.writeln(' <Notes>Chapters: $chaptersInfo</Notes>');
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.writeln(' <Manga>Unknown</Manga>');
|
||||||
|
buffer.writeln(' <BlackAndWhite>Unknown</BlackAndWhite>');
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
buffer.writeln(' <Year>${now.year}</Year>');
|
||||||
|
|
||||||
|
buffer.writeln('</ComicInfo>');
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _escapeXml(String text) {
|
||||||
|
return text
|
||||||
|
.replaceAll('&', '&')
|
||||||
|
.replaceAll('<', '<')
|
||||||
|
.replaceAll('>', '>')
|
||||||
|
.replaceAll('"', '"')
|
||||||
|
.replaceAll("'", ''');
|
||||||
|
}
|
||||||
|
|
||||||
static _compress(String src, String dst) async {
|
static _compress(String src, String dst) async {
|
||||||
await ZipFile.compressFolderAsync(src, dst, 4);
|
await ZipFile.compressFolderAsync(src, dst, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -135,12 +135,12 @@ String sanitizeFileName(String fileName, {String? dir, int? maxLength}) {
|
|||||||
if (fileName.endsWith('.')) {
|
if (fileName.endsWith('.')) {
|
||||||
fileName = fileName.substring(0, fileName.length - 1);
|
fileName = fileName.substring(0, fileName.length - 1);
|
||||||
}
|
}
|
||||||
var maxLength = 255;
|
var length = maxLength ?? 255;
|
||||||
if (dir != null) {
|
if (dir != null) {
|
||||||
if (!dir.endsWith('/') && !dir.endsWith('\\')) {
|
if (!dir.endsWith('/') && !dir.endsWith('\\')) {
|
||||||
dir = "$dir/";
|
dir = "$dir/";
|
||||||
}
|
}
|
||||||
maxLength -= dir.length;
|
length -= dir.length;
|
||||||
}
|
}
|
||||||
final invalidChars = RegExp(r'[<>:"/\\|?*]');
|
final invalidChars = RegExp(r'[<>:"/\\|?*]');
|
||||||
final sanitizedFileName = fileName.replaceAll(invalidChars, ' ');
|
final sanitizedFileName = fileName.replaceAll(invalidChars, ' ');
|
||||||
@@ -148,11 +148,11 @@ String sanitizeFileName(String fileName, {String? dir, int? maxLength}) {
|
|||||||
if (trimmedFileName.isEmpty) {
|
if (trimmedFileName.isEmpty) {
|
||||||
throw Exception('Invalid File Name: Empty length.');
|
throw Exception('Invalid File Name: Empty length.');
|
||||||
}
|
}
|
||||||
if (maxLength <= 0) {
|
if (length <= 0) {
|
||||||
throw Exception('Invalid File Name: Max length is less than 0.');
|
throw Exception('Invalid File Name: Max length is less than 0.');
|
||||||
}
|
}
|
||||||
if (trimmedFileName.length > maxLength) {
|
if (trimmedFileName.length > length) {
|
||||||
trimmedFileName = trimmedFileName.substring(0, maxLength);
|
trimmedFileName = trimmedFileName.substring(0, length);
|
||||||
}
|
}
|
||||||
return trimmedFileName;
|
return trimmedFileName;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user