Greasy Fork

Greasy Fork is available in English.

Reddl

Reddit Preview Ctrl+s Downloading Utility - also applies to a few other (wallpaper) sites

目前为 2023-10-22 提交的版本,查看 最新版本

// ==UserScript==
// @name         Reddl
// @version      0.2.0
// @description  Reddit Preview Ctrl+s Downloading Utility - also applies to a few other (wallpaper) sites
// @author       JFKennedy
// @license      MIT
// @match        https://*.reddit.com/media?url=*
// @match        https://w.wallha.com/*
// @match        https://get.wallhere.com/*
// @match        https://c.wallhere.com/*
// @match        https://*.wallhere.com/*
// @match        https://*.pinimg.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=reddit.com
// @grant        GM_xmlhttpRequest
// @connect      external-preview.redd.it
// @connect      i.redd.it
// @connect      *.redd.it
// @connect      *.reddit.com
// @connect      w.wallha.com
// @connect      get.wallhere.com
// @connect      c.wallhere.com
// @connect      *.pinimg.com
// @namespace    http://greasyfork.icu/users/1202256
// ==/UserScript==

document.addEventListener('keydown', async e => {
  const fetchWithTampermonkey = async (url, responseType = 'blob') => {
    return new Promise((resolve, reject) => {
      const loader = document.createElement('div');
      loader.style.height = '4px';
      loader.style.width = '100vw';
      loader.style.position = 'fixed';
      loader.style.top = '0';
      loader.style.left = '0';
      loader.style.display = 'block';
      loader.style.background = '#1a1a1a00';
      const loaderInner = document.createElement('div');
      loaderInner.style.height = loader.style.height;
      loaderInner.style.width = '0';
      loaderInner.style.position = 'fixed';
      loaderInner.style.top = '0';
      loaderInner.style.left = '0';
      loaderInner.style.display = 'block';
      loaderInner.style.background = '#aa99ff';
      loader.appendChild(loaderInner);
      const loaderInner2 = document.createElement('div');
      loaderInner2.style.height = loader.style.height;
      loaderInner2.style.width = loader.style.height;
      loaderInner2.style.position = 'fixed';
      loaderInner2.style.top = '0';
      loaderInner2.style.right = '0';
      loaderInner2.style.display = 'block';
      loaderInner2.style.filter = 'blur(2px)';
      loaderInner2.style.background = loaderInner.style.background;
      loaderInner2.style.borderRadius = '128px';
      loaderInner.appendChild(loaderInner2);
      document.body.appendChild(loader);
      GM_xmlhttpRequest({
        method: 'GET',
        url,
        responseType, // specify the desired responseType
        onload: (response) => {
          if (response.status === 200) {
            if (responseType === 'blob') {
              resolve(new Blob([response.response], { type: response.responseHeaders.match(/content-type: (.*)/i)[1] }));
            } else {
              resolve(response.responseText);
            }
            loader.remove();
          } else {
            setTimeout(() => loader.remove(), 1000)
            loaderInner.style.background = '#ffaaaa'
            loaderInner2.style.background = '#ffaaaa'
            reject(new Error('Request failed with status ' + response.status));
          }
        },
        onprogress: function (progress) {
          const percent = progress.lengthComputable ? (progress.position / progress.totalSize) : 100;
          console.log(progress, percent);
          loaderInner.style.width = `${percent * 100}vw`
          loaderInner2.style.left = loaderInner;
        },
        onerror: (error) => {
          reject(error);
        },
      });
    });
  };
  const dl = (url, filename) => {
    const a = document.createElement('a');
    a.href = url;
    a.download = filename || ('img-' + Date.now());
    document.body.appendChild(a);
    a.click();
    a.remove();
  }


  if (e.key === 's' && e.ctrlKey) {
    switch (location.hostname) {
      case 'reddit.com':
      case 'redd.it':
      case 'www.reddit.com':
      case 'www.redd.it':
      case 'i.redd.it':
        {
          const url = new URLSearchParams(location.search).get('url')
          if (!url) return;
          e.preventDefault()
          const data = await fetchWithTampermonkey(url);
          const dlUrl = URL.createObjectURL(data);
          const fname = (url.split('-').pop() || '').split('.');
          fname.pop();
          dl(dlUrl, `reddit-${fname.join('.') || `unknown-${Date.now()}`}.${url.split('.').pop()}`);
          break;
        }
      case 'wallhere.com':
      case 'www.wallhere.com':
        {
          const img = document.querySelector('img[itemprop="contentURL"]')
          if (!img) return;
          const url = img.src;
          if (!url) return;
          e.preventDefault()
          const data = await fetchWithTampermonkey(url);
          const dlUrl = URL.createObjectURL(data);
          const fname = (url.split('-').pop() || '').split('.');
          fname.pop();
          dl(dlUrl, `wall-${fname.join('.') || `unknown-${Date.now()}`}.${url.split('.').pop()}`);
          break;
        }
      case 'i.pinimg.com':
      case 'pinimg.com':
      case 'w.wallha.com':
      case 'i.wallha.com':
      case 'get.wallhere.com':
      case 'c.wallhere.com':
        {
          const img = document.querySelector('img')
          if (!img) return console.warn('No image');
          e.preventDefault()
          dl(img.src);
          break;
        }
    }
  }
})