From aec05d63db9a58a2df90cbef1fee0cafd811b1a8 Mon Sep 17 00:00:00 2001 From: elioat Date: Sat, 15 Mar 2025 21:00:44 -0400 Subject: * --- html/web-font-vacuum/app.js | 87 +++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 62 deletions(-) (limited to 'html') diff --git a/html/web-font-vacuum/app.js b/html/web-font-vacuum/app.js index e34c519..b1aada2 100644 --- a/html/web-font-vacuum/app.js +++ b/html/web-font-vacuum/app.js @@ -1,18 +1,17 @@ /** - * Web Font Vacuum - A tool to find and extract web fonts from any website + * An Immoral Web Font Vacuum + * A tool to find and extract web fonts from any website * - * Architecture Overview: - * This app follows a pipeline pattern where each step processes the data and passes it to the next: - * 1. URL Input → 2. Fetch HTML → 3. Parse & Extract → 4. Process CSS → 5. Display Results + * We sort of set up a pipeline where each step processes the data and passes it to the next: + * 1. URL Input > 2. Fetch HTML > 3. Parse & Extract > 4. Process CSS > 5. Display Results * - * The app uses multiple CORS proxies with a fallback system to handle cross-origin requests, - * and implements a font preview system using the FontFace API. */ /** + * Proxy List + * Proxies are buggy, and temperamental...so why not use a whole lot of them! * List of CORS proxies we can try if the main one fails. - * We keep track of the last working proxy to optimize future requests. - * Each proxy has a name, base URL, and a formatter function to construct the full URL. + * Keeps track of the last working proxy to optimize future requests. * @type {Array<{name: string, url: string, urlFormatter: (url: string) => string}>} */ const CORS_PROXIES = [ @@ -46,7 +45,6 @@ const CORS_PROXIES = [ // Keep track of which proxy worked last let lastWorkingProxyIndex = 0; -// Helper function to try multiple proxies async function fetchWithProxies(url, attempt = 0, isBinary = false) { // Start with the last working proxy const startIndex = lastWorkingProxyIndex; @@ -73,7 +71,6 @@ async function fetchWithProxies(url, attempt = 0, isBinary = false) { const response = await fetch(proxy.urlFormatter(url), fetchOptions); if (response.ok) { - // Remember this working proxy for next time lastWorkingProxyIndex = proxyIndex; return response; } @@ -83,11 +80,11 @@ async function fetchWithProxies(url, attempt = 0, isBinary = false) { } } - // If we get here, all proxies failed + // DO NOT PASS GO! DO NOT COLLECT $200 DOLLARS + // All proxies failed throw new Error('All proxies failed to fetch the resource'); } -// Function to handle font downloading async function downloadFont(url, filename) { try { console.log('Downloading font from:', url); @@ -101,13 +98,12 @@ async function downloadFont(url, filename) { // Convert ArrayBuffer to Blob with proper MIME type const blob = new Blob([arrayBuffer], { type: getFontMimeType(url) }); - // Create a temporary link to trigger the download + // Temporary link to trigger the download const objectUrl = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = objectUrl; link.download = filename; - // Append to body, click, and remove document.body.appendChild(link); link.click(); @@ -125,7 +121,7 @@ async function downloadFont(url, filename) { } } -// Helper function to determine MIME type based on font URL +// Assume the MIME type based on the file's extension function getFontMimeType(url) { const extension = url.split('.').pop().toLowerCase().split('?')[0]; switch (extension) { @@ -143,12 +139,10 @@ function getFontMimeType(url) { } /** - * Main application entry point. Sets up event listeners and initializes the app. - * This is where everything kicks off when the page loads. + * Sets up event listeners and initializes the app. * - * The app follows this general flow: * 1. User enters URL and clicks Analyze - * 2. We fetch the HTML through a CORS proxy + * 2. Fetch the HTML through a CORS proxy * 3. Parse HTML to find: * - Direct font links * - Stylesheet links @@ -161,15 +155,11 @@ document.addEventListener('DOMContentLoaded', () => { const analyzeBtn = document.getElementById('analyzeBtn'); const resultsDiv = document.getElementById('results'); const errorDiv = document.getElementById('error'); - - // Sample text for font preview - const PREVIEW_TEXT = 'The quick brown fox jumps over the lazy dog 0123456789'; /** - * Handles the font preview functionality using the FontFace API. - * We try two different methods to load the font: - * 1. First attempt: Using a data URL - * 2. Fallback: Using a blob URL if data URL fails + * Two different methods to load the font: + * - Using a data URL + * - Fallback: Using a blob URL if data URL fails * * @param {string} url - The URL of the font file to preview * @param {string} fontFamily - The font-family name to use @@ -196,14 +186,12 @@ document.addEventListener('DOMContentLoaded', () => { try { const dataUrl = reader.result; - // Create and load the font const fontFace = new FontFace(fontFamily, `url(${dataUrl})`, { style: 'normal', weight: '400', display: 'swap' }); - // Load the font into the document const loadedFont = await fontFace.load(); document.fonts.add(loadedFont); @@ -245,10 +233,8 @@ document.addEventListener('DOMContentLoaded', () => { } /** - * Main click handler for the Analyze button. - * This is the heart of the application - it orchestrates the entire font discovery process. + * Click handler for the Analyze button. * - * Process Flow: * 1. Validate input URL * 2. Fetch and parse webpage * 3. Look for fonts in: @@ -270,7 +256,7 @@ document.addEventListener('DOMContentLoaded', () => { errorDiv.style.display = 'none'; // Show loading state - resultsDiv.innerHTML = '

Analyzing webpage, please wait...

'; + resultsDiv.innerHTML = '

Analyzing webpage. Sometimes this takes a while.

'; // Fetch the target webpage through the proxy system const response = await fetchWithProxies(url); @@ -287,7 +273,7 @@ document.addEventListener('DOMContentLoaded', () => { const baseUrlObj = new URL(url); const domain = baseUrlObj.origin; - // Check common font directories + // Brute force common font paths, for scenarios where the font is not found in the css const commonFontPaths = [ '/assets/fonts/', '/fonts/', @@ -374,8 +360,7 @@ document.addEventListener('DOMContentLoaded', () => { }); /** - * Processes a CSS URL to extract font information. - * This is called for each external stylesheet found in the HTML. + * Processes a the URL of a CSS file to extract font information. * * @param {string} cssUrl - The URL of the CSS file to process * @param {Set} fontUrls - Set to store found font URLs @@ -388,15 +373,13 @@ document.addEventListener('DOMContentLoaded', () => { const css = await response.text(); // Use the CSS URL as the base URL for resolving font URLs - extractFontUrlsFromCss(css, cssUrl, fontUrls); } catch (error) { console.error(`Error processing CSS from ${cssUrl}:`, error); } } /** - * Extracts font URLs from CSS content using regex. - * This is our CSS parser - it looks for @font-face rules and extracts: + * Extracts font URLs from CSS by the power of regex. * - Font URLs * - Font family names * - Full CSS rules for reference @@ -406,7 +389,6 @@ document.addEventListener('DOMContentLoaded', () => { * @param {Set} fontUrls - Set to store found font URLs */ function extractFontUrlsFromCss(css, baseUrl, fontUrls) { - // Regular expression to match @font-face rules const fontFaceRegex = /@font-face\s*{[^}]*}/g; const urlRegex = /url\(['"]?([^'"\)]+)['"]?\)/g; const fontFamilyRegex = /font-family\s*:\s*['"]?([^'";]+)['"]?/; @@ -434,9 +416,7 @@ document.addEventListener('DOMContentLoaded', () => { // Extract font-family name const familyMatch = rule.match(fontFamilyRegex); - const familyName = familyMatch ? familyMatch[1].trim() : 'Unknown Font'; - - // Clean up the CSS rule for display + const familyName = familyMatch ? familyMatch[1].trim() : 'Unknown Font'; const cleanRule = rule.replace(/\s+/g, ' ').trim(); urls.forEach(url => { @@ -470,7 +450,7 @@ document.addEventListener('DOMContentLoaded', () => { } /** - * Looks for direct font links in HTML. + * Find direct font links in HTML. * Checks two types of links: * 1. Preload links with as="font" * 2. Regular tags pointing to font files @@ -534,10 +514,8 @@ document.addEventListener('DOMContentLoaded', () => { } /** - * Displays the found fonts in a user-friendly way. - * This is our view layer - it creates all the UI elements for each font. - * - * Features: + * The V of MVC + * * - Auto-preview for 3 or fewer fonts * - Manual preview toggle for 4+ fonts * - Download buttons @@ -563,7 +541,6 @@ document.addEventListener('DOMContentLoaded', () => { container.style.maxWidth = '800px'; container.style.margin = '0 auto'; - // Convert urls Set to Array for length check and iteration const fontsArray = Array.from(urls); const shouldAutoPreview = fontsArray.length < 4; @@ -574,7 +551,6 @@ document.addEventListener('DOMContentLoaded', () => { fontItem.style.background = 'var(--beige)'; fontItem.style.position = 'relative'; - // Add accent bar at the top const accentBar = document.createElement('div'); accentBar.style.position = 'absolute'; accentBar.style.top = '0'; @@ -584,7 +560,6 @@ document.addEventListener('DOMContentLoaded', () => { accentBar.style.background = 'var(--accent)'; fontItem.appendChild(accentBar); - // Font info section const fontInfo = document.createElement('div'); fontInfo.style.marginTop = '0.5rem'; @@ -630,7 +605,6 @@ document.addEventListener('DOMContentLoaded', () => { fontInfo.appendChild(ruleContainer); } - // Preview section const previewContainer = document.createElement('div'); previewContainer.style.marginTop = '1rem'; previewContainer.style.padding = '1rem'; @@ -653,7 +627,6 @@ document.addEventListener('DOMContentLoaded', () => { preview.textContent = 'The quick brown fox jumps over the lazy dog 0123456789'; previewContainer.appendChild(preview); - // Size variations const sizeVariations = document.createElement('div'); sizeVariations.style.borderTop = '1px solid var(--dark)'; sizeVariations.style.paddingTop = '0.5rem'; @@ -668,20 +641,17 @@ document.addEventListener('DOMContentLoaded', () => { previewContainer.appendChild(sizeVariations); - // Button container const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.gap = '0.5rem'; buttonContainer.style.marginTop = '1rem'; - // Download button const downloadBtn = document.createElement('button'); downloadBtn.textContent = '⬇ Download'; downloadBtn.style.flex = '1'; downloadBtn.addEventListener('click', () => downloadFont(fontData.url, fontData.filename)); buttonContainer.appendChild(downloadBtn); - // Preview button (only for 5 or more fonts) if (!shouldAutoPreview) { const previewBtn = document.createElement('button'); previewBtn.textContent = '👁 Preview'; @@ -717,7 +687,6 @@ document.addEventListener('DOMContentLoaded', () => { fontItem.appendChild(buttonContainer); container.appendChild(fontItem); - // Auto-preview for fewer than 4 fonts if (shouldAutoPreview) { // Use setTimeout to ensure the DOM is ready setTimeout(async () => { @@ -735,12 +704,6 @@ document.addEventListener('DOMContentLoaded', () => { resultsDiv.appendChild(container); } - /** - * Shows an error message to the user. - * We use this for any user-facing errors during the process. - * - * @param {string} message - The error message to display - */ function showError(message) { errorDiv.textContent = message; errorDiv.style.display = 'block'; -- cgit 1.4.1-2-gfad0