// ==UserScript== // @name RED Cover Inspector // @namespace https://greasyfork.org/users/321857-anakunda // @version 1.02.1 // @description Adds cover sticker if needs updating for unsupported host / big size / small resolution // @author Anakunda // @copyright 2020, Anakunda (https://greasyfork.org/users/321857-anakunda) // @license GPL-3.0-or-later // @match https://redacted.ch/torrents.php?id=* // @match https://redacted.ch/artist.php?id=* // @connect * // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @downloadURL none // ==/UserScript== const httpParser = /^(https?:\/\/.+)*$/i; function getRemoteFileSize(url, forced = true) { return httpParser.test(url) ? new Promise(function(resolve, reject) { let size, abort = GM_xmlhttpRequest({ method: forced ? 'GET' : 'HEAD', url: url, responseType: 'blob', onreadystatechange: function(response) { if (size >= 0 || response.readyState < XMLHttpRequest.HEADERS_RECEIVED) return; if (/^(?:Content-Length)\s*:\s*(\d+)\b/im.test(response.responseHeaders) && (size = parseInt(RegExp.$1)) >= 0) resolve(size); else if (!forced) reject(undefined); else return; abort.abort(); }, onload: function(response) { // fail-safe if (size >= 0) return; if (response.status >= 200 && response.status < 400) resolve(response.response.size); else reject('File not accessible'); }, onerror: response => { reject('File not accessible') }, ontimeout: response => { reject('File not accessible') }, }); }) : Promise.reject('getRemoteFileSize: parameter not valid URL'); } function formattedSize(size) { return size >= 0 ? size < 1024**1 ? Math.round(size) + ' B' : size < 1024**2 ? (Math.round(size * 10 / 2**10) / 10) + ' KiB' : size < 1024**3 ? (Math.round(size * 100 / 2**20) / 100) + ' MiB' : size < 1024**4 ? (Math.round(size * 100 / 2**30) / 100) + ' GiB' : size < 1024**5 ? (Math.round(size * 100 / 2**40) / 100) + ' TiB' : (Math.round(size * 100 / 2**50) / 100) + ' PiB' : NaN; } let acceptableCoverSize = GM_getValue('acceptable_cover_size'); if (!(acceptableCoverSize >= 0)) GM_setValue('acceptable_cover_size', acceptableCoverSize = 2048); let acceptableCoverResolution = GM_getValue('acceptable_cover_resolution'); if (!(acceptableCoverResolution >= 0)) GM_setValue('acceptable_cover_resolution', acceptableCoverResolution = 200); document.querySelectorAll('div#covers p > img, div.box_image > div > img').forEach(function(img) { let imgSrc = img.dataset.gazelleTempSrc || img.src; if (imgSrc.startsWith(document.location.origin) && imgSrc.includes('/static/common/noartwork/')) return; if (imgSrc.startsWith('https://i.imgur.com/')) imgSrc = imgSrc.replace(/\/(\w{7,})m\.(\w+)$/, '/$1.$2'); console.debug('imgSrc:', imgSrc); getRemoteFileSize(imgSrc).catch(function(reason) { console.warn('Failed to get remote image size (' + imgSrc + '):', reason); return undefined; }).then(function(size) { const span = (content, isOK = false) => (isOK ? '' : '') + content + '', isProxied = imgSrc.startsWith(document.location.origin + '/image.php?'), isPreferredHost = imgSrc.startsWith('https://ptpimg.me'), isInvalid = isProxied && (size < 2 * 2**10 && img.naturalWidth == 400 && img.naturalHeight == 100 || size == 503), isSizeOK = acceptableCoverSize == 0 || size <= acceptableCoverSize * 2**10, isResolutionOK = acceptableCoverResolution == 0 || (!img.naturalWidth || img.naturalWidth >= acceptableCoverResolution) && (!img.naturalHeight || img.naturalHeight >= acceptableCoverResolution); if (isPreferredHost && isSizeOK && isResolutionOK) return; let div = document.createElement('div'); div.style = 'color: white; border: 1px solid whitesmoke; background-color: #ae2300; ' + 'position: relative; font: 700 8pt "Segoe UI"; padding: 1px 5px;'; if (!isInvalid) { div.style.opacity = 0.8; div.style.float = 'right'; div.style.right = '7px'; div.style.bottom = '25px'; div.innerHTML = span(formattedSize(size), isSizeOK) + ' / ' + span(img.naturalWidth + '×' + img.naturalHeight, isResolutionOK); if (isProxied) div.innerHTML = span('PROXY') + ' / ' + div.innerHTML; else if (!isPreferredHost) div.innerHTML = span('XTRN') + ' / ' + div.innerHTML; } else { div.style.bottom = '3px'; div.innerHTML = span('INVALID'); } img.insertAdjacentElement('afterend', div); if (isInvalid) img.remove(); }); });