Checks whether dead Imgur links are archived and replaces them.
目前為
// ==UserScript==
// @name Imgur Archivist
// @namespace https://reddit.com/u/VladVV/
// @version 0.9
// @description Checks whether dead Imgur links are archived and replaces them.
// @author /u/VladVV
// @match *://*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=archive.org
// @grant none
// @license EUPL v1.2
// ==/UserScript==
(function () {
'use strict';
// A dictionary to store the dead Imgur URLs and their archived versions
var imgurArchive = {};
// A function to check if an Imgur link is dead or alive
function checkImgurLink(url) {
var url_old = url; url = url.replace('http://','https://');
if (url in imgurArchive) return; //Abort if url has already been checked
var xhr = new XMLHttpRequest();
xhr.open('HEAD', url);
xhr.onreadystatechange = function () {
if (this.readyState === this.DONE) {
if (this.responseURL.indexOf('removed.png') !== -1 || this.status === 404) {
// Imgur image is removed or deleted
// Setup a GET request to the archive.org API
var archiveUrl = 'https://archive.org/wayback/available?url=' + url_old;
var archiveXhr = new XMLHttpRequest();
archiveXhr.open('GET', archiveUrl);
archiveXhr.onreadystatechange = function () {
if (this.readyState === this.DONE) {
var response = JSON.parse(this.responseText);
if (response.archived_snapshots.closest) {
// Archived image found
// Add the dead link and the archived link to the dictionary
imgurArchive[url_old] = response.archived_snapshots.closest.url;
} else {
// The removed image is not archived :(
imgurArchive[url_old] = false;
}
}
};
archiveXhr.send();
} else {
// Imgur image is live; our services aren't needed.
imgurArchive[url_old] = true;
}
}
};
xhr.send();
}
const archive_org_re = /^(?:https?:\/\/)?(?:web\.archive\.org\/web\/\d+\/)/
// A function to replace an Imgur link with its archived version if it exists in the dictionary
function replaceImgurLink(link) {
var url = link.href.replace(archive_org_re, '');
if (url in imgurArchive) {
if (imgurArchive[url] !== true && imgurArchive[url] !== false) {
// Save old element attributes to be restored
let old_style = link.style; let old_title = link.title;
// Set temporary element attributes
link.style.color = 'green';
link.style.outline = 'thin dotted green';
link.title = "Archived image available. (Imgur link is dead)";
// Set archive link if not already set
if (url in imgurArchive) link.setAttribute('href', imgurArchive[url]);
// Add event listener to restore old element attributes
link.addEventListener('mouseleave', function () {
link.style = old_style; link.title = old_title;
}, { once: true });
} else if (imgurArchive[url] === false) {
// Save old element attributes to be restored
let old_style = link.style; let old_title = link.title;
// Set temporary element attributes
link.style.color = 'red';
link.style.outline = 'thin dotted red';
link.title = "No archived image available. (Imgur link is dead)";
// Add event listener to restore old element attributes
link.addEventListener('mouseleave', function () {
link.style = old_style; link.title = old_title;
}, { once: true });
}
}
}
// A list of <a> elements that have already been processed (for dynamic content loading)
var old_links = [];
function updateLinks() {
// Get all the links in the document
var links = Array.from(document.getElementsByTagName('a'));
// Filter out link tags that have already been processed
if (old_links !== []) {
for (let i = 0; i < links.length; i++) {
if (links[i] in old_links) {
links.splice(i, 1);
} else {
old_links.push(links[i]);
}
}
} else {
old_links = links;
}
// Loop through the links and check if they are Imgur links
for (let i = 0; i < links.length; i++) {
if (links[i].href.indexOf('imgur') !== -1 && links[i].href.indexOf('archive.org') === -1) {
checkImgurLink(links[i].href);
}
}
}
updateLinks();
// Create an observer instance to respond to new content loaded dynamically by the page
var observer = new MutationObserver (function (mutations) {
mutations.forEach (function (mutation) {
if (mutation.type === "childList") {
mutation.addedNodes.forEach (function (node) {
var links;
if (node.tagName === 'A') {
links = [node];
} else if (node.childNodes && String(node) !== '[object Text]') {
links = node.querySelectorAll('a');
} else {
return;
}
for (let i = 0; i < links.length; i++) {
if (links[i].href.indexOf('imgur') !== -1 && links[i].href.indexOf('archive.org') === -1) {
checkImgurLink(links[i].href);
old_links.push(links[i]);
}
}
});
}
});
});
observer.observe(document.documentElement || document.body, {childList: true, subtree: true});
// Add an event listener to the whole document that waits for hovers on links
document.addEventListener('mouseover', function (event) {
// Get the target element of the hover event
var target = event.target;
//Traverse the DOM tree until we find a link (or not)
while (target && target.tagName !== 'A') {
target = target.parentNode;
}
// If a link is found, replace it with its archived version if possible
if (target) {
replaceImgurLink(target);
}
});
})();