reilly-downloader/index.js
Joey Yakimowich-Payne 7a44902433 feat: surface detailed download progress
Changelog:
- forward download progress from background/offscreen workers to content frames
- add progress UI and button state management in Safari Books page script
- emit structured progress callbacks and faster image fetching in SafariBooksDownloader
- sync Firefox bundle with progress plumbing and concurrency improvements
- ignore packaged extension archives

Description:
Expose progress events through the downloader so the content script can present real-time status, including chapter and asset fetching milestones. Added concurrency controls, page detection, and packaging telemetry, while keeping Firefox build behavior in sync and ignoring generated .xpi bundles.
2025-10-16 10:30:18 -06:00

86 lines
2.5 KiB
JavaScript

import { SafariBooksDownloader } from "./safaribooks/downloader.js";
import { collectSessionCookies } from "./safaribooks/cookies.js";
const form = document.getElementById("download-form");
const bookIdInput = document.getElementById("book-id");
const themeSelect = document.getElementById("theme");
const kindleCheckbox = document.getElementById("kindle");
const logView = document.getElementById("log");
const downloadButton = document.getElementById("start-download");
function appendLog(message) {
const timestamp = new Date().toLocaleTimeString();
logView.textContent += `[${timestamp}] ${message}\n`;
logView.scrollTop = logView.scrollHeight;
}
const downloader = new SafariBooksDownloader(appendLog);
function setDisabled(disabled) {
downloadButton.disabled = disabled;
bookIdInput.disabled = disabled;
themeSelect.disabled = disabled;
kindleCheckbox.disabled = disabled;
}
function extractBookIdFromUrl(url) {
try {
const { pathname } = new URL(url);
const segments = pathname.split("/").filter(Boolean).reverse();
return segments.find((segment) => /^[0-9]{9,}$/.test(segment)) || null;
} catch (_) {
return null;
}
}
async function detectActiveBook() {
if (!chrome.tabs?.query) {
return;
}
try {
const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!activeTab?.url || !activeTab.url.includes("/library/view/")) {
return;
}
const detectedBookId = extractBookIdFromUrl(activeTab.url);
if (!detectedBookId) {
return;
}
if (bookIdInput.value !== detectedBookId) {
bookIdInput.value = detectedBookId;
appendLog(`Detected book ID ${detectedBookId} from the active tab.`);
}
} catch (error) {
console.warn("SafariBooks Downloader: unable to detect active book.", error);
}
}
form.addEventListener("submit", async (event) => {
event.preventDefault();
const bookId = bookIdInput.value.trim();
if (!bookId) {
appendLog("Please enter a book ID.");
return;
}
setDisabled(true);
appendLog("Verifying O'Reilly session...");
try {
const session = await collectSessionCookies();
appendLog(`Session OK (cookies detected: ${session.count}).`);
appendLog(`Starting EPUB download for ${bookId}...`);
await downloader.download(bookId, {
theme: themeSelect.value,
kindle: kindleCheckbox.checked
});
appendLog("Download completed.");
} catch (error) {
console.error(error);
appendLog(`Download failed: ${error.message}`);
} finally {
setDisabled(false);
}
});
detectActiveBook();