Press R on prnt.sc website to load some random screenshot
// ==UserScript== // @name LightShot (prnt.sc) random screenshot // @description Press R on prnt.sc website to load some random screenshot // // @name:ru Lightshot (prnt.sc) случайный скриншот // @description:ru Нажми R на сайте prnt.sc чтобы загрузить какой-то случайный скриншот // // @author Konf // @namespace https://greasyfork.org/users/424058 // @icon https://t1.gstatic.com/faviconV2?client=SOCIAL&url=http://prnt.sc&size=32 // @version 1.3.1 // @match https://prnt.sc/* // @compatible Chrome // @compatible Opera // @compatible Firefox // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js // @run-at document-body // @grant GM_addStyle // @noframes // ==/UserScript== /* jshint esversion: 8 */ (function() { 'use strict'; const langStrings = { en: { getNewRandImg: 'Load new random screenshot', hotkey: 'Hotkey', scriptGotFailStreak: 'Oops! Script just have got a huge fail streak. ' + 'If your internet connection is fine, maybe the script ' + 'is broken. Please consider to notify the script author ' + 'about the problem. Also it would be great if you check ' + 'your browser console and save all the info messages ' + 'from there. They are contain the errors details', }, ru: { getNewRandImg: 'Загрузить новый случайный скриншот', hotkey: 'Горячая клавиша', scriptGotFailStreak: 'Упс! Скрипт много пытался, но так и не смог ' + 'сработать. Если у тебя всё в порядке с интернетом, ' + 'то возможно скрипт просто сломан. Пожалуйста, сообщи ' + 'о проблеме автору скрипта. А ещё было бы супер если ' + 'бы ты открыл(а) консоль браузера и сохранил(а) оттуда ' + 'все сообщения. Они содержат описания ошибок', }, }; const userLang = navigator.language.slice(0, 2); const i18n = langStrings[userLang || 'en']; const css = [` body { /* fix header glitching */ overflow-y: scroll; } .randsshot-icon { float: left; width: 28px; height: 28px; margin: 11px 25px 0 0; color: white; font-weight: bold; user-select: none; cursor: pointer; border: 2px solid lightgray; border-radius: 100%; outline: none; background: none; } .randsshot-icon--loading { /* hide text */ text-indent: -9999em; white-space: nowrap; overflow: hidden; border-top: 5px solid rgba(255, 255, 255, 0.2); border-right: 5px solid rgba(255, 255, 255, 0.2); border-bottom: 5px solid rgba(255, 255, 255, 0.2); border-left: 5px solid #ffffff; transform: translateZ(0); animation: loading 1.1s infinite linear; } @keyframes loading { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `].join(); // node queries const qs = { garbage: [ 'div.image__title.image-info-item', 'div.additional', 'div.header-downloads', 'div.social', 'div.image-info', 'script[src*="image-helper.js"]', ].join(', '), needed: { mainImg: 'img.no-click.screenshot-image', headerLogo: 'a.header-logo', headerLogoParent: 'div.header > div.page-constrain', } }; const neededNodes = { mainImg: null, headerLogo: null, headerLogoParent: null, } document.arrive(qs.garbage, { existing: true }, n => n.remove()); let injected = false; for (const nodeId in qs.needed) { const query = qs.needed[nodeId]; document.arrive(query, { existing: true }, (aNode) => { // unreachable? if (injected) return; neededNodes[nodeId] = aNode; document.unbindArrive(query); for (const nodeId in neededNodes) { const node = neededNodes[nodeId]; if (node === null) return; } injected = true; main(); }); } function main() { GM_addStyle(css); const b = document.createElement('button'); const bParent = neededNodes.headerLogoParent; const bNeighbour = neededNodes.headerLogo; b.innerText = 'R'; b.title = `${i18n.getNewRandImg}\n${i18n.hotkey}: R`; b.className = 'randsshot-icon'; bParent.insertBefore(b, bNeighbour); b.addEventListener('click', loadNewSshot); document.addEventListener('keydown', ev => { if (ev.code === 'KeyR' && !ev.ctrlKey) loadNewSshot(); }); const parser = new DOMParser(); let failsStreak = 0; let isFetching = false; function closeFetchUX() { isFetching = false; b.className = 'randsshot-icon'; } async function loadNewSshot() { if (isFetching) return; isFetching = true; b.className = 'randsshot-icon randsshot-icon--loading'; const newSshotUrl = `https://prnt.sc/${makeSshotId()}`; try { const newSshotPage = await fetch(newSshotUrl); const newSshotPageDOM = parser.parseFromString( await newSshotPage.text(), 'text/html' ); const fetchedImgNode = newSshotPageDOM.querySelector( qs.needed.mainImg ); if (!fetchedImgNode || !fetchedImgNode.src) { throw new Error( 'Failed to find a new image in fetched webpage. ' + 'URL: ' + newSshotUrl ); } neededNodes.mainImg.src = fetchedImgNode.src; await new Promise((resolve, reject) => { const listeners = { load: () => { turnListeners('off'); history.pushState(null, null, newSshotUrl); closeFetchUX(); resolve(); }, error: () => { turnListeners('off'); reject( `Failed to load ${fetchedImgNode.src} ` + `that was fetched from ${newSshotUrl}` ); }, }; const turnListeners = (to) => { for (const type in listeners) { const listener = listeners[type]; if (to === 'on') { neededNodes.mainImg.addEventListener(type, listener); } else { neededNodes.mainImg.removeEventListener(type, listener); } } }; turnListeners('on'); }); failsStreak = 0; } catch (e) { failsStreak += 1; console.error(e); closeFetchUX(); if (failsStreak < 20) { // retry immediately (almost) setTimeout(loadNewSshot, 250); } else { alert(`${GM_info.script.name}:\n${i18n.scriptGotFailStreak}`); failsStreak = 0; } } } window.addEventListener('popstate', reloadPage); } // utils --------------------------------------------- function reloadPage() { window.location.reload(); } function makeSshotId() { const chars = { first: 'abcdefghijklmnopqrstuvwxyz123456789', rest: 'abcdefghijklmnopqrstuvwxyz0123456789', }; return makeId(chars.first, 1) + makeId(chars.rest, 5); } function makeId(charset, length) { let r###lt = ''; for (let i = 0, randNum; i < length; i++) { randNum = Math.floor(Math.random() * charset.length); r###lt += charset.charAt(randNum); } return r###lt; } // --------------------------------------------------- })();