Skip to content

Instantly share code, notes, and snippets.

@crutch12
Forked from markflorkowski/gist:4269bc529324dceb2858c77b7609704c
Last active October 20, 2024 15:36
Show Gist options
  • Save crutch12/a43178a7c45d2dc8ecfbbcb05a9246e3 to your computer and use it in GitHub Desktop.
Save crutch12/a43178a7c45d2dc8ecfbbcb05a9246e3 to your computer and use it in GitHub Desktop.
ReplicateUI
// ==UserScript==
// @name Donwload Site (ReplicateUI)
// @namespace http://tampermonkey.net/
// @version 2024-09-26
// @description https://gist.github.com/crutch12/a43178a7c45d2dc8ecfbbcb05a9246e3
// @author @crutch12
// @match https://*/*
// @icon https://cdn-icons-png.freepik.com/512/489/489707.png
// @grant none
// ==/UserScript==
(function() {
'use strict';
document.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.altKey && event.key === 's') {
console.log('Ctrl + Alt + S was pressed. run downloadCompleteHTML()');
// You can add your custom logic here
downloadCompleteHTML().catch(err => {
console.error(err)
alert(err.message)
})
}
});
// Your code here...
// source: https://gist.github.com/markflorkowski/4269bc529324dceb2858c77b7609704c
async function downloadCompleteHTML() {
// Helper function to fetch content of external files (CSS, JS, images)
async function fetchResource(url, isBinary = false) {
try {
const response = await fetch(url);
if (isBinary) {
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
} else {
return await response.text();
}
} catch (error) {
console.warn('Failed to fetch resource:', url);
return '';
}
}
// Helper function to inline external CSS and convert relative URLs to absolute
async function inlineCSS(linkElement) {
const href = linkElement.href;
const cssContent = await fetchResource(href);
// Resolve relative URLs within CSS (for images, fonts, etc.)
const resolvedCSS = cssContent.replace(/url\((?!['"]?(?:data|https?|ftp):)['"]?([^'")]+)['"]?\)/g, function(match, relativeUrl) {
try {
const absoluteUrl = new URL(relativeUrl, href).href;
return `url(${absoluteUrl})`;
}
catch (err) {
console.warn('Failed to generate url:', relativeUrl);
return ''
}
});
// Create a <style> tag with the inlined CSS
const styleElement = document.createElement('style');
styleElement.textContent = resolvedCSS;
return styleElement;
}
// Helper function to convert images to base64-encoded data URIs
async function inlineImages(element) {
const images = element.querySelectorAll('img');
for (let img of images) {
if (img.src.startsWith('http')) {
const dataUri = await fetchResource(img.src, true);
img.src = dataUri; // Replace the src with base64-encoded data URI
}
}
}
// Get the entire DOM HTML structure
const html = document.documentElement.outerHTML;
// Create a new document to parse and modify the HTML content
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
// Inline all external CSS files
const linkElements = [...doc.querySelectorAll('link[rel="stylesheet"]')];
for (let link of linkElements) {
const inlineStyleElement = await inlineCSS(link);
link.replaceWith(inlineStyleElement);
}
// Inline all images as base64 data URIs
await inlineImages(doc);
// Get the final HTML including the modified DOM
const finalHTML = doc.documentElement.outerHTML;
// Create a downloadable HTML file
const downloadHTML = (content, fileName) => {
const a = document.createElement("a");
const file = new Blob([content], { type: "text/html" });
a.href = URL.createObjectURL(file);
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
// Download the final HTML file
downloadHTML(finalHTML, "index.html");
// Hide loading overlay
// loadingOverlay.style.display = 'none';
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment