Skip to content

Instantly share code, notes, and snippets.

@hargup
Created January 31, 2025 04:39
Show Gist options
  • Save hargup/0c1b0d761c44a9f069ea67fea040f424 to your computer and use it in GitHub Desktop.
Save hargup/0c1b0d761c44a9f069ea67fea040f424 to your computer and use it in GitHub Desktop.
// Function to check if a URL is broken and replace with Wayback Machine version
async function getWaybackUrl(url) {
const waybackUrl = `https://archive.org/wayback/available?url=${encodeURIComponent(url)}`;
try {
const waybackResponse = await fetch(waybackUrl);
const data = await waybackResponse.json();
// Check if there's an archived version available
if (data.archived_snapshots?.closest?.url) {
return data.archived_snapshots.closest.url;
}
return null;
} catch (error) {
console.error('Error checking Wayback Machine:', error);
return null;
}
}
// Function to check if a URL is accessible
async function isUrlAccessible(url) {
try {
const response = await fetch(url, { method: 'HEAD' });
return response.ok;
} catch (error) {
return false;
}
}
// Function to replace broken links
async function replaceWithWaybackLink(url) {
if (await isUrlAccessible(url)) {
return url;
}
const waybackUrl = await getWaybackUrl(url);
return waybackUrl || url;
}
// Function to handle broken images
function handleBrokenImage(img) {
// Only process if not already being handled
if (!img.dataset.beingProcessed) {
img.dataset.beingProcessed = 'true';
const originalSrc = img.src;
getWaybackUrl(originalSrc).then(waybackUrl => {
if (waybackUrl) {
img.src = waybackUrl;
img.setAttribute('data-original-src', originalSrc);
img.classList.add('wayback-replaced');
}
}).finally(() => {
delete img.dataset.beingProcessed;
});
}
}
// Function to replace all broken links and images in a webpage
async function replaceAllBrokenContent() {
// Handle links
const links = document.getElementsByTagName('a');
for (const link of links) {
const originalUrl = link.href;
if (originalUrl && !originalUrl.startsWith('javascript:')) {
const newUrl = await replaceWithWaybackLink(originalUrl);
if (newUrl !== originalUrl) {
link.href = newUrl;
link.setAttribute('data-original-url', originalUrl);
link.classList.add('wayback-replaced');
}
}
}
// Handle images
const images = document.getElementsByTagName('img');
for (const img of images) {
// Set up error handler for images
img.onerror = () => handleBrokenImage(img);
// Also check current images
if (!img.complete || img.naturalHeight === 0) {
handleBrokenImage(img);
}
}
}
// Function to observe DOM changes and handle new content
function observeContentChanges() {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
// Handle new links
if (node.tagName === 'A') {
replaceWithWaybackLink(node.href).then(newUrl => {
if (newUrl !== node.href) {
node.href = newUrl;
node.setAttribute('data-original-url', node.href);
node.classList.add('wayback-replaced');
}
});
}
// Handle new images
if (node.tagName === 'IMG') {
node.onerror = () => handleBrokenImage(node);
if (!node.complete || node.naturalHeight === 0) {
handleBrokenImage(node);
}
}
// Check for nested elements
const links = node.getElementsByTagName('a');
const images = node.getElementsByTagName('img');
Array.from(links).forEach(link => replaceAllBrokenContent());
Array.from(images).forEach(img => {
img.onerror = () => handleBrokenImage(img);
if (!img.complete || img.naturalHeight === 0) {
handleBrokenImage(img);
}
});
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// CSS to style replaced content
const style = document.createElement('style');
style.textContent = `
.wayback-replaced {
border: 2px dotted #666;
position: relative;
}
.wayback-replaced:hover::after {
content: 'Archived version from Wayback Machine';
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #333;
color: white;
padding: 5px;
border-radius: 3px;
font-size: 12px;
white-space: nowrap;
z-index: 1000;
}
img.wayback-replaced {
padding: 2px;
}
`;
document.head.appendChild(style);
// Initialize when the page loads
document.addEventListener('DOMContentLoaded', () => {
replaceAllBrokenContent();
observeContentChanges();
});
// Usage example:
// Run the replacement manually
// replaceAllBrokenContent();
// Check individual URLs
// const newUrl = await replaceWithWaybackLink('https://example.com/broken-link');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment