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.
86 lines
2.5 KiB
JavaScript
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();
|