Greasy Fork

LightShot (prnt.sc) random screenshot

Press R on prnt.sc website to load some random screenshot

目前为 2021-11-30 提交的版本。查看 最新版本

// ==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.1.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
// ==/UserScript==

/* jshint esversion: 6 */

(function() {
  'use strict';

  const langStrings = {
    en: {
      getNewRandImg: 'Load new random screenshot',
      hotkey: 'Hotkey',
    },
    ru: {
      getNewRandImg: 'Загрузить новый случайный скриншот',
      hotkey: 'Горячая клавиша',
    },
  };
  const userLang = navigator.language.slice(0, 2);
  const i18n = langStrings[userLang || 'en'];

  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);
      }
    }
  `].join();

  // node queries
  const qs = {
    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',
        node: null,
      },
      headerLogoParent: {
        q: 'div.header > div.page-constrain',
        node: null,
      },
    }
  };

  document.arrive(qs.garbage.join(', '), { 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 neededNodesCount = Object.keys(qs.needed).length;
      let arrivedCount = 0;

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

        if (nodeObj.node) arrivedCount++;
      }

      if (injected === false && arrivedCount === neededNodesCount) {
        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', loader);
    document.addEventListener('keydown', ev => {
      if (ev.code !== 'KeyR') return;

      loader();
    });

    let fetching = false;

    async function loader() {
      if (fetching) return;

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

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

      try {
        const response = await fetch(newImgUrl);
        const tempDiv = document.createElement('div');

        tempDiv.innerHTML = await response.text();

        const mainImg = qs.needed.mainImg.node;
        const fetchedImgNode = tempDiv.querySelector(qs.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 (e) {
        console.error(e);

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

        setTimeout(loader, 250);
      }
    }

    window.addEventListener('popstate', reloadPage);
  }


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

  function reloadPage() {
    window.location.href = window.location.href;
  }

  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;
  }

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