Greasy Fork

来自缓存

Greasy Fork is available in English.

下载原始图片

一个帮你从网站下载原始尺寸图片的工具

当前为 2022-01-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Download Original Picture
// @name:zh-CN  下载原始图片
// @description  A tool to help you download full size images from websites
// @description:zh-CN  一个帮你从网站下载原始尺寸图片的工具
// @namespace    https://huching.net/
// @version     0.1.0
// @license     GPL-3.0
// @icon        data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTA4IDUwOCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+IDxjaXJjbGUgc3R5bGU9ImZpbGw6I0ZGRDA1QjsiIGN4PSIyNTQiIGN5PSIyNTQiIHI9IjI1NCIvPiA8cGF0aCBzdHlsZT0iZmlsbDojRkZGRkZGOyIgZD0iTTM3Mi44LDE5NkgzNjhjLTIuNC00MC40LTM1LjYtNzIuNC03Ni40LTcyLjRjLTQsMC04LDAuNC0xMS42LDAuOGMtMTYtMjguNC00Ni00Ny42LTgwLjgtNDcuNiBjLTUxLjIsMC05Mi40LDQxLjYtOTIuNCw5Mi40YzAsMTAuOCwyLDIxLjIsNS4yLDMwLjhjLTI1LjIsMTAtNDIuOCwzNC00Mi44LDYyLjRjMCwzNi40LDI5LjYsNjYuNCw2Ni40LDY2LjRoMjM3LjIgYzM2LjQsMCw2Ni40LTI5LjYsNjYuNC02Ni40QzQzOC44LDIyNS42LDQwOS4yLDE5NiwzNzIuOCwxOTZ6Ii8+IDxwYXRoIHN0eWxlPSJmaWxsOiNGRjcwNTg7IiBkPSJNMzI1LjIsMzYyLjRsLTY2LjQsNjYuNGMtMi44LDIuOC03LjIsMi44LTEwLDBsLTY2LTY2LjRjLTQuNC00LjQtMS4yLTEyLDQuOC0xMmgxNC44IGM0LDAsNy4yLTMuMiw3LjItNy4ydi05NmMwLTQsMy4yLTcuMiw3LjItNy4yaDc0LjhjNCwwLDcuMiwzLjIsNy4yLDcuMnY5NmMwLDQsMy4yLDcuMiw3LjIsNy4yaDE0LjggQzMyNi40LDM1MC40LDMyOS42LDM1OCwzMjUuMiwzNjIuNHoiLz4gPC9zdmc+IA==
// @author      huc < [email protected] >
// @supportURL  https://github.com/hz2/user-scripts-and-styles/issues/new
// @require http://greasyfork.icu/scripts/396752-hx-script-library/code/hx-script-library.js
// @resource HxLib http://greasyfork.icu/scripts/396752-hx-script-library/code/hx-script-library.js
// @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&[email protected]&item_name=Greasy+Fork+donation
// @contributionAmount 5
// @include     *://medium.com/*
// @include     *://twitter.com/*
// @include     *://mobile.twitter.com/*
// @include     *://weibo.com/*
// @include     *://*.weibo.com/*
// @include     *://*.vmgirls.com/*
// @include     *://wallpaperhub.app/*
// @include     *://*.bing.com/*
// @include     *://*.msn.cn/*
// @include     *://instagram.com/*
// @include     *://*.instagram.com/*
// @include     *://instagram.com/*
// @include     *://*.instagram.com/*
// @include     *://tiktok.com/*
// @include     *://*.tiktok.com/*
// @include     *://*.douyin.com/*
// @include     *://*.kuaishou.com/*
// @include     *://*.xiaohongshu.com/*

// @noframes
// @grant          unsafeWindow
// @grant          GM_setClipboard
// @grant          GM_xmlhttpRequest
// @grant          GM_openInTab
// @grant          GM_registerMenuCommand
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_getResourceText
// @grant          GM_info
// @grant          GM_addStyle
// ==/UserScript==

