diff --git a/src/web/mjs/HakuNeko.mjs b/src/web/mjs/HakuNeko.mjs index e506fd143d..9c3282418d 100644 --- a/src/web/mjs/HakuNeko.mjs +++ b/src/web/mjs/HakuNeko.mjs @@ -8,6 +8,7 @@ import BookmarkManager from './engine/BookmarkManager.mjs'; import ChaptermarkManager from './engine/ChaptermarkManager.mjs'; import Connectors from './engine/Connectors.mjs'; import DownloadManager from './engine/DownloadManager.mjs'; +import ComicInfoGenerator from './engine/ComicInfoGenerator.mjs'; //import HistoryWorker from './engine/HistoryWorker.mjs' import Request from './engine/Request.mjs'; import Settings from './engine/Settings.mjs'; @@ -32,6 +33,7 @@ export default class HakuNeko { this._connectors = new Connectors(ipc); this._storage = new Storage(); this._bookmarkManager = new BookmarkManager(this._settings, new BookmarkImporter()); + this._comicInfoGenerator = new ComicInfoGenerator(); this._chaptermarkManager = new ChaptermarkManager(this._settings); this._discordPresence = new DiscordPresence(this._settings); } @@ -63,6 +65,10 @@ export default class HakuNeko { return this._bookmarkManager; } + get ComicInfoGenerator() { + return this._comicInfoGenerator; + } + get ChaptermarkManager() { return this._chaptermarkManager; } diff --git a/src/web/mjs/engine/ComicInfoGenerator.mjs b/src/web/mjs/engine/ComicInfoGenerator.mjs new file mode 100644 index 0000000000..394133e080 --- /dev/null +++ b/src/web/mjs/engine/ComicInfoGenerator.mjs @@ -0,0 +1,26 @@ +export default class ComicInfoGenerator { + createComicInfoXML(series, title, pagesCount) { + series = this.escapeXML(series); + title = this.escapeXML(title); + return ` + + ${title} + ${series} + ${pagesCount} +`; + } + + escapeXML(str) { + const symbols = { + '<': '<', + '>': '>', + '&': '&', + '\'': ''', + '"': '"' + }; + + return str.replace(/[<>&'"]/g, function (c) { + return symbols[c]; + }); + } +} diff --git a/src/web/mjs/engine/Settings.mjs b/src/web/mjs/engine/Settings.mjs index 9a87150f78..958365d63e 100644 --- a/src/web/mjs/engine/Settings.mjs +++ b/src/web/mjs/engine/Settings.mjs @@ -420,4 +420,4 @@ export default class Settings extends EventTarget { return value; } } -} \ No newline at end of file +} diff --git a/src/web/mjs/engine/Storage.mjs b/src/web/mjs/engine/Storage.mjs index 297610918a..d8ec1c03fa 100644 --- a/src/web/mjs/engine/Storage.mjs +++ b/src/web/mjs/engine/Storage.mjs @@ -448,7 +448,7 @@ export default class Storage { } if (Engine.Settings.chapterFormat.value === extensions.cbz) { this._createDirectoryChain(this.path.dirname(output)); - promise = this._saveChapterPagesCBZ(output, pageData) + promise = this._saveChapterPagesCBZ(output, pageData, chapter.manga.title, chapter.title) .then(() => this._runPostChapterDownloadCommand(chapter, output)); } if (Engine.Settings.chapterFormat.value === extensions.pdf) { @@ -548,8 +548,12 @@ export default class Storage { * Create and save pages to the given archive file. * Callback will be executed after completion and provided with an array of errors (or an empty array when no errors occured). */ - _saveChapterPagesCBZ(archive, pageData) { + _saveChapterPagesCBZ(archive, pageData, mangaName = '', chapterName = '') { let zip = new JSZip(); + + let comicFile = Engine.ComicInfoGenerator.createComicInfoXML(mangaName, chapterName, pageData.length); + zip.file('ComicInfo.xml', comicFile); + pageData.forEach(page => { zip.file(page.name, page.data); }); @@ -893,4 +897,4 @@ export default class Storage { }); }); } -} \ No newline at end of file +}