// ==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://www.google.com/s2/favicons?domain=prnt.sc&sz=32 // @version 1.2.0 // @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 // @downloadURL none // ==/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 { overflow-y: scroll; } .parser-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; } .parser-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', ].join(', '), needed: { mainImg: { q: 'img.no-click.screenshot-image', node: null, }, headerLogo: { q: 'a.header-logo', node: null, }, headerLogoParent: { q: 'div.header > div.page-constrain', node: null, }, } }; document.arrive(qs.garbage, { existing: true }, n => n.remove()); let injected = false; for (const nodeId in qs.needed) { const nodeObj = qs.needed[nodeId]; // eslint-disable-next-line no-loop-func document.arrive(nodeObj.q, { existing: true }, (aNode) => { nodeObj.node = aNode; const neededNodesAmount = Object.keys(qs.needed).length; let arrivedCount = 0; for (const nodeId in qs.needed) { const nodeObj = qs.needed[nodeId]; if (nodeObj.node) arrivedCount += 1; } if ( injected === false && arrivedCount === neededNodesAmount ) { injected = true; main(); } }); } function main() { GM_addStyle(css); const b = document.createElement('button'); // fetch button const bParent = qs.needed.headerLogoParent.node; const bNeighbour = qs.needed.headerLogo.node; b.innerText = 'R'; b.title = `${i18n.getNewRandImg}\n${i18n.hotkey}: R`; b.className = 'parser-icon'; bParent.insertBefore(b, bNeighbour); b.addEventListener('click', loadNewImg); document.addEventListener('keydown', ev => { if (ev.code === 'KeyR') loadNewImg(); }); let failsStreak = 0; let isFetching = false; function closeFetchUX() { isFetching = false; b.className = 'parser-icon'; } async function loadNewImg() { if (isFetching) return; isFetching = true; b.className = 'parser-icon parser-icon--loading'; const newSshotUrl = `https://prnt.sc/${makeImgId()}`; try { const newSshotPage = await fetch(newSshotUrl); const tempDiv = document.createElement('div'); tempDiv.innerHTML = await newSshotPage.text(); const mainImg = qs.needed.mainImg.node; const fetchedImgNode = tempDiv.querySelector(qs.needed.mainImg.q); if (!fetchedImgNode || !fetchedImgNode.src) { throw new Error( 'Failed to find a new image in fetched webpage. ' + 'URL: ' + newSshotUrl ); } let newSshotBlob; try { const newSshotImg = await fetch(fetchedImgNode.src); newSshotBlob = await newSshotImg.blob(); } catch (e) { console.error(e); throw new Error( `Failed to load ${fetchedImgNode.src} ` + `that was fetched from ${newSshotUrl}` ); } mainImg.src = URL.createObjectURL(newSshotBlob); closeFetchUX(); history.pushState(null, null, newSshotUrl); failsStreak = 0; } catch (e) { failsStreak += 1; console.error(e); closeFetchUX(); if (failsStreak < 20) { // retry immediately (almost) setTimeout(loadNewImg, 250); } else { alert(`${GM_info.script.name}:\n${i18n.scriptGotFailStreak}`); failsStreak = 0; } } } window.addEventListener('popstate', reloadPage); } // utils --------------------------------------------- function reloadPage() { window.location.reload(); } function makeImgId() { const chars = { first: 'abcdefghijklmnopqrstuvwxyz123456789', rest: 'abcdefghijklmnopqrstuvwxyz0123456789', }; return makeId(chars.first, 1) + makeId(chars.rest, 5); } function makeId(charset, length) { let result = ''; for (let i = 0, randNum; i < length; i++) { randNum = Math.floor(Math.random() * charset.length); result += charset.charAt(randNum); } return result; } // --------------------------------------------------- })();