const head = document.getElementsByTagName('head');
head[0].insertAdjacentHTML('beforeend', `<style type="text/css">
.hx-download-original-images-tool{
    position: absolute;
    background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTA4IDUwOCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+IDxjaXJjbGUgc3R5bGU9ImZpbGw6I0ZGRDA1QjsiIGN4PSIyNTQiIGN5PSIyNTQiIHI9IjI1NCIvPiA8cGF0aCBzdHlsZT0iZmlsbDojRkZGRkZGOyIgZD0iTTM3Mi44LDE5NkgzNjhjLTIuNC00MC40LTM1LjYtNzIuNC03Ni40LTcyLjRjLTQsMC04LDAuNC0xMS42LDAuOGMtMTYtMjguNC00Ni00Ny42LTgwLjgtNDcuNiBjLTUxLjIsMC05Mi40LDQxLjYtOTIuNCw5Mi40YzAsMTAuOCwyLDIxLjIsNS4yLDMwLjhjLTI1LjIsMTAtNDIuOCwzNC00Mi44LDYyLjRjMCwzNi40LDI5LjYsNjYuNCw2Ni40LDY2LjRoMjM3LjIgYzM2LjQsMCw2Ni40LTI5LjYsNjYuNC02Ni40QzQzOC44LDIyNS42LDQwOS4yLDE5NiwzNzIuOCwxOTZ6Ii8+IDxwYXRoIHN0eWxlPSJmaWxsOiNGRjcwNTg7IiBkPSJNMzI1LjIsMzYyLjRsLTY2LjQsNjYuNGMtMi44LDIuOC03LjIsMi44LTEwLDBsLTY2LTY2LjRjLTQuNC00LjQtMS4yLTEyLDQuOC0xMmgxNC44IGM0LDAsNy4yLTMuMiw3LjItNy4ydi05NmMwLTQsMy4yLTcuMiw3LjItNy4yaDc0LjhjNCwwLDcuMiwzLjIsNy4yLDcuMnY5NmMwLDQsMy4yLDcuMiw3LjIsNy4yaDE0LjggQzMyNi40LDM1MC40LDMyOS42LDM1OCwzMjUuMiwzNjIuNHoiLz4gPC9zdmc+IA==);
    background-size: cover;
    width: 50px;
    height: 50px;
    cursor: pointer;
    opacity: .35;
    z-index: 50000;
    transform: scale(.75);
    transition: all cubic-bezier(0.18, 0.89, 0.32, 1.28) 250ms;
}
.hx-download-original-images-tool.white{
    background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIGZpbGw9ImluaGVyaXQiIGltcGxpY2l0LWNvbnNlbnQtc291cmNlPSJ0cnVlIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMDEyMiAwIDAgMS4wMTIyIC0yOC42ODQgLTMuNDMzOSkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjMiPgogIDxjaXJjbGUgY3g9IjQwLjE5NCIgY3k9IjE1LjI0OCIgcj0iOC45ODI0Ii8+CiAgPHBhdGggZD0ibTQ1IDE3LTQuNTMzIDMuNTQ3Yy0wLjE2NjU5IDAuMTMwMzUtMC4zODQ2MSAwLjE0OTU3LTAuNTM0MTggMGwtNC41NjY0LTMuNTQ3Yy0wLjIzNTA0LTAuMjM1MDQtMC4wNjQxLTAuNjQxMDIgMC4yNTY0MS0wLjY0MTAyaDIuNDM2MmMwLjIxMzY3IDAgMC4zODQ2MS0wLjE3MDk0IDAuMzg0NjEtMC4zODQ2MXYtNS43MzI5YzAtMC4yMTM2NyAwLjE3MDk0LTAuMzg0NjEgMC4zODQ2MS0wLjM4NDYxaDIuNzAzNmMwLjIxMzY3IDAgMC4zODQ2MSAwLjE3MDk0IDAuMzg0NjEgMC4zODQ2MXY1LjczMjljMCAwLjIxMzY3IDAuMTcwOTQgMC4zODQ2MSAwLjM4NDYxIDAuMzg0NjFoMi40NjM5YzAuMjk5MTQgMCAwLjQ5NjgyIDAuNDM2MTggMC4yMzUwNCAwLjY0MTAyeiIvPgogPC9nPgo8L3N2Zz4K);
    width: 24px;
    height: 24px;
}
.hx-download-original-images-tool:hover {
    opacity:1;
    transform: scale(.9);
}
.hx-download-original-images-tool:active {
    opacity:.8;
    transform: scale(.7)  rotateZ(360deg);
}
</style>`);


