下载微博图片和视频

一键下载一条微博中的图片,文件名包含该微博的路径.xxx_wb_uid_wid,可恢复为 https://weibo.com/uid/wid

  1. // ==UserScript==
  2. // @name 下载微博图片和视频
  3. // @name:en Download Weibo Images and Video
  4. // @namespace https://greasyfork.org/zh-CN/users/127123-flao
  5. // @version 1.5.2
  6. // @description 一键下载一条微博中的图片,文件名包含该微博的路径.xxx_wb_uid_wid,可恢复为 https://weibo.com/uid/wid
  7. // @description:en Download images from weibo with user-id and weibo-id in its filename. filname format xxx_wb_uid_wid
  8. // @author Flao
  9. // @match https://weibo.com/*
  10. // @match https://www.weibo.com/*
  11. // @grant none
  12. // @license MIT License
  13. // @run-at document-end
  14. // @connect *://*.sinaimg.cn
  15. // ==/UserScript==
  16.  
  17.  
  18. (function() {
  19.  
  20. var doDownload = function(blob, filename) {
  21. var a = document.createElement('a');
  22. a.download = filename;
  23. a.href = blob;
  24. a.click();
  25. }
  26.  
  27. // Current blob size limit is around 500MB for browsers
  28. var download = function (url, filename) {
  29. if (!filename) filename = url.split('\\').pop().split('/').pop();
  30. fetch(url, {
  31. headers: new Headers({
  32. 'Origin': location.origin
  33. }),
  34. mode: 'cors'
  35. })
  36. .then(response => response.blob())
  37. .then(blob => {
  38. let blobUrl = window.URL.createObjectURL(blob);
  39. doDownload(blobUrl, filename);
  40. })
  41. .catch(e => {console.error(e); return false;});
  42.  
  43. return true;
  44. }
  45.  
  46. var toast = function(text, duration) {
  47. if(isNaN(duration)) duration = 1500;
  48. let _toast = document.createElement('div');
  49. _toast.innerText = text;
  50. _toast.style.cssText = 'width: 60%; height:50px; line-height: 50px; min-width:100px;text-align: center; font-size: 15px;' +
  51. 'position: fixed; top: 60%; left: 40%; background: rgb(0,0,0); color:rgb(255,255,255); opacity:0.75; z-index: 999';
  52. document.body.children[0].appendChild(_toast);
  53.  
  54. _toast.style.transition = 'all 0.7s';
  55. _toast.style.webkitTransition = 'all 0.7s';
  56.  
  57. setTimeout(function() {
  58. _toast.style.opacity = 0;
  59. setTimeout(()=> { document.body.children[0].removeChild(_toast);},700);
  60.  
  61. }, duration);
  62. }
  63.  
  64. // global variables
  65. var globalValue = "";
  66. var inputBoxDict = new Map();
  67. var proceedList = new WeakSet();
  68. var imgPathReg = new RegExp("(https://[\\S]+/)([\\S]+)(/[\\S]+)");
  69.  
  70. var buttonOnClick = function(e) {
  71. let buttonData = inputBoxDict.get(this); // path
  72. let inputName = this.previousSibling.value && this.previousSibling.value.split('@')[0];
  73.  
  74. let fileName = (inputName && inputName + '_') + 'wb_' + buttonData[0] + '_' + buttonData[1];
  75.  
  76. var imgList = this.parentNode.parentNode.getElementsByClassName('media_box')[0].children[0].children; // media_box > ul >li
  77. // set the page mask
  78. let pages = this.previousSibling.value.split('@')[1];
  79. let temp = /[0-9]*/.exec(pages);
  80. pages = temp && temp[0];
  81. let mask = new Uint8Array(imgList.length);
  82. if(!pages){
  83. mask.fill(1);
  84. }
  85. else {
  86. console.log(pages, '_', pages.length);
  87. for(var i = 0; i < pages.length; i++) {
  88. let num = pages[i] - 1;
  89. if(num > mask.length || num < 0) continue;
  90. mask[num] = 1;
  91. }
  92. }
  93. console.log(mask);
  94. // check if the media is video
  95. let firstMediaClass = imgList[0].classList[0];
  96. if(firstMediaClass === 'WB_video') {
  97. let videoElem = imgList[0].getElementsByTagName('video')[0];
  98. let result = download(videoElem.src, fileName);
  99. if(result === false) {toast('下载出错,详见控制台');}
  100. else {toast('下载开始');}
  101. return;
  102. }
  103. // else download images
  104. var failedList = [];
  105. for(var j = 0; j < imgList.length; j++) {
  106. if(mask[j] === 0) continue;
  107. let result = true;
  108. let child = imgList[j].children[0];
  109. var imgsrc = '';
  110. // check whether picture or gif
  111. if(child.tagName === 'IMG') {
  112. imgsrc = child.src.replace(imgPathReg,'$1large$3'); // replace ....sinaming.cn/XXX/YYY.jpg' with '...sinaimg.cn/large/YYY.jpg'
  113. result = download(imgsrc, fileName + '_' + j);
  114. }
  115. else {
  116. imgsrc = child.children[0].src.replace(imgPathReg, '$1large$3');
  117. result = download(imgsrc, fileName + '_' + j + '.gif');
  118. }
  119. if(result === false) failedList.push(j+1);
  120. }
  121. if(failedList.length !== 0) {
  122. toast('第 ' + failedList + ' 下失败,详见控制台');
  123. }
  124. else {
  125. toast('全部下载开始');
  126. }
  127. }
  128.  
  129. var getWeiboPath = function(media_box) {
  130. var path = "";
  131. if(media_box.parentNode.nextElementSibling &&
  132. media_box.parentNode.nextElementSibling.classList.contains('WB_func')) {
  133. path = media_box.parentNode.nextElementSibling.children[0].children[0].children[0].children[0].children[0].href;
  134. // let date = media_box.parentNode.nextElementSibling.children[0].children[0].children[0].children[0].children[0].title;
  135. path = path.split("?")[0].split("/").slice(3,5);
  136. }
  137. else {
  138. path = media_box.parentNode.parentNode.children[1].children[0].href; // in an independent weibo page
  139. //let date = media_box.parentNode.parentNode.children[1].children[0].title;
  140. path = path.split("?")[0].split("/").slice(3,5);
  141.  
  142. }
  143. return path;
  144.  
  145. }
  146.  
  147. var addFunction = function(){
  148. var lists = document.getElementsByClassName('media_box');
  149. console.log('media_box list.length = ' + lists.length);
  150. for( var i = 0; i < lists.length; i++) {
  151. var list = lists[i].parentNode.parentNode.children[1];
  152. if(proceedList.has(list)) {
  153. continue;
  154. }
  155. proceedList.add(list);
  156. var inputBox = document.createElement('input');
  157. inputBox.style.width = '20%';
  158. inputBox.style.height = '70%';
  159. inputBox.style.float = "right";
  160. inputBox.style.marginLeft = '5px';
  161. inputBox.style.opacity = "0.2";
  162.  
  163. var button = document.createElement('a');
  164. button.setAttribute('class','S_txt2');
  165. button.innerText = '下载图片';
  166. button.href = 'javascript:void(0)';
  167. button.input = inputBox;
  168.  
  169. var path = getWeiboPath(lists[i]);
  170. button.onclick = buttonOnClick;
  171. button.style.float = "right";
  172.  
  173. inputBoxDict.set(button,path);
  174.  
  175. list.appendChild(inputBox);
  176. list.appendChild(button);
  177. }
  178. }
  179. window.addEventListener ("load", ()=>{
  180. setTimeout(addFunction,1000);
  181. });
  182.  
  183. (function () {
  184. var DOMObserverTimer = false;
  185. var DOMObserverConfig = {
  186. attributes: true,
  187. childList: true,
  188. subtree: true
  189. };
  190. var DOMObserver = new MutationObserver(function () {
  191. if (DOMObserverTimer !== 'false') {
  192. clearTimeout(DOMObserverTimer);
  193. }
  194. DOMObserverTimer = setTimeout(function () {
  195. DOMObserver.disconnect();
  196. addFunction();
  197. DOMObserver.observe(document.body, DOMObserverConfig);
  198. }, 1000);
  199. });
  200. DOMObserver.observe(document.body, DOMObserverConfig);
  201. }) ();
  202.  
  203. })();