diff --git a/plugin/js/Library.js b/plugin/js/Library.js index 7e477883..1c02077c 100644 --- a/plugin/js/Library.js +++ b/plugin/js/Library.js @@ -565,6 +565,7 @@ class Library { // eslint-disable-line no-unused-vars let LibTemplateMetadataSubject = document.getElementById("LibTemplateMetadataSubject").innerHTML; let LibTemplateMetadataDescription = document.getElementById("LibTemplateMetadataDescription").innerHTML; let LibTemplateMetadataPublisher = document.getElementById("LibTemplateMetadataPublisher").innerHTML; + let LibTemplateMetadataCoverImageUrl = document.getElementById("LibTemplateMetadataCoverImageUrl").innerHTML; let LibRenderResult = document.getElementById("LibRenderMetadata" + objbtn.dataset.libepubid); let LibMetadata = await Library.LibGetMetadata(objbtn.dataset.libepubid); let LibRenderString = ""; @@ -604,6 +605,10 @@ class Library { // eslint-disable-line no-unused-vars LibRenderString += ""+LibTemplateMetadataPublisher+""; LibRenderString += ""; LibRenderString += ""; + LibRenderString += ""; + LibRenderString += ""+LibTemplateMetadataCoverImageUrl+""; + LibRenderString += ""; + LibRenderString += ""; LibRenderString += ""; LibRenderString += ""; LibRenderString += ""; @@ -631,7 +636,33 @@ class Library { // eslint-disable-line no-unused-vars let LibSubjectInput = document.getElementById("LibSubjectInput"+obj.dataset.libepubid).value; let LibDescriptionInput = document.getElementById("LibDescriptionInput"+obj.dataset.libepubid).value; let LibPublisherInput = document.getElementById("LibPublisherInput"+obj.dataset.libepubid).value; + let LibCoverImageUrlInput = document.getElementById("LibCoverImageUrlInput"+obj.dataset.libepubid).value; Library.LibShowLoadingText(); + + let newCoverBlob = null; + let newCoverMimeType = null; + + // Update cover image in storage if a new URL was provided + if (LibCoverImageUrlInput.trim() !== "") { + try { + let response = await fetch(LibCoverImageUrlInput); + newCoverBlob = await response.blob(); + newCoverMimeType = newCoverBlob.type; + let reader = new FileReader(); + let coverDataUrl = await new Promise((resolve, reject) => { + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsDataURL(newCoverBlob); + }); + chrome.storage.local.set({ + ["LibCover" + obj.dataset.libepubid]: coverDataUrl + }); + } catch { + // If fetching the image fails, continue with the metadata save + newCoverBlob = null; + } + } + let LibDateCreated = new EpubPacker().getDateForMetaData(); try { let EpubReader = await new zip.Data64URIReader(await Library.LibGetFromStorage("LibEpub"+obj.dataset.libepubid)); @@ -639,14 +670,104 @@ class Library { // eslint-disable-line no-unused-vars let EpubContent = await EpubZipRead.getEntries(); EpubContent = EpubContent.filter(a => a.directory == false); let opfFile = await EpubContent.filter(a => a.filename == "OEBPS/content.opf")[0].getData(new zip.TextWriter()); + + // Handle new cover embedding in EPUB + let oldCoverimgPath = null; + let newCoverimgPath = null; + let coverXhtmlFile = EpubContent.filter(a => a.filename == "OEBPS/Text/Cover.xhtml"); + + if (newCoverBlob != null) { + let extension = "jpg"; + if (newCoverMimeType && newCoverMimeType.includes("png")) { + extension = "png"; + } else if (newCoverMimeType && newCoverMimeType.includes("gif")) { + extension = "gif"; + } else if (newCoverMimeType && newCoverMimeType.includes("webp")) { + extension = "webp"; + } + + if (coverXhtmlFile.length > 0) { + try { + let Coverxml = await coverXhtmlFile[0].getData(new zip.TextWriter()); + let match = Coverxml.match(/"..\/Images\/000.+?"/); + if (match) { + oldCoverimgPath = "OEBPS" + match[0].replace(/"../, "").replace("\"", ""); + let baseName = oldCoverimgPath.substring(0, oldCoverimgPath.lastIndexOf(".")); + newCoverimgPath = baseName + "." + extension; + + let oldHref = oldCoverimgPath.replace("OEBPS/", ""); + let newHref = newCoverimgPath.replace("OEBPS/", ""); + + // Update OPF + let itemRegexStr = "]+href=\"" + oldHref.replace(/\./g, "\\.") + "\"[^>]*>"; + let itemRegex = new RegExp(itemRegexStr, "g"); + let itemMatch = opfFile.match(itemRegex); + if (itemMatch) { + let oldItem = itemMatch[0]; + let newItem = oldItem.replace(oldHref, newHref); + if (newCoverMimeType) { + newItem = newItem.replace(/media-type="[^"]+"/, "media-type=\"" + newCoverMimeType + "\""); + } + opfFile = opfFile.replace(oldItem, newItem); + } + + // Update Cover.xhtml + let oldSrc = oldHref.replace("Images/", "../Images/"); + let newSrc = newHref.replace("Images/", "../Images/"); + coverXhtmlFile[0].newXmlData = Coverxml.replace(oldSrc, newSrc); + } + } catch (e) { + // Ignore if cover modification fails + oldCoverimgPath = null; + newCoverimgPath = null; + } + } else { + // EPUB had no cover previously, inject one + newCoverimgPath = "OEBPS/Images/0000_cover." + extension; + + let newManifestItems = `\n\n\n`; + opfFile = opfFile.replace("", "" + newManifestItems); + + opfFile = opfFile.replace(/]*>/, "$&\n\n"); + + if (opfFile.includes("")) { + opfFile = opfFile.replace("", "\n\n"); + } else { + opfFile = opfFile.replace("", "\n\n\n"); + } + + opfFile = opfFile.replace(/]*>/, "$&\n\n"); + + let newCoverxml = `\n\n\n\n Cover\n\n\n
\n Cover\n
\n\n`; + + coverXhtmlFile = [{ + filename: "OEBPS/Text/Cover.xhtml", + newXmlData: newCoverxml + }]; + } + } let EpubWriter = new zip.BlobWriter("application/epub+zip"); let EpubZipWrite = new zip.ZipWriter(EpubWriter,{useWebWorkers: false,compressionMethod: 8}); //Copy Epub in NewEpub for (let element of EpubContent.filter(a => a.filename != "OEBPS/content.opf")) { + if (oldCoverimgPath != null && element.filename === oldCoverimgPath) { + continue; // Skip old image + } + if (newCoverBlob != null && element.filename === "OEBPS/Text/Cover.xhtml") { + // Original cover existed, skip adding it here (we add the modified one below) + continue; + } EpubZipWrite.add(element.filename, new zip.BlobReader(await element.getData(new zip.BlobWriter()))); } + if (newCoverBlob != null && newCoverimgPath != null) { + EpubZipWrite.add(newCoverimgPath, new zip.BlobReader(newCoverBlob)); + } + if (newCoverBlob != null && coverXhtmlFile.length > 0 && coverXhtmlFile[0].newXmlData) { + EpubZipWrite.add(coverXhtmlFile[0].filename, new zip.TextReader(coverXhtmlFile[0].newXmlData)); + } + let regex1 = opfFile.match(new RegExp(".+?", "gs")); if ( regex1 == null) { ErrorLog.showErrorMessage(UIText.Error.errorEditMetadata); diff --git a/plugin/popup.html b/plugin/popup.html index 5a73dfb9..846625c8 100644 --- a/plugin/popup.html +++ b/plugin/popup.html @@ -244,6 +244,9 @@

Instructions

__MSG_label_Metadata_publisher__ + + __MSG_label_Cover_Image_URL__ +