console.warn('Welcome to %c \ud83d\ude48\ud83d\ude49\ud83d\ude4a\u0020\u0048\u007a\u00b2\u0020\u0053\u0063\u0072\u0069\u0070\u0074\u0020\u004c\u0069\u0062\u0072\u0061\u0072\u0079 %c v0.06 ', 'background-color:teal;color: white;border:1px solid teal;border-radius: 4px 0 0 4px;border-left-width:0;padding:1px;margin:2px 0;font-size:1.1em', 'background-color:#777;color: white;border:1px solid #777;border-radius: 0 4px 4px 0;border-right-width:0;padding:1px;margin:5px 0;');

const openDown = (url, e, name) => {
  e && e.preventDefault();
  e && e.stopPropagation()


  const downBlobUrl = (blobUrl) => {
    let el = document.createElement("a");
    el.setAttribute("href", blobUrl);
    if (name) {
      el.setAttribute("download", name)
    }
    if (document.createEvent) {
      const event = document.createEvent("MouseEvents");
      event.initEvent("click", true, true);
      el.dispatchEvent(event);
    } else {
      el.click();
    }

  }

  if (url.startsWith('blob')) {
    downBlobUrl(url)
    return

  }


  fetch(url, {
      mode: "cors"
    })
    .then(resp => resp.blob())
    .then(r => {
      const blobUrl = URL.createObjectURL(r)
      downBlobUrl(blobUrl)
    })
    .catch(err => {
      console.log("Request failed", err);
    });
}

const hostname = window.location.hostname

const lastItem = arr => arr.length ? arr[arr.length - 1] : ''

const createDomAll = (item, fn) => {
  let domDL = document.createElement('a');
  domDL.className = 'hx-download-original-images-tool'
  domDL.title = '下载原始图片'

  item.addEventListener('load', _ => {
    let link = fn(item.src)
    domDL.href = link
    domDL.addEventListener('click', e => openDown(link, e))
  })
  item.insertAdjacentElement('afterEnd', domDL)
}

const createDom = (cfg) => {
  const {
    parent,
    link,
    name,
    className = '',
    style = '',
    target,
    postion = 'afterEnd'
  } = cfg

  const genDomDL = (dom) => {
    let domDL = dom || document.createElement('a');
    Object.assign(domDL, {
      title: '下载原始图片',
      className: 'hx-download-original-images-tool ' + className,
      style: style,
      href: link,
    })
    domDL.onclick = e => {
      e && e.preventDefault();
      e && e.stopPropagation()
      const newName = name || lastItem(link.split('/'))
      openDown(link, e, newName)
    }
    return domDL
  }

  let parent2 = parent
  if (!parent && target) {
    parent2 = target.parentElement
  }
  if (['afterEnd', 'beforeBegin'].includes(postion)) {
    parent2 = target.parentElement.parentElement
  }
  const exist = parent2.querySelector('.hx-download-original-images-tool')
  if (exist) {
    genDomDL(exist)
  } else {
    parent2.insertAdjacentElement(postion, genDomDL())
  }
}

const updateLink = (dom, link) => {
  dom.href = link
  const newName = lastItem(link.split('/'))
  dom.onclick = e => openDown(link, e, newName)
}

