Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions plugin/js/Library.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "";
Expand Down Expand Up @@ -604,6 +605,10 @@ class Library { // eslint-disable-line no-unused-vars
LibRenderString += "<td>"+LibTemplateMetadataPublisher+"</td>";
LibRenderString += "<td colspan='2'><input id='LibPublisherInput"+objbtn.dataset.libepubid+"' type='text'></input></td>";
LibRenderString += "</tr>";
LibRenderString += "<tr id='LibRenderMetadataCoverImageUrl"+objbtn.dataset.libepubid+"'>";
LibRenderString += "<td>"+LibTemplateMetadataCoverImageUrl+"</td>";
LibRenderString += "<td colspan='2'><input id='LibCoverImageUrlInput"+objbtn.dataset.libepubid+"' type='url' placeholder='https://...'></input></td>";
LibRenderString += "</tr>";
LibRenderString += "</tbody>";
LibRenderString += "</table>";
LibRenderString += "</div>";
Expand Down Expand Up @@ -631,22 +636,138 @@ 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));
let EpubZipRead = new zip.ZipReader(EpubReader, {useWebWorkers: false});
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 = "<item[^>]+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<item id="cover" href="Text/Cover.xhtml" media-type="application/xhtml+xml"/>\n<item id="cover_img" href="Images/0000_cover.${extension}" media-type="${newCoverMimeType || "image/jpeg"}"/>\n`;
opfFile = opfFile.replace("<manifest>", "<manifest>" + newManifestItems);

opfFile = opfFile.replace(/<spine[^>]*>/, "$&\n<itemref idref=\"cover\"/>\n");

if (opfFile.includes("<guide>")) {
opfFile = opfFile.replace("<guide>", "<guide>\n<reference href=\"Text/Cover.xhtml\" title=\"Cover\" type=\"cover\"/>\n");
} else {
opfFile = opfFile.replace("</package>", "<guide>\n<reference href=\"Text/Cover.xhtml\" title=\"Cover\" type=\"cover\"/>\n</guide>\n</package>");
}

opfFile = opfFile.replace(/<metadata[^>]*>/, "$&\n<meta name=\"cover\" content=\"cover_img\"/>\n");

let newCoverxml = `<?xml version="1.0" encoding="utf-8"?>\n<!DOCTYPE html>\n<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">\n<head>\n <title>Cover</title>\n</head>\n<body>\n <div style="text-align: center; padding: 0pt; margin: 0pt;">\n <img src="../Images/0000_cover.${extension}" alt="Cover" />\n </div>\n</body>\n</html>`;

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("<dc:title>.+?</dc:creator>", "gs"));
if ( regex1 == null) {
ErrorLog.showErrorMessage(UIText.Error.errorEditMetadata);
Expand Down
3 changes: 3 additions & 0 deletions plugin/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ <h3>Instructions</h3>
<tr>
<td id="LibTemplateMetadataPublisher">__MSG_label_Metadata_publisher__</td>
</tr>
<tr>
<td id="LibTemplateMetadataCoverImageUrl">__MSG_label_Cover_Image_URL__</td>
</tr>
</tbody>
</table>
</div>
Expand Down
Loading