A Virgin’s Wish – part 1

Published On: December 2, 2025
To view this content, you must be a member of ExperienceLawd's Patreon at $6.5 or more
Already a qualifying Patreon member? Refresh to access this content.

One thought on “A Virgin’s Wish – part 1

  1. Nice

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    *

    *

    *

// So checking parentNode. if (comicSelect.parentNode.classList.contains('comic-series-selector')) { comicSelect.parentNode.appendChild(btnContainer); } else { // Fallback for select without wrapper comicSelect.parentNode.insertBefore(btnContainer, comicSelect.nextSibling); } } else { // Fallback if no select: Insert before the comic container splicedComic.parentNode.insertBefore(btnContainer, splicedComic); } // --- Zip Functionality --- btnZip.addEventListener('click', async function () { const originalText = btnZip.innerText; btnZip.innerText = 'Generating Zip...'; btnZip.disabled = true; try { const zip = new JSZip(); // Use validImages defined in outer scope const promises = validImages.map(async (img, index) => { if (!img.src) return; try { // Bypass CORS if needed (assuming same origin or CORS headers present) const response = await fetch(img.src); const blob = await response.blob(); // Guess extension let ext = 'jpg'; const type = blob.type; if (type === 'image/png') ext = 'png'; else if (type === 'image/jpeg') ext = 'jpg'; else if (type === 'image/webp') ext = 'webp'; // Pad index for correct sorting const filename = `page-${String(index + 1).padStart(3, '0')}.${ext}`; zip.file(filename, blob); } catch (err) { console.error('Error fetching image:', img.src, err); } }); await Promise.all(promises); const content = await zip.generateAsync({ type: "blob" }); // Trigger download const url = URL.createObjectURL(content); const a = document.createElement('a'); a.href = url; a.download = getCleanFilename('zip'); document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } catch (e) { console.error("Zip generation failed:", e); alert("Failed to generate zip file."); } finally { btnZip.innerText = originalText; btnZip.disabled = false; } }); // --- PDF Functionality --- btnPdf.addEventListener('click', async function () { const originalText = btnPdf.innerText; btnPdf.innerText = 'Generating PDF...'; btnPdf.disabled = true; try { const { jsPDF } = window.jspdf; const doc = new jsPDF(); // Use validImages defined in outer scope for (let i = 0; i < validImages.length; i++) { const img = validImages[i]; if (!img.src) continue; // Fetch image const response = await fetch(img.src); const blob = await response.blob(); // Convert to Base64 const base64 = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(blob); }); // Get dimensions const imgProps = doc.getImageProperties(base64); const pdfWidth = doc.internal.pageSize.getWidth(); const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; if (i > 0) { doc.addPage(); } doc.addImage(base64, 'JPEG', 0, 0, pdfWidth, pdfHeight); } doc.save(getCleanFilename('pdf')); } catch (e) { console.error("PDF generation failed:", e); alert("Failed to generate PDF file."); } finally { btnPdf.innerText = originalText; btnPdf.disabled = false; } }); } });