const init = () => {

  if (hostname === "twitter.com" || hostname === "mobile.twitter.com") {
    //twitter
    window.addEventListener('mouseover', ({
      target
    }) => {
      const src = target && target.src
      const parent = target.parentElement
      const next = parent && parent.nextElementSibling
      if (target.tagName == 'IMG' &&
        !(next && next.className.includes('hx-download-original-images-tool')) &&
        !/profile_images|video_thumb/g.test(src)) {
        const link = src.replace(/\&name=\w+/g, '&name=orig')
        const name = lastItem(link.split('/')).replace(/\?format=(\w+)\&name=orig/g, (_, b) => `.${b}`)
        const style = 'margin-left: 10px;margin-top: 10px;'
        const cfg = {
          parent,
          link,
          name,
          style
        }
        createDom(cfg)
      }
    })
  } else if (hostname.includes('weibo')) {
    const isWeiboNode = dom => {
      const getNodeValue = el => el.attributes['node-type'] && el.attributes['node-type'].nodeValue
      if (getNodeValue(dom.parentElement) === 'artwork_box' || getNodeValue(dom) === 'img_box' || dom.className.includes('woo-picture-main') || dom.className.includes('woo-picture-slot') || dom.className.includes('imgInstance')) {
        return true
      } else {
        return false
      }
    }
    window.addEventListener('mouseover', ({
      target
    }) => {
      const parent = target.parentElement
      const next = parent && parent.nextElementSibling
      if (target.tagName == 'IMG' && isWeiboNode(parent)) {
        const link = target.src.replace(/orj\d+|mw\d+/g, 'large')
        if (next && next.className.includes('hx-download-original-images-tool')) {
          updateLink(next, link)
        } else {
          const style = 'top: 40px;right: 10px;'
          const cfg = {
            parent,
            link,
            style
          }
          createDom(cfg)
        }
      }
    })
  } else if (hostname === "www.vmgirls.com") {
    // vmgirls
    let domDL = document.createElement('a');
    domDL.className = 'hx-download-original-images-tool '
    domDL.style = 'position: relative;margin-right: 10px;display: inline-block;vertical-align: -20px;'
    domDL.title = '下载原始图片'
    domDL.onclick = e => {
      const list1 = [...document.querySelector('.post').querySelectorAll('a')].filter(x => x.src && x.src.indexOf('static.vmgirls.com/image') !== -1)
      const list2 = [...document.querySelector('.post-content').querySelectorAll('img')].filter(x => x.src && x.src.indexOf('t.cdn.ink/image') !== -1)
      const imgList = [...list1, ...list2].map((x, i) => ({
        link: x.src && x.src.replace('-scaled', ''),
        name: `${x.alt || x.title}_${i}.jpg`
      }))
      domDL.title += ' ' + imgList.length
      imgList.forEach(x => openDown(x.link, e, x.name))
      const link1 = imgList.map(x => x.link).join('\n')
      const link2 = imgList.map(x => `aria2c -o ${x.name} ${x.link}`).join('\n')
      const content = `<html><head><meta charset="utf-8"><title>获取链接</title></head><body><textarea style="width: 850px; height: 250px; margin: 30px;">${link1}</textarea>
      <textarea style="width: 850px; height: 250px; margin: 30px;">${link2}</textarea>
      </body></html>`
      window.open(URL.createObjectURL(new Blob([content], {
        type: 'text/html'
      })))
    }
    document.querySelector('.main-submenu').insertAdjacentElement('afterBegin', domDL)
  } else if (hostname === "medium.com") {
    // medium
    document.querySelector('article').querySelectorAll('img').forEach(x => (x.width > 80) && createDomAll(x, src => src.replace(/max\/\d+\//g, 'max/30000/')))
  } else if (hostname === "wallpaperhub.app") {
    // wallpaperhub
    const odomList = [...document.querySelectorAll('.downloadButton')]
    odomList.forEach(odom => {
      if (odom) {
        let link0 = odom.href.split('downloadUrl=')[1]
        const link = link0
        const style = 'position: relative;margin-right: 10px;display: inline-block;vertical-align: -20px;'
        const cfg = {
          parent: odom.parentElement.parentElement,
          link,
          style,
          postion: 'beforeBegin'
        }
        createDom(cfg)
      }
    })
  } else if (hostname === "ntp.msn.cn") {
    // edge 首页
    const link = document.querySelector('background-image')._imageSource;
    const style = 'position: fixed;right: 80px;top: 40px;'
    const cfg = {
      parent: document.body,
      link,
      className: 'white',
      style,
      postion: 'beforeBegin'
    }
    createDom(cfg)
  } else if (hostname === "www.bing.com") {
    // bing 首页
    const orig = document.querySelector('[style*="th?id="]').style.backgroundImage
    const link = orig.match(/th\?id\=[\w\d\.\-\_]+/g)[0].replace('1920x1080', 'UHD')
    const name = link && link.split('=')[1]
    const style = 'position: relative;width: 42px;height: 42px;margin: 0;opacity: .9;'
    const cfg = {
      parent: document.querySelector('#id_h'),
      link,
      name,
      className: 'white',
      style,
      postion: 'afterBegin'
    }
    createDom(cfg)
  } else if (hostname === "cn.bing.com") {
    // bing 首页
    const link = document.querySelector('#bgImgProgLoad').dataset.ultraDefinitionSrc.split('&')[0];
    const name = link && link.split('=')[1]
    const style = 'position: fixed;right: 225px;bottom: 53px;margin: 0px;width: 64px;height: 64px;z-index: 550;opacity: .9;'
    const cfg = {
      parent: document.body,
      link,
      name,
      className: 'white',
      style,
      postion: 'beforeBegin'
    }
    createDom(cfg)
  } else if (hostname === "www.instagram.com") {
    window.addEventListener('mouseover', ({
      target
    }) => {
      const el = target.previousElementSibling
      const el2 = target.parentElement
      const img = (el && el.querySelector('img:not([data-testid])') || el2 && el2.querySelector('video:not([data-testid])'))
      if (img) {
        const src = img.src
        const parent = img.parentElement
        const link = src
        const style = 'left: 10px;top: 10px;'
        const cfg = {
          parent,
          link,
          style,
          target: img,
          name: img.alt ? (img.alt + '.jpg') : src.split(/[\?\/]/g).filter(x => x.endsWith('.jpg'))[0],
          postion: 'beforeEnd'
        }
        createDom(cfg)
      }
    })
  } else if (hostname === "www.tiktok.com") {
    window.addEventListener('mouseover', ({
      target
    }) => {
      if (target.tagName == 'VIDEO') {
        const src = target.src
        const parent = target.parentElement
        const link = src
        const style = 'left: 10px;top: 10px;'
        const cfg = {
          parent,
          link,
          style,
          target,
          name: lastItem(src.split('?')[0].split('/').filter(x => x)),
          postion: 'beforeEnd'
        }
        createDom(cfg)
      }
    })
  } else if (hostname === "www.douyin.com") {
    window.addEventListener('mouseover', ({
      target
    }) => {
      // if (target && target.tagName === 'VIDEO') {
      //   const src = (target.querySelector('source') || target).src
      //   const link = src
      //   const style = 'left: 10px;top: 10px;'
      //   const cfg = {
      //     link,
      //     style,
      //     target,
      //     postion: 'afterEnd',
      //     name: lastItem(src.split('?')[0].split('/').filter(x => x)),
      //   }
      //   createDom(cfg)
      //   return
      // } else 
      if (target && target.parentElement) {
        const container = target.parentElement.parentElement || {
          className: ''
        }
        if (container && container.className.includes('videoContainer') && container.querySelector('video')) {
          const src = (container.querySelector('source') || container.querySelector('video')).src
          const link = src
          const style = 'left: 10px;top: 10px;'
          const cfg = {
            link,
            style,
            target: container,
            postion: 'beforeEnd',
            name: lastItem(src.split('?')[0].split('/').filter(x => x)),
          }
          createDom(cfg)
        }

      }
    })
  } else if (hostname === "www.kuaishou.com") {
    window.addEventListener('mouseover', ({
      target
    }) => {
      if (target && target.parentElement) {
        const container = target.parentElement.parentElement || {
          className: ''
        }
        if (container && container.className.includes('kwai-player') && container.querySelector('video')) {
          const src = (container.querySelector('source') || container.querySelector('video')).src
          const link = src
          const style = 'left: 10px;top: 10px;'
          const cfg = {
            link,
            style,
            target: container,
            postion: 'beforeEnd',
            name: lastItem(src.split('?')[0].split('/').filter(x => x)),
          }
          createDom(cfg)
        }

      }
    })
  } else if (hostname === "www.xiaohongshu.com") {
    window.addEventListener('mouseover', ({
      target
    }) => {
      const container = target && target.parentElement
      if (container && container.className && container.className.includes('carousel')) {
        const inner = container.querySelector('li:not([style*=none]) .inner')
        const src = inner && inner.style['background-image'].replace(/^url\(\"|\"\)$/g, '')
        const link = src
        const style = 'left: 10px;top: 10px;'
        const cfg = {
          link,
          style,
          parent: container,
          postion: 'beforeEnd',
          name: lastItem(src.split('?')[0].split('/').filter(x => x)) + '.jpg',
        }
        createDom(cfg)
      }


    })
  }

}

setTimeout(() => {
  init()
}, 1500);