Greasy Fork is available in English.

LightShot (prnt.sc) random screenshot

Нажми R на сайте prnt.sc чтобы загрузить какой-то случайный скриншот

// ==UserScript==
// @name             LightShot (prnt.sc) random screenshot
// @description      Нажми 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.0.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-start
// @grant            none
// @noframes
// ==/UserScript==

/* jshint esversion: 6 */

(function() {
  'use strict';

  const n = { // nodes and its queries
    garbage: [
      'div.image__title.image-info-item', 'div.additional',
      'div.header-downloads', 'div.social', 'div.image-info'
    ],
    needed: {
      mainImg: {
        q: 'img.no-click.screenshot-image',
        node: null
      },
      headerLogo: { q: 'a.header-logo' },
      headerLogoParent: { q: 'div.header > div.page-constrain' }
    }
  }

  const garbageNodesStr = n.garbage.join(', ');

  document.arrive(garbageNodesStr, { existing: true }, (aNode) => {
    aNode.remove();
  });

  const css = [`
    .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);
      }
    }
  `];

  let injected = false;

  for (const nodeId in n.needed) {
    const nodeObj = n.needed[nodeId];

    document.arrive(nodeObj.q, { existing: true }, (aNode) => {
      nodeObj.node = aNode;

      const neededNodesCount = Object.keys(n.needed).length;
      let arrivedCount = 0;

      for (const nodeId in n.needed) {
        const nodeObj = n.needed[nodeId];

        if (nodeObj.node) arrivedCount++;
      }

      if (!injected && arrivedCount === neededNodesCount) {
        injected = true;
        main();
      }
    });
  }


  function main() {
    addCSS(css[0]);

    let fetching = false;

    const b = document.createElement('button'); // fetch button
    const bParent = n.needed.headerLogoParent.node;
    const bNeighbour = n.needed.headerLogo.node;

    b.innerText = 'R';
    b.title = 'Загрузить новый случайный скриншот\nГорячая клавиша: R';
    b.className = 'parser-icon';
    bParent.insertBefore(b, bNeighbour);

    b.addEventListener('click', loader);
    document.addEventListener('keydown', ev => {
      if (ev.code !== 'KeyR') return;
      loader();
    });

    function loader() {
      if (fetching) return;

      fetching = true;
      b.className = 'parser-icon parser-icon--loading';

      const newImgUrl = 'https://prnt.sc/' + makeId(6);

      fetch(newImgUrl)
      .then(res => res.text())
      .then(body => {
        const tempDiv = document.createElement('div');
        tempDiv.innerHTML = body;

        const mainImg = n.needed.mainImg.node;
        const fetchedImgNode = tempDiv.querySelector(n.needed.mainImg.q);

        if (fetchedImgNode && fetchedImgNode.src) {
          mainImg.src = fetchedImgNode.src;

          mainImg.addEventListener('load', (ev) => {
            fetching = false;
            b.className = 'parser-icon';

            history.pushState(null, null, newImgUrl);
          }, { once: true });
        } else {
          throw new Error(
            'Failed to find a new image in fetched webpage. ' +
            'URL: ' + newImgUrl
          );
        }
      })
      .catch(err => {
        console.error(err);

        fetching = false;
        b.className = 'parser-icon';

        setTimeout(loader, 250);
      })
    }

    window.addEventListener('popstate', (ev) => {
      window.location.href = window.location.href;
    });
  }


  // utils ---------------------------------------------

  function addCSS(cssCode) {
    const styleEl = document.createElement("style");
    styleEl.type = "text/css";

    if (styleEl.styleSheet) {
      styleEl.styleSheet.cssText = cssCode;
    } else {
      styleEl.appendChild(document.createTextNode(cssCode));
    }

    document.getElementsByTagName("head")[0].appendChild(styleEl);

    return styleEl;
  }

  function makeId(length) {
    const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';

    for (let i = 0, randNum; i < length; i++) {
      randNum = Math.floor(Math.random() * chars.length);
      result += chars.charAt(randNum);
    }

    return result;
  }

  // ---------------------------------------------------
})();