下载原始图片

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

目前为 2022-01-22 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Download Original Picture
  3. // @name:zh-CN 下载原始图片
  4. // @description A tool to help you download full size images from websites
  5. // @description:zh-CN 一个帮你从网站下载原始尺寸图片的工具
  6. // @namespace https://huching.net/
  7. // @version 0.1.0
  8. // @license GPL-3.0
  9. // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTA4IDUwOCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+IDxjaXJjbGUgc3R5bGU9ImZpbGw6I0ZGRDA1QjsiIGN4PSIyNTQiIGN5PSIyNTQiIHI9IjI1NCIvPiA8cGF0aCBzdHlsZT0iZmlsbDojRkZGRkZGOyIgZD0iTTM3Mi44LDE5NkgzNjhjLTIuNC00MC40LTM1LjYtNzIuNC03Ni40LTcyLjRjLTQsMC04LDAuNC0xMS42LDAuOGMtMTYtMjguNC00Ni00Ny42LTgwLjgtNDcuNiBjLTUxLjIsMC05Mi40LDQxLjYtOTIuNCw5Mi40YzAsMTAuOCwyLDIxLjIsNS4yLDMwLjhjLTI1LjIsMTAtNDIuOCwzNC00Mi44LDYyLjRjMCwzNi40LDI5LjYsNjYuNCw2Ni40LDY2LjRoMjM3LjIgYzM2LjQsMCw2Ni40LTI5LjYsNjYuNC02Ni40QzQzOC44LDIyNS42LDQwOS4yLDE5NiwzNzIuOCwxOTZ6Ii8+IDxwYXRoIHN0eWxlPSJmaWxsOiNGRjcwNTg7IiBkPSJNMzI1LjIsMzYyLjRsLTY2LjQsNjYuNGMtMi44LDIuOC03LjIsMi44LTEwLDBsLTY2LTY2LjRjLTQuNC00LjQtMS4yLTEyLDQuOC0xMmgxNC44IGM0LDAsNy4yLTMuMiw3LjItNy4ydi05NmMwLTQsMy4yLTcuMiw3LjItNy4yaDc0LjhjNCwwLDcuMiwzLjIsNy4yLDcuMnY5NmMwLDQsMy4yLDcuMiw3LjIsNy4yaDE0LjggQzMyNi40LDM1MC40LDMyOS42LDM1OCwzMjUuMiwzNjIuNHoiLz4gPC9zdmc+IA==
  10. // @author huc < ht@live.se >
  11. // @supportURL https://github.com/hz2/user-scripts-and-styles/issues/new
  12. // @require https://gf.qytechs.cn/scripts/396752-hx-script-library/code/hx-script-library.js
  13. // @resource HxLib https://gf.qytechs.cn/scripts/396752-hx-script-library/code/hx-script-library.js
  14. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=your.email.here@example.com&item_name=Greasy+Fork+donation
  15. // @contributionAmount 5
  16. // @include *://medium.com/*
  17. // @include *://twitter.com/*
  18. // @include *://mobile.twitter.com/*
  19. // @include *://weibo.com/*
  20. // @include *://*.weibo.com/*
  21. // @include *://*.vmgirls.com/*
  22. // @include *://wallpaperhub.app/*
  23. // @include *://*.bing.com/*
  24. // @include *://*.msn.cn/*
  25. // @include *://instagram.com/*
  26. // @include *://*.instagram.com/*
  27. // @include *://instagram.com/*
  28. // @include *://*.instagram.com/*
  29. // @include *://tiktok.com/*
  30. // @include *://*.tiktok.com/*
  31. // @include *://*.douyin.com/*
  32. // @include *://*.kuaishou.com/*
  33. // @include *://*.xiaohongshu.com/*
  34.  
  35. // @noframes
  36. // @grant unsafeWindow
  37. // @grant GM_setClipboard
  38. // @grant GM_xmlhttpRequest
  39. // @grant GM_openInTab
  40. // @grant GM_registerMenuCommand
  41. // @grant GM_getValue
  42. // @grant GM_setValue
  43. // @grant GM_getResourceText
  44. // @grant GM_info
  45. // @grant GM_addStyle
  46. // ==/UserScript==
  47.  
  48. const head = document.getElementsByTagName('head');
  49. head[0].insertAdjacentHTML('beforeend', `<style type="text/css">
  50. .hx-download-original-images-tool{
  51. position: absolute;
  52. background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTA4IDUwOCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+IDxjaXJjbGUgc3R5bGU9ImZpbGw6I0ZGRDA1QjsiIGN4PSIyNTQiIGN5PSIyNTQiIHI9IjI1NCIvPiA8cGF0aCBzdHlsZT0iZmlsbDojRkZGRkZGOyIgZD0iTTM3Mi44LDE5NkgzNjhjLTIuNC00MC40LTM1LjYtNzIuNC03Ni40LTcyLjRjLTQsMC04LDAuNC0xMS42LDAuOGMtMTYtMjguNC00Ni00Ny42LTgwLjgtNDcuNiBjLTUxLjIsMC05Mi40LDQxLjYtOTIuNCw5Mi40YzAsMTAuOCwyLDIxLjIsNS4yLDMwLjhjLTI1LjIsMTAtNDIuOCwzNC00Mi44LDYyLjRjMCwzNi40LDI5LjYsNjYuNCw2Ni40LDY2LjRoMjM3LjIgYzM2LjQsMCw2Ni40LTI5LjYsNjYuNC02Ni40QzQzOC44LDIyNS42LDQwOS4yLDE5NiwzNzIuOCwxOTZ6Ii8+IDxwYXRoIHN0eWxlPSJmaWxsOiNGRjcwNTg7IiBkPSJNMzI1LjIsMzYyLjRsLTY2LjQsNjYuNGMtMi44LDIuOC03LjIsMi44LTEwLDBsLTY2LTY2LjRjLTQuNC00LjQtMS4yLTEyLDQuOC0xMmgxNC44IGM0LDAsNy4yLTMuMiw3LjItNy4ydi05NmMwLTQsMy4yLTcuMiw3LjItNy4yaDc0LjhjNCwwLDcuMiwzLjIsNy4yLDcuMnY5NmMwLDQsMy4yLDcuMiw3LjIsNy4yaDE0LjggQzMyNi40LDM1MC40LDMyOS42LDM1OCwzMjUuMiwzNjIuNHoiLz4gPC9zdmc+IA==);
  53. background-size: cover;
  54. width: 50px;
  55. height: 50px;
  56. cursor: pointer;
  57. opacity: .35;
  58. z-index: 50000;
  59. transform: scale(.75);
  60. transition: all cubic-bezier(0.18, 0.89, 0.32, 1.28) 250ms;
  61. }
  62. .hx-download-original-images-tool.white{
  63. background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIGZpbGw9ImluaGVyaXQiIGltcGxpY2l0LWNvbnNlbnQtc291cmNlPSJ0cnVlIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMDEyMiAwIDAgMS4wMTIyIC0yOC42ODQgLTMuNDMzOSkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjMiPgogIDxjaXJjbGUgY3g9IjQwLjE5NCIgY3k9IjE1LjI0OCIgcj0iOC45ODI0Ii8+CiAgPHBhdGggZD0ibTQ1IDE3LTQuNTMzIDMuNTQ3Yy0wLjE2NjU5IDAuMTMwMzUtMC4zODQ2MSAwLjE0OTU3LTAuNTM0MTggMGwtNC41NjY0LTMuNTQ3Yy0wLjIzNTA0LTAuMjM1MDQtMC4wNjQxLTAuNjQxMDIgMC4yNTY0MS0wLjY0MTAyaDIuNDM2MmMwLjIxMzY3IDAgMC4zODQ2MS0wLjE3MDk0IDAuMzg0NjEtMC4zODQ2MXYtNS43MzI5YzAtMC4yMTM2NyAwLjE3MDk0LTAuMzg0NjEgMC4zODQ2MS0wLjM4NDYxaDIuNzAzNmMwLjIxMzY3IDAgMC4zODQ2MSAwLjE3MDk0IDAuMzg0NjEgMC4zODQ2MXY1LjczMjljMCAwLjIxMzY3IDAuMTcwOTQgMC4zODQ2MSAwLjM4NDYxIDAuMzg0NjFoMi40NjM5YzAuMjk5MTQgMCAwLjQ5NjgyIDAuNDM2MTggMC4yMzUwNCAwLjY0MTAyeiIvPgogPC9nPgo8L3N2Zz4K);
  64. width: 24px;
  65. height: 24px;
  66. }
  67. .hx-download-original-images-tool:hover {
  68. opacity:1;
  69. transform: scale(.9);
  70. }
  71. .hx-download-original-images-tool:active {
  72. opacity:.8;
  73. transform: scale(.7) rotateZ(360deg);
  74. }
  75. </style>`);
  76.  
  77.  
  78. 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;');
  79.  
  80. const openDown = (url, e, name) => {
  81. e && e.preventDefault();
  82. e && e.stopPropagation()
  83.  
  84.  
  85. const downBlobUrl = (blobUrl) => {
  86. let el = document.createElement("a");
  87. el.setAttribute("href", blobUrl);
  88. if (name) {
  89. el.setAttribute("download", name)
  90. }
  91. if (document.createEvent) {
  92. const event = document.createEvent("MouseEvents");
  93. event.initEvent("click", true, true);
  94. el.dispatchEvent(event);
  95. } else {
  96. el.click();
  97. }
  98.  
  99. }
  100.  
  101. if (url.startsWith('blob')) {
  102. downBlobUrl(url)
  103. return
  104.  
  105. }
  106.  
  107.  
  108. fetch(url, {
  109. mode: "cors"
  110. })
  111. .then(resp => resp.blob())
  112. .then(r => {
  113. const blobUrl = URL.createObjectURL(r)
  114. downBlobUrl(blobUrl)
  115. })
  116. .catch(err => {
  117. console.log("Request failed", err);
  118. });
  119. }
  120.  
  121. const hostname = window.location.hostname
  122.  
  123. const lastItem = arr => arr.length ? arr[arr.length - 1] : ''
  124.  
  125. const createDomAll = (item, fn) => {
  126. let domDL = document.createElement('a');
  127. domDL.className = 'hx-download-original-images-tool'
  128. domDL.title = '下载原始图片'
  129.  
  130. item.addEventListener('load', _ => {
  131. let link = fn(item.src)
  132. domDL.href = link
  133. domDL.addEventListener('click', e => openDown(link, e))
  134. })
  135. item.insertAdjacentElement('afterEnd', domDL)
  136. }
  137.  
  138. const createDom = (cfg) => {
  139. const {
  140. parent,
  141. link,
  142. name,
  143. className = '',
  144. style = '',
  145. target,
  146. postion = 'afterEnd'
  147. } = cfg
  148.  
  149. const genDomDL = (dom) => {
  150. let domDL = dom || document.createElement('a');
  151. Object.assign(domDL, {
  152. title: '下载原始图片',
  153. className: 'hx-download-original-images-tool ' + className,
  154. style: style,
  155. href: link,
  156. })
  157. domDL.onclick = e => {
  158. e && e.preventDefault();
  159. e && e.stopPropagation()
  160. const newName = name || lastItem(link.split('/'))
  161. openDown(link, e, newName)
  162. }
  163. return domDL
  164. }
  165.  
  166. let parent2 = parent
  167. if (!parent && target) {
  168. parent2 = target.parentElement
  169. }
  170. if (['afterEnd', 'beforeBegin'].includes(postion)) {
  171. parent2 = target.parentElement.parentElement
  172. }
  173. const exist = parent2.querySelector('.hx-download-original-images-tool')
  174. if (exist) {
  175. genDomDL(exist)
  176. } else {
  177. parent2.insertAdjacentElement(postion, genDomDL())
  178. }
  179. }
  180.  
  181. const updateLink = (dom, link) => {
  182. dom.href = link
  183. const newName = lastItem(link.split('/'))
  184. dom.onclick = e => openDown(link, e, newName)
  185. }
  186.  
  187. const init = () => {
  188.  
  189. if (hostname === "twitter.com" || hostname === "mobile.twitter.com") {
  190. //twitter
  191. window.addEventListener('mouseover', ({
  192. target
  193. }) => {
  194. const src = target && target.src
  195. const parent = target.parentElement
  196. const next = parent && parent.nextElementSibling
  197. if (target.tagName == 'IMG' &&
  198. !(next && next.className.includes('hx-download-original-images-tool')) &&
  199. !/profile_images|video_thumb/g.test(src)) {
  200. const link = src.replace(/\&name=\w+/g, '&name=orig')
  201. const name = lastItem(link.split('/')).replace(/\?format=(\w+)\&name=orig/g, (_, b) => `.${b}`)
  202. const style = 'margin-left: 10px;margin-top: 10px;'
  203. const cfg = {
  204. parent,
  205. link,
  206. name,
  207. style
  208. }
  209. createDom(cfg)
  210. }
  211. })
  212. } else if (hostname.includes('weibo')) {
  213. const isWeiboNode = dom => {
  214. const getNodeValue = el => el.attributes['node-type'] && el.attributes['node-type'].nodeValue
  215. 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')) {
  216. return true
  217. } else {
  218. return false
  219. }
  220. }
  221. window.addEventListener('mouseover', ({
  222. target
  223. }) => {
  224. const parent = target.parentElement
  225. const next = parent && parent.nextElementSibling
  226. if (target.tagName == 'IMG' && isWeiboNode(parent)) {
  227. const link = target.src.replace(/orj\d+|mw\d+/g, 'large')
  228. if (next && next.className.includes('hx-download-original-images-tool')) {
  229. updateLink(next, link)
  230. } else {
  231. const style = 'top: 40px;right: 10px;'
  232. const cfg = {
  233. parent,
  234. link,
  235. style
  236. }
  237. createDom(cfg)
  238. }
  239. }
  240. })
  241. } else if (hostname === "www.vmgirls.com") {
  242. // vmgirls
  243. let domDL = document.createElement('a');
  244. domDL.className = 'hx-download-original-images-tool '
  245. domDL.style = 'position: relative;margin-right: 10px;display: inline-block;vertical-align: -20px;'
  246. domDL.title = '下载原始图片'
  247. domDL.onclick = e => {
  248. const list1 = [...document.querySelector('.post').querySelectorAll('a')].filter(x => x.src && x.src.indexOf('static.vmgirls.com/image') !== -1)
  249. const list2 = [...document.querySelector('.post-content').querySelectorAll('img')].filter(x => x.src && x.src.indexOf('t.cdn.ink/image') !== -1)
  250. const imgList = [...list1, ...list2].map((x, i) => ({
  251. link: x.src && x.src.replace('-scaled', ''),
  252. name: `${x.alt || x.title}_${i}.jpg`
  253. }))
  254. domDL.title += ' ' + imgList.length
  255. imgList.forEach(x => openDown(x.link, e, x.name))
  256. const link1 = imgList.map(x => x.link).join('\n')
  257. const link2 = imgList.map(x => `aria2c -o ${x.name} ${x.link}`).join('\n')
  258. const content = `<html><head><meta charset="utf-8"><title>获取链接</title></head><body><textarea style="width: 850px; height: 250px; margin: 30px;">${link1}</textarea>
  259. <textarea style="width: 850px; height: 250px; margin: 30px;">${link2}</textarea>
  260. </body></html>`
  261. window.open(URL.createObjectURL(new Blob([content], {
  262. type: 'text/html'
  263. })))
  264. }
  265. document.querySelector('.main-submenu').insertAdjacentElement('afterBegin', domDL)
  266. } else if (hostname === "medium.com") {
  267. // medium
  268. document.querySelector('article').querySelectorAll('img').forEach(x => (x.width > 80) && createDomAll(x, src => src.replace(/max\/\d+\//g, 'max/30000/')))
  269. } else if (hostname === "wallpaperhub.app") {
  270. // wallpaperhub
  271. const odomList = [...document.querySelectorAll('.downloadButton')]
  272. odomList.forEach(odom => {
  273. if (odom) {
  274. let link0 = odom.href.split('downloadUrl=')[1]
  275. const link = link0
  276. const style = 'position: relative;margin-right: 10px;display: inline-block;vertical-align: -20px;'
  277. const cfg = {
  278. parent: odom.parentElement.parentElement,
  279. link,
  280. style,
  281. postion: 'beforeBegin'
  282. }
  283. createDom(cfg)
  284. }
  285. })
  286. } else if (hostname === "ntp.msn.cn") {
  287. // edge 首页
  288. const link = document.querySelector('background-image')._imageSource;
  289. const style = 'position: fixed;right: 80px;top: 40px;'
  290. const cfg = {
  291. parent: document.body,
  292. link,
  293. className: 'white',
  294. style,
  295. postion: 'beforeBegin'
  296. }
  297. createDom(cfg)
  298. } else if (hostname === "www.bing.com") {
  299. // bing 首页
  300. const orig = document.querySelector('[style*="th?id="]').style.backgroundImage
  301. const link = orig.match(/th\?id\=[\w\d\.\-\_]+/g)[0].replace('1920x1080', 'UHD')
  302. const name = link && link.split('=')[1]
  303. const style = 'position: relative;width: 42px;height: 42px;margin: 0;opacity: .9;'
  304. const cfg = {
  305. parent: document.querySelector('#id_h'),
  306. link,
  307. name,
  308. className: 'white',
  309. style,
  310. postion: 'afterBegin'
  311. }
  312. createDom(cfg)
  313. } else if (hostname === "cn.bing.com") {
  314. // bing 首页
  315. const link = document.querySelector('#bgImgProgLoad').dataset.ultraDefinitionSrc.split('&')[0];
  316. const name = link && link.split('=')[1]
  317. const style = 'position: fixed;right: 225px;bottom: 53px;margin: 0px;width: 64px;height: 64px;z-index: 550;opacity: .9;'
  318. const cfg = {
  319. parent: document.body,
  320. link,
  321. name,
  322. className: 'white',
  323. style,
  324. postion: 'beforeBegin'
  325. }
  326. createDom(cfg)
  327. } else if (hostname === "www.instagram.com") {
  328. window.addEventListener('mouseover', ({
  329. target
  330. }) => {
  331. const el = target.previousElementSibling
  332. const el2 = target.parentElement
  333. const img = (el && el.querySelector('img:not([data-testid])') || el2 && el2.querySelector('video:not([data-testid])'))
  334. if (img) {
  335. const src = img.src
  336. const parent = img.parentElement
  337. const link = src
  338. const style = 'left: 10px;top: 10px;'
  339. const cfg = {
  340. parent,
  341. link,
  342. style,
  343. target: img,
  344. name: img.alt ? (img.alt + '.jpg') : src.split(/[\?\/]/g).filter(x => x.endsWith('.jpg'))[0],
  345. postion: 'beforeEnd'
  346. }
  347. createDom(cfg)
  348. }
  349. })
  350. } else if (hostname === "www.tiktok.com") {
  351. window.addEventListener('mouseover', ({
  352. target
  353. }) => {
  354. if (target.tagName == 'VIDEO') {
  355. const src = target.src
  356. const parent = target.parentElement
  357. const link = src
  358. const style = 'left: 10px;top: 10px;'
  359. const cfg = {
  360. parent,
  361. link,
  362. style,
  363. target,
  364. name: lastItem(src.split('?')[0].split('/').filter(x => x)),
  365. postion: 'beforeEnd'
  366. }
  367. createDom(cfg)
  368. }
  369. })
  370. } else if (hostname === "www.douyin.com") {
  371. window.addEventListener('mouseover', ({
  372. target
  373. }) => {
  374. // if (target && target.tagName === 'VIDEO') {
  375. // const src = (target.querySelector('source') || target).src
  376. // const link = src
  377. // const style = 'left: 10px;top: 10px;'
  378. // const cfg = {
  379. // link,
  380. // style,
  381. // target,
  382. // postion: 'afterEnd',
  383. // name: lastItem(src.split('?')[0].split('/').filter(x => x)),
  384. // }
  385. // createDom(cfg)
  386. // return
  387. // } else
  388. if (target && target.parentElement) {
  389. const container = target.parentElement.parentElement || {
  390. className: ''
  391. }
  392. if (container && container.className.includes('videoContainer') && container.querySelector('video')) {
  393. const src = (container.querySelector('source') || container.querySelector('video')).src
  394. const link = src
  395. const style = 'left: 10px;top: 10px;'
  396. const cfg = {
  397. link,
  398. style,
  399. target: container,
  400. postion: 'beforeEnd',
  401. name: lastItem(src.split('?')[0].split('/').filter(x => x)),
  402. }
  403. createDom(cfg)
  404. }
  405.  
  406. }
  407. })
  408. } else if (hostname === "www.kuaishou.com") {
  409. window.addEventListener('mouseover', ({
  410. target
  411. }) => {
  412. if (target && target.parentElement) {
  413. const container = target.parentElement.parentElement || {
  414. className: ''
  415. }
  416. if (container && container.className.includes('kwai-player') && container.querySelector('video')) {
  417. const src = (container.querySelector('source') || container.querySelector('video')).src
  418. const link = src
  419. const style = 'left: 10px;top: 10px;'
  420. const cfg = {
  421. link,
  422. style,
  423. target: container,
  424. postion: 'beforeEnd',
  425. name: lastItem(src.split('?')[0].split('/').filter(x => x)),
  426. }
  427. createDom(cfg)
  428. }
  429.  
  430. }
  431. })
  432. } else if (hostname === "www.xiaohongshu.com") {
  433. window.addEventListener('mouseover', ({
  434. target
  435. }) => {
  436. const container = target && target.parentElement
  437. if (container && container.className && container.className.includes('carousel')) {
  438. const inner = container.querySelector('li:not([style*=none]) .inner')
  439. const src = inner && inner.style['background-image'].replace(/^url\(\"|\"\)$/g, '')
  440. const link = src
  441. const style = 'left: 10px;top: 10px;'
  442. const cfg = {
  443. link,
  444. style,
  445. parent: container,
  446. postion: 'beforeEnd',
  447. name: lastItem(src.split('?')[0].split('/').filter(x => x)) + '.jpg',
  448. }
  449. createDom(cfg)
  450. }
  451.  
  452.  
  453. })
  454. }
  455.  
  456. }
  457.  
  458. setTimeout(() => {
  459. init()
  460. }, 1500);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址