thesummit / Main Action Hotkey

// ==UserScript==
// @name            Main Action Hotkey
// @version         0.1
// @description     main action hotkey per website
// @match           *://*/*
// @grant           none
// @exclude         *

// ==UserLibrary==
// @name            Main Action Hotkey
// @version         1.0
// @description  main action hotkey per website
// @license LGPL-3.0-or-later

// ==/UserLibrary==

// ==/UserScript==

(function () {
  'use strict';

  const getElement = q => document.querySelector(q);
  const click = q => getElement(q).click();
  const clickLast = q => {
    const eles = document.querySelectorAll(q);
    if (!eles.length) return false;
    eles[eles.length - 1].click();

    return true;
  };

  // config map
  const sitePatternToActionMap = {
    "https://www.deviantart.com/": {
      autoRun: false,
      run: () => window.open(getElement('.dev-view-deviation > img').src)
    },
    "https://www.google.com/url?q=": {
      autoRun: true,
      run: () => click('a')
    },
    // enter custom entries below
    "https://forum.snahp.it/viewtopic.php?": {
      autoRun: false,
      run: () => {
        const selector = '.post-buttons .fa-thumbs-o-up';
        if (document.querySelector(selector)) {
          click(selector);
          return;
        }

        const isBase64 = t => {
          t = t.trim();
          if (!t.length || t.includes(' ')) {
            return false;
          }
          try {
            window.atob(t);
          }
          catch (e) {
            // return e.code === 5;
            return false;
          }

          return true;
        };
        const getSelectionText = () => {
          var text = "";
          if (window.getSelection) {
            text = window.getSelection().toString();
          }
          else if (document.selection && document.selection.type != "Control") {
            text = document.selection.createRange().text;
          }
          return text;
        }
        const isValidUrl = s => {
          try {
            new URL(s);
            return true;
          }
          catch (_) {
            return false;
          }
        };
        const openBase64Link = t => {
          const decode = s => {
            try {
              return atob(s);
            }
            catch (_) {
              return s;
            }
          };

          let decoded = t;
          for (let i = 0; i < 2; i++) {
            console.log(`decoding: ${decoded}`);
            decoded = decode(decoded);
            if (isValidUrl(decoded)) {
              window.open(decoded);
              break;
            }
          }
        };
        const sel = getSelectionText().trim();
        if (sel) {
          openBase64Link(sel);
          return;
        }

        const findBase64CodeLucky = () => {
          const candidates2 = document
            .querySelector('.postbody')
            .innerText
            .split('\n')
            .map(t => t.trim())
            .filter(t => t.length > 20)
            .filter(isBase64)
            .sort((a, b) => b.length - a.length);
          const candidates = Array
            .from(document.querySelectorAll('.postbody code'))
            .map(e => e.innerText)
            .map(t => t.split(' ').sort((a, b) => b.length - a.length)[0])
            .filter(isBase64)
            .concat(candidates2);

          return candidates.length > 0 ? candidates[0] : null;
        };
        const findCodeLucky = findBase64CodeLucky();
        if (findCodeLucky) {
          console.log('found lucky code so using that');
          openBase64Link(findCodeLucky);
          return;
        }

        const candidates = Array
          .from(document.querySelectorAll('.postbody code'))
          .map(e => e.innerText)
          .filter(isValidUrl)
          .filter(url => url.includes('mega.nz/'));
        if (candidates.length) {
          window.open(candidates[0]);
          return;
        }

        alert('couldn\'t find any base64 code. select some text manually and try again.');
      }
    },
    "https://forum.snahp.it/search.php?": {
      autoRun: false,
      run: () => click('.successfulOptionLink')
    },
    "https://nmac.to/dl/": {
      autoRun: true,
      run: () => click('.btn.btn-medium.btn-block')
    },
    "https://nmac.to/": {
      autoRun: false,
      run: () => clickLast('.the-content a[target="_blank"].btn.btn-small.btn-block')
    },
    "https://imgur.com/gallery/": {
      autoRun: false,
      run: () => click('.navNext')
    },
  };

  const runPattern = pattern => sitePatternToActionMap[pattern]['run']();
  const isCurrentUrlMatchedByPattern = pattern => window.location.href.toLowerCase().startsWith(pattern.toLowerCase());
  const trigger = () => {
    let success = false;
    Object
      .keys(sitePatternToActionMap)
      .filter(isCurrentUrlMatchedByPattern)
      .forEach(pattern => {
        if (!success) {
          runPattern(pattern);
          success = true;
        }
      });
    if (!success) {
      console.log('[mine] no custom runnable found for current url');
    }
  };

  document.onkeydown = function (e) {
    const getCharCode = c => c.toUpperCase().charCodeAt(0);
    const isHotkey = e.ctrlKey && e.which === getCharCode('a'); // ctrl-a(ction)
    const isHotkey2 = e.metaKey && e.keyCode === getCharCode('h'); // cmd-h(ere)
    if (isHotkey || isHotkey2) trigger();
  };

  const runAutorunables = () => {
    const autoRunablePatterns = Object
      .keys(sitePatternToActionMap)
      .filter(pattern => sitePatternToActionMap[pattern].autoRun === true);
    autoRunablePatterns
      .filter(isCurrentUrlMatchedByPattern)
      .forEach(runPattern);
  };
  runAutorunables();
})();