🏠 Home 

Adobe Fonts Downloader

Adds a download button to Adobe Fonts.

// ==UserScript==
// @name         Adobe Fonts Downloader
// @description  Adds a download button to Adobe Fonts.
// @icon         https://badnoise.net/TypeRip/favicon.png
// @version      1.3
// @author       afkarxyz
// @namespace    https://github.com/afkarxyz/misc-scripts/
// @supportURL   https://github.com/afkarxyz/misc-scripts/issues
// @license      MIT
// @match        https://fonts.adobe.com/*
// @match        https://badnoise.net/TypeRip/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        window.close
// @run-at       document-end
// ==/UserScript==
(function() {
'use strict';
if (window.location.hostname === 'badnoise.net') {
const adobeUrl = GM_getValue('adobeFontUrl', '');
if (adobeUrl) {
GM_setValue('adobeFontUrl', '');
const waitForElement = (selector) => {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
observer.disconnect();
resolve(document.querySelector(selector));
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
};
Promise.all([
waitForElement('#url_input'),
waitForElement('#url_submit_button')
]).then(([urlInput, submitButton]) => {
urlInput.value = adobeUrl;
urlInput.dispatchEvent(new Event('input', { bubbles: true }));
submitButton.click();
});
}
return;
}
function getFullFontUrl(href) {
if (!href) return '';
if (href.startsWith('http')) return href;
return `https://fonts.adobe.com${href}`;
}
function createDownloadButton(originalButton) {
const newButton = originalButton.cloneNode(true);
originalButton.parentNode.replaceChild(newButton, originalButton);
const labelSpan = newButton.querySelector('.spectrum-Button-label, .add-family-label');
if (labelSpan) {
labelSpan.textContent = 'Download';
}
newButton.removeAttribute('ng-click');
newButton.removeAttribute('ng-show');
newButton.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
let fontUrl = '';
const cardLink = newButton.closest('.adobe-fonts-family-card')?.querySelector('.adobe-fonts-family-card--link');
if (cardLink) {
fontUrl = getFullFontUrl(cardLink.getAttribute('href'));
} else {
fontUrl = window.location.href;
}
GM_setValue('adobeFontUrl', fontUrl);
window.open('https://badnoise.net/TypeRip/', '_blank');
});
return newButton;
}
function modifyButtons() {
const buttons = document.querySelectorAll([
'.adobe-fonts-family__top-actions-add-family button',
'button[ng-click*="useModelSyncFontpack"]',
'.collection-show__font-pack-actions-bottom button.add-family-button',
'.add-family-button'
].join(','));
buttons.forEach(button => {
if (button.hasAttribute('data-modified')) return;
const newButton = createDownloadButton(button);
newButton.setAttribute('data-modified', 'true');
});
}
function changeTextToDownload(node) {
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.classList.contains('add-family-button') && !node.hasAttribute('data-modified')) {
const newButton = createDownloadButton(node);
newButton.setAttribute('data-modified', 'true');
}
if (node.shadowRoot) {
changeTextToDownload(node.shadowRoot);
}
node.childNodes.forEach(child => changeTextToDownload(child));
}
}
function init() {
modifyButtons();
changeTextToDownload(document.body);
}
init();
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
const currentUrl = location.href;
if (window.lastUrl !== currentUrl) {
window.lastUrl = currentUrl;
init();
continue;
}
const addedNodes = Array.from(mutation.addedNodes);
const hasNewButton = addedNodes.some(node =>
node.querySelector && (
node.querySelector('.adobe-fonts-family__top-actions-add-family') ||
node.querySelector('button[ng-click*="useModelSyncFontpack"]') ||
node.querySelector('.collection-show__font-pack-actions-bottom') ||
node.querySelector('.add-family-button')
)
);
if (hasNewButton) {
init();
break;
}
addedNodes.forEach(changeTextToDownload);
}
});
window.lastUrl = location.href;
observer.observe(document.body, {
childList: true,
subtree: true
});
})();