您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Checks whether dead Imgur links and images are archived and replaces them.
- // ==UserScript==
- // @name Imgur Archivist
- // @namespace https://reddit.com/u/VladVV/
- // @version 0.12
- // @description Checks whether dead Imgur links and images 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';
- // Configuration options for the script:
- const scriptConfig = {
- DOMElements: {
- // Any DOM element can be added in the format 'tagName' : 'attribute'
- // The attribute will be treated as a URL and replaced with archived URLs
- 'A' : 'href',
- 'IMG' : 'src'
- },
- archiveIcon: '', //TODO: implement little icon to display inside archived elements
- linkTooltips: {
- // Tooltips when hovering over links. Set to a blank string ("") for nothing.
- available: "Archived image available. (Imgur link is dead)",
- unavailable: "No archived image available. (Imgur link is dead)"
- },
- changeLinkStyleOnHover: true, // Archived links will become green/red; set to false to disable
- };
- // A dictionary to store the dead Imgur URLs and their archived versions
- var imgurArchive = {};
- // A function to check if an Imgur URL is dead or alive
- function checkImgurURL(url) {
- // Force HTTPS to prevent cross-domain request issues
- 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;
- 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] = response.archived_snapshots.closest.url;
- } else {
- // The removed image is not archived :(
- imgurArchive[url] = false;
- }
- }
- };
- archiveXhr.send();
- } else {
- // Imgur image is live; our services aren't needed.
- imgurArchive[url] = 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) {
- // Set archive link if not already set
- if (url in imgurArchive) link.setAttribute('href', imgurArchive[url]);
- if (scriptConfig.changeLinkStyleOnHover) {
- // 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 = scriptConfig.linkTooltips.available;
- // 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 && scriptConfig.changeLinkStyleOnHover) {
- // 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 = scriptConfig.linkTooltips.unavailable;
- // 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 elements that have already been processed (for dynamic content loading)
- var processed_elements = {};
- function updateURLs() {
- // Get all the relevant elements in the document
- var elements = {};
- for (let el in scriptConfig.DOMElements) {
- elements[el] = Array.from(document.getElementsByTagName(el));
- }
- //var links = Array.from(document.getElementsByTagName('a'));
- // Filter out link tags that have already been processed
- if (processed_elements !== {}) {
- for (let el in elements) {
- for (let i = 0; i < elements[el].length; i++) {
- if (elements[el][i] in processed_elements) {
- elements[el].splice(i, 1);
- } else {
- if (!processed_elements[el]) processed_elements[el] = [];
- processed_elements[el].push(elements[el][i]);
- }
- }
- }
- } else {
- processed_elements = elements;
- }
- // Loop through the elements and check if they are associated with Imgur links
- for (let el in elements) {
- for (let i = 0; i < elements[el].length; i++) {
- let elementURL = elements[el][i][scriptConfig.DOMElements[el]];
- if (elementURL.indexOf('imgur') !== -1 && elementURL.indexOf('archive.org') === -1) {
- checkImgurURL(elementURL);
- if (elementURL in imgurArchive) {
- elements[el][i].setAttribute(scriptConfig.DOMElements[el], imgurArchive[elementURL]);
- }
- }
- }
- }
- }
- updateURLs();
- // 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 elements = {};
- if (node.tagName in scriptConfig.DOMElements) {
- elements[node.tagName] = [node];
- } else if (node.childNodes && String(node) !== '[object Text]') {
- for (let el in scriptConfig.DOMElements) {
- elements[el] = node.querySelectorAll(el);
- }
- } else return;
- for (let el in elements) {
- for (let i = 0; i < elements[el].length; i++) {
- let elementURL = elements[el][i][scriptConfig.DOMElements[el]].replace('http://','https://');
- if (elementURL.indexOf('imgur') !== -1 && elementURL.indexOf('archive.org') === -1) {
- checkImgurURL(elementURL);
- if (elementURL in imgurArchive) {
- elements[el][i].setAttribute(scriptConfig.DOMElements[el], imgurArchive[elementURL]);
- }
- if (!processed_elements[el]) processed_elements[el] = [];
- processed_elements[el].push(elements[el][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);
- }
- });
- })();