From 16da0dffaf63932e578ff707d32b3899519a1193 Mon Sep 17 00:00:00 2001 From: Aryan Mane <146648718+ARYAN-9099@users.noreply.github.com> Date: Thu, 30 Jul 2026 23:43:59 +0530 Subject: [PATCH 1/3] Edit image URL for existing books in library #2792 --- plugin/js/Library.js | 26 ++++++++++++++++++++++++++ plugin/popup.html | 3 +++ 2 files changed, 29 insertions(+) diff --git a/plugin/js/Library.js b/plugin/js/Library.js index 7e477883..4bbbce00 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,28 @@ 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(); + + // Update cover image in storage if a new URL was provided + if (LibCoverImageUrlInput.trim() !== "") { + try { + let response = await fetch(LibCoverImageUrlInput); + let blob = await response.blob(); + let reader = new FileReader(); + let coverDataUrl = await new Promise((resolve, reject) => { + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsDataURL(blob); + }); + chrome.storage.local.set({ + ["LibCover" + obj.dataset.libepubid]: coverDataUrl + }); + } catch { + // If fetching the image fails, continue with the metadata save + } + } + let LibDateCreated = new EpubPacker().getDateForMetaData(); try { let EpubReader = await new zip.Data64URIReader(await Library.LibGetFromStorage("LibEpub"+obj.dataset.libepubid)); 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__ + From 5d9f181204a2e2367e4291c3067c8b191629a035 Mon Sep 17 00:00:00 2001 From: Aryan Mane <146648718+ARYAN-9099@users.noreply.github.com> Date: Fri, 31 Jul 2026 01:55:35 +0530 Subject: [PATCH 2/3] fix: change image in the ebook --- plugin/js/Library.js | 73 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/plugin/js/Library.js b/plugin/js/Library.js index 4bbbce00..cfed9622 100644 --- a/plugin/js/Library.js +++ b/plugin/js/Library.js @@ -639,22 +639,27 @@ class Library { // eslint-disable-line no-unused-vars 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); - let blob = await response.blob(); + 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(blob); + 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; } } @@ -665,12 +670,74 @@ 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 && 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 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"; + } + + 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; + } + } 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")) { - EpubZipWrite.add(element.filename, new zip.BlobReader(await element.getData(new zip.BlobWriter()))); + if (oldCoverimgPath != null && element.filename === oldCoverimgPath) { + continue; // Skip old image + } + if (newCoverBlob != null && element.filename === "OEBPS/Text/Cover.xhtml" && coverXhtmlFile[0].newXmlData) { + EpubZipWrite.add(element.filename, new zip.TextReader(coverXhtmlFile[0].newXmlData)); + } else { + 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)); } let regex1 = opfFile.match(new RegExp(".+?", "gs")); From 6aa51376c82086a51e0911736b2d4698b4201fc4 Mon Sep 17 00:00:00 2001 From: Aryan Mane <146648718+ARYAN-9099@users.noreply.github.com> Date: Sun, 2 Aug 2026 11:20:11 +0530 Subject: [PATCH 3/3] fix: update cover image handling in EPUB files --- plugin/js/Library.js | 116 +++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 44 deletions(-) diff --git a/plugin/js/Library.js b/plugin/js/Library.js index cfed9622..1c02077c 100644 --- a/plugin/js/Library.js +++ b/plugin/js/Library.js @@ -675,50 +675,75 @@ class Library { // eslint-disable-line no-unused-vars let oldCoverimgPath = null; let newCoverimgPath = null; let coverXhtmlFile = EpubContent.filter(a => a.filename == "OEBPS/Text/Cover.xhtml"); - if (newCoverBlob != null && 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 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"; - } - - let baseName = oldCoverimgPath.substring(0, oldCoverimgPath.lastIndexOf(".")); - newCoverimgPath = baseName + "." + extension; + + 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"; + } - 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 + "\""); + 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); } - 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); } - - // 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; } - } 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 + }]; } } @@ -729,16 +754,19 @@ class Library { // eslint-disable-line no-unused-vars if (oldCoverimgPath != null && element.filename === oldCoverimgPath) { continue; // Skip old image } - if (newCoverBlob != null && element.filename === "OEBPS/Text/Cover.xhtml" && coverXhtmlFile[0].newXmlData) { - EpubZipWrite.add(element.filename, new zip.TextReader(coverXhtmlFile[0].newXmlData)); - } else { - EpubZipWrite.add(element.filename, new zip.BlobReader(await element.getData(new zip.BlobWriter()))); + 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) {