/* globals waitForKeyElements */
// ==UserScript==
// @name DDB Book Downloader
// @namespace http://tampermonkey.net/
// @version 0.1.9
// @description Save your DBB books to PDF!
// @author rsminsmith (Adapted from C T Zaran, print styling from /u/Ninjaen37)
// @match https://www.dndbeyond.com/sources/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=dndbeyond.com
// @grant none
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
const minPageDelay = 0; // Time to wait between each page. Increase if you're getting bot detected
const maxPageDelay = 0;
let bookHTML = '';
// Get necessary URL components
const slug = document.location.pathname;
const urlParts = slug.split('/');
if (urlParts[1] != 'sources') {
console.info('DNDBeyondPdf: Not a source page');
return;
}
// If this is a subpage, only worry about indexing it
const tocHeaderEl = document.querySelector('.compendium-toc-full-header');
if (!tocHeaderEl) {
console.info('DNDBeyondPdf: Not a ToC page, ignoring');
return;
}
// Build helper container and button elements
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'inline-block';
buttonContainer.style.float = 'right';
// Build buttons
const resetButton = document.createElement('button');
resetButton.classList.add('reset-pdf');
resetButton.textContent = 'Reset Cache';
resetButton.type = 'button';
const pdfButton = document.createElement('button');
pdfButton.classList.add('generate-pdf');
pdfButton.textContent = 'Generate PDF';
pdfButton.type = 'button';
// Spelljammer has 3 books on one page; need to export them individually
if (slug === '/sources/sais') {
buttonContainer.style.backgroundColor = 'yellow';
buttonContainer.style.color = 'black';
buttonContainer.style.padding = '0.5em';
buttonContainer.textContent = 'Navigate to each book within Spelljammer to generate PDF';
} else {
// Otherwise append generate and reset buttons
buttonContainer.append(pdfButton);
buttonContainer.append(resetButton);
}
// Attach buttons to header
tocHeaderEl.prepend(buttonContainer);
// Handle PDF generation
pdfButton.onclick = async function() {
// Update the button
pdfButton.textContent = 'Generating...';
pdfButton.disabled = true;
// Only fetch data if needed
if (!bookHTML) {
// Get book info
const bookTitle = document.title;
// Pull all links in ToC and filter out the ones that aren't needed
let tocLinkEls = document.querySelectorAll('.compendium-toc-full-text a');
let validPages = [];
let pageNames = {};
for (const a of tocLinkEls) {
let href = a.href.replace(/#.*$/, ''); // remove the fragment from the url if any.
if (validPages.includes(href)) continue; // skip duplicates
validPages.push(href);
pageNames[href] = a.textContent;
}
// Create initial page HTML
bookHTML = '' +
''+
'