Greasy Fork is available in English.

微博超话图片下载

提供超话内原图下载,优化超话浏览体验

Устаревшая версия за 21.03.2023. Перейдите к последней версии.

  1. // ==UserScript==
  2. // @name 微博超话图片下载
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5
  5. // @description 提供超话内原图下载,优化超话浏览体验
  6. // @author 乃木流架
  7. // @match https://weibo.com/p/*
  8. // @match https://weibo.com/u/*
  9. // @icon https://i.jpg.dog/26e8e3a48d8a079e3bca9bae1a96434b.png
  10. // @grant GM_download
  11. // @run-at document-start
  12. // @license GPL-3.0 License
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. ("use strict");
  17.  
  18. console.log("🏳️‍🌈[微博超话图片下载]脚本开始执行");
  19.  
  20. //自定义用户主页背景图片
  21. //图床:https://jpg.dog/
  22. const urlNew = "https://i.jpg.dog/f5651b662ec09801fdd4a54285038ee1.jpeg";
  23.  
  24. //默认主页背景图片
  25. const urlDefault1 =
  26. "https://ww1.sinaimg.cn/mw2000/70ace9b7ly1ggzusnypoej20yi0yiaop.jpg";
  27. const urlDefault2 =
  28. "https://wx1.sinaimg.cn/mw2000/001WLsZ7ly1gs69906b4pj60u00u0wiu02.jpg";
  29.  
  30. /**
  31. * @desc 属性改变监听,属性被set时出发watch的方法,类似vue的watch
  32. * @author Jason
  33. * @study https://www.jianshu.com/p/00502d10ea95
  34. * @data 2018-04-27
  35. * @constructor
  36. * @param {object} opts - 构造参数. @default {data:{},watch:{}};
  37. * @argument {object} data - 要绑定的属性
  38. * @argument {object} watch - 要监听的属性的回调
  39. * watch @callback (newVal,oldVal) - 新值与旧值
  40. */
  41.  
  42. class watcher {
  43. constructor(opts) {
  44. this.$data = this.getBaseType(opts.data) === "Object" ? opts.data : {};
  45. this.$watch = this.getBaseType(opts.watch) === "Object" ? opts.watch : {};
  46. for (let key in opts.data) {
  47. this.setData(key);
  48. }
  49. }
  50.  
  51. getBaseType(target) {
  52. const typeStr = Object.prototype.toString.apply(target);
  53.  
  54. return typeStr.slice(8, -1);
  55. }
  56.  
  57. setData(_key) {
  58. Object.defineProperty(this, _key, {
  59. get: function () {
  60. return this.$data[_key];
  61. },
  62. set: function (val) {
  63. const oldVal = this.$data[_key];
  64. if (oldVal === val) return val;
  65. this.$data[_key] = val;
  66. this.$watch[_key] &&
  67. typeof this.$watch[_key] === "function" &&
  68. this.$watch[_key].call(this, val, oldVal);
  69. return val;
  70. },
  71. });
  72. }
  73. }
  74.  
  75. // export default watcher;
  76.  
  77. const picImpl = "https://weibo.com/ajax/statuses/show?id=";
  78. let length = 15;
  79. let wm = new watcher({
  80. data: {
  81. len: length,
  82. },
  83. watch: {
  84. len(newVal, oldVal) {
  85. // console.log("length: ", length);
  86. console.log("🔢新微博条数:" + newVal);
  87. console.log("🔢旧微博条数:" + oldVal);
  88. if (newVal > length) {
  89. let faces = document.getElementsByClassName("WB_info");
  90. let i = length;
  91. length = faces.length;
  92. while (i < length) {
  93. let btn = initBtn();
  94. faces[i].appendChild(btn);
  95. // console.log(i);
  96. // console.log(faces[i]);
  97. handleBtn(btn);
  98. i++;
  99. }
  100. }
  101. },
  102. },
  103. });
  104.  
  105. function sendAjax(type, url) {
  106. let xhr = new XMLHttpRequest();
  107. // 拼接所需要的的值
  108. // 所要拼接的值 + 里面填获取值的参数+ "&或者的意思" 最后拼接的直接+获取值的参数
  109. xhr.open(type, url, false);
  110. xhr.send();
  111. // xhr.onreadystatechange = function () {
  112. // if (xhr.readyState == 4 && xhr.readyState == 200) {
  113. // // 这个是转化为字符串的形式
  114. // let data = JSON.parse(xhr.responseText);
  115. // callback(data);
  116. // }
  117. // };
  118. return JSON.parse(xhr.responseText);
  119. }
  120.  
  121. function initBtn() {
  122. let div = document.createElement("div");
  123. let img = document.createElement("img");
  124. let a = document.createElement("a");
  125. // img.src = "https://i.jpg.dog/72dbffd3545cb15b148682beaf0fb64a.png";
  126. // img.src = "https://i.jpg.dog/d5380c9048e6ee303f188da9ec574399.png";
  127. img.src =
  128. "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEMAAABDCAYAAADHyrhzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFMElEQVR4nO2baYgcRRTHKzGJqFlFvDDRL16RCB6sG3f7vdnxQ+KBB3gEL4R8cVFUZN0se8x7U4giqIj4TZB4bEAJKIpCUBA0+SCaLwoKUYOKmCBoNEYYp6vGWFJzrLs7PTO93V3dk539Q8F8merXv36vjveqhFhWd8iMDp5kZP7MssQLygXvwpL01hm56VSxlGWkWKmkd6UmHNUEM4rhc0VwRDOaoKYYfM34tWZ8WxE+WSngZgtOHM8AKgxbai+Ph1u9eNhmASmCjxTltplxr08cDzITm0/ThAXNeDAugJZgCEua4BWfvA2iG2XGvT7F8JRi+NMVhAAoxzTjrq6C4jPcogl/SgtCcwihVgQvGplfmxkEMzlwhmJ4PysITY3we81DA6mD0NO5TZrhh8wBNIUOVDThhBFiRSogfILb69Of6eL2upH5VU5B6AI8XB+4sn7ZMGHznrP1iWZ4xI1r4zFFUHbU924z0r86URCK8G43HgHflWT+PCM3rtEMO914CMwkNoZo9oYUoXJkKP8PHK5wGDIyNggziadrgh+dGcmwvfEsn4YvdvUc69V2jxMLhmZ4xx2I9GDUgMAvdpccCYTPuTvcgkgXRr3tWDQII/tPdhse2cBQjP9qxvyiYGjGYgpfKQvPsOPHvvBeMbblFEXw21KFYVul4F0X0itge1pGZQVDEe7t7BVCrKjt/pY2jCoQiZe394pCbjhNgzKFwfBspxB5uVdgaMJDNlfbBgYe7BkYtdYfCMKXQ5emb0zGMCg33sIrvAd7DYbd4gfCUIwv9RoMO260gvFxz8FgNIElTU14qBdh6Gnv6qbFlmL4pxdhVDh3U/MulTP4Kl0Aw6Y058OYuuacnoVRxAfmwShJb12vwrBLivmeMe719SoMVfTuWzBmiJX1LFDEugfuVoSfpg7DZuMI3lKMf0SF4ZN3a9A643CkDglHZ6dnhsm0YNjDK3bgr/3X2xBjNoRmGBTly9p5Ggbn9mMLv65hVEEsKB0qhl+j2G+m8KwmGJrwtWhk4dWAviZcwQgCYYvhUWxXhL83gYib7lOEL4hIQBYHIwhEheHGqKcCWqb/NA8NRIXRALKwpqkJxpKCoRj22GT1fBC56+MUrRXBE4EwzNatJ7Q7kugGSDgYLkDYVinAtYEwrOw0FafzBhAROmQ6w0g6NObYedQ8esOJopV8htviwlich7SH4cojQpUajdy4JqkCUjggrWE4BtE+RBpSBM8n8bBwIRMMw1VozDaCb9tmxhsy07lzkzxW1N5DmmG49oiaTbltIqxUwvnQlkAIxubCSAOEPcBrh4PQMErTg+sV419JA1n4HCOHzp79Pe71OQ2Nhh1FvCc0iIY04+NJGtHKQ1opcY9ohGCUw25G5ldpwi9cAOkMwoFHEJRtoUxElW/jmPBomh7iwiPqbUTElSp6dzkwLBCIQxC7YoNoSDE+7RqIi9Coh8dnC2eoWDL2EAvjDjdA4BPN8Gb1RkDS/RPuj3zcsfOACjMugDhphPv/LuTOF65kbOWN4JnMX7Sjt+G+wHSeC+kCPtS9d05gZyNRnJoUDV+lCQ90jzdAWRM8JrKSkfm1ivA5e2kuUxCMH9o1kegGKYLLFMEHqYMgPOAT3im6UdomlQnedX51i/ArRXCvzduKbldpenC9jV/N+GWCY8IRO7VX78andTsxaZXl4EV2X6AJ3tCM34QeXwh+roYewZSt2jm/jZiFzEj/al/iJTYHWSG8uXr/rYj322S0/er2elamt5eXtSwxV/8B8CHKT9TokA8AAAAASUVORK5CYII=";
  129. img.setAttribute(
  130. "style",
  131. "width:12px;height:12px;margin-top:5px;margin-right:2px;"
  132. );
  133. a.innerHTML = "图片下载";
  134. a.setAttribute(
  135. "style",
  136. "padding:0;font-size: 12px;margin-top:1px;color:#333333;margin-top: 3px;"
  137. );
  138. div.appendChild(img);
  139. div.appendChild(a);
  140. div.setAttribute("class", "nogiruka-button");
  141. div.setAttribute(
  142. "style",
  143. "display: inline-flex;position:absolute;box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);border:1px solid #d9d9d9;height:21px;width:80px;background-color:#ffffff;font-color:#333333;font-size: 12px;text-align: center;border-radius: 2px;cursor: pointer;margin-left:5px;margin-bottom:5px;justify-content: center;"
  144. );
  145. return div;
  146. }
  147.  
  148. function addBtn() {
  149. let faces = document.getElementsByClassName("WB_info");
  150. let i = 0;
  151. length = faces.length;
  152. console.log("🔢初始微博条数: " + length);
  153. while (i < length) {
  154. let btn = initBtn();
  155. faces[i].appendChild(btn);
  156. // console.log(i);
  157. // console.log(faces[i]);
  158. handleBtn(btn);
  159. i++;
  160. }
  161. }
  162.  
  163. function handleBtn(btn) {
  164. btn.addEventListener("click", function (e) {
  165. let detail = e.target.parentNode.parentNode;
  166. let from = detail.nextElementSibling;
  167. let href = from.firstElementChild.href;
  168. // console.log(detail);
  169. // console.log(from);
  170. // console.log(href);
  171. let mblogid = href.split("/")[href.split("/").length - 1];
  172. let url = picImpl + mblogid;
  173. // console.log(mblogid);
  174. // console.log(url);
  175. let response = sendAjax("GET", url);
  176. // console.log(response);
  177. const picInfos = response.pic_infos;
  178. const userName = response.user.screen_name;
  179. const text = response.text_raw;
  180. console.log("🌈微博用户:" + userName + "\n📝微博文案:\n" + text);
  181. let downloadList = [];
  182. if (picInfos) {
  183. console.log("💝开始下载图片。。。");
  184. let index = 0;
  185. for (const [id, pic] of Object.entries(picInfos)) {
  186. index += 1;
  187. let largePicUrl = pic.largest.url;
  188. let picName = largePicUrl
  189. .split("/")
  190. [largePicUrl.split("/").length - 1].split("?")[0];
  191. let ext = picName.split(".")[1];
  192. let dlName = userName + "-" + mblogid + "-" + index + "." + ext;
  193. downloadList.push({
  194. url: largePicUrl,
  195. name: dlName,
  196. headerFlag: true,
  197. });
  198. }
  199. // console.log(downloadList);
  200. handleDownloadList(downloadList);
  201. }
  202. });
  203. }
  204.  
  205. function handleDownloadList(downloadList) {
  206. for (const item of downloadList) {
  207. downloadWrapper(item.url, item.name, item.headerFlag);
  208. }
  209. }
  210.  
  211. const pro = {
  212. a: "🌚", //0-25
  213. b: "🌘", //25-50
  214. c: "🌓", //50
  215. d: "🌒", //50-75
  216. e: "🌝", //100
  217. };
  218. function downloadWrapper(url, name, headerFlag) {
  219. let textContent = name + " [0%]";
  220. let percent = 0;
  221. const download = GM_download({
  222. url,
  223. name,
  224. headers: headerFlag
  225. ? {
  226. Referer: "https://weibo.com/",
  227. Origin: "https://weibo.com/",
  228. }
  229. : null,
  230. // saveAs: false,
  231. onprogress: (e) => {
  232. // e = { int done, finalUrl, bool lengthComputable, int loaded, int position, int readyState, response, str responseHeaders, responseText, responseXML, int status, statusText, int total, int totalSize }
  233. percent = (e.done / e.total) * 100;
  234. percent = percent.toFixed(0);
  235. textContent = name + " [" + percent + "%]";
  236. if (percent < 25) {
  237. console.log(pro.a + textContent);
  238. } else if (percent >= 25 && percent < 50) {
  239. console.log(pro.b + textContent);
  240. } else if (percent >= 50 && percent < 75) {
  241. console.log(pro.c + textContent);
  242. } else if (percent >= 75 && percent < 100) {
  243. console.log(pro.d + textContent);
  244. } else {
  245. console.log(pro.e + textContent);
  246. }
  247.  
  248. // console.log(textContent);
  249. },
  250. onload: ({ status, response }) => {
  251. console.log("💖图片下载完毕。。。");
  252. },
  253. onerror: (e) => {
  254. console.log(e);
  255. },
  256. ontimeout: (e) => {
  257. console.log(e);
  258. },
  259. });
  260. }
  261.  
  262. function handleQ() {
  263. //搜索处理
  264. if (document.getElementsByClassName("username")[0]) {
  265. let username = document.getElementsByClassName("username")[0].innerText;
  266. let input = document.getElementsByClassName("W_input")[0];
  267. let q = username + "超话 ";
  268. let ph = document.getElementsByClassName("placeholder")[0];
  269. if (ph != null) {
  270. ph.remove();
  271. }
  272. // console.log(input.value);
  273. if (input.value != q) {
  274. input.value = q;
  275. }
  276. }
  277. }
  278.  
  279. function handleBack() {
  280. let back = document.getElementsByClassName("woo-picture-img")[0];
  281. if (back != null) {
  282. let url = back.src;
  283. // console.log(url != null);
  284. // console.log(url == urlDefault);
  285. // console.log(url);
  286. // console.log(urlDefault);
  287. if (url != null) {
  288. if (url == urlDefault1 || url == urlDefault2) {
  289. back.src = urlNew;
  290. }
  291. }
  292. }
  293. }
  294.  
  295. let ba = setInterval(() => {
  296. //更换用户主页背景图片
  297. handleBack();
  298. // console.log("更改用户主页背景图片。。。");
  299. }, 50);
  300. let go1 = true;
  301. let go2 = true;
  302. let currentLink = window.location.href;
  303. let jumpLink = "";
  304.  
  305. //全局循环器
  306. setInterval(() => {
  307. let back = document.getElementsByClassName("woo-picture-img")[0];
  308. jumpLink = window.location.href;
  309. //监听网页链接变化,刷新页面
  310. if (currentLink != jumpLink && /weibo.com\/u/.test(window.location.href)) {
  311. if (
  312. (back != null && back.src == urlDefault1) ||
  313. back.src == urlDefault2
  314. ) {
  315. window.location.href = jumpLink;
  316. }
  317. }
  318.  
  319. //伪超话内搜索
  320. handleQ();
  321.  
  322. //去除扫描二维码进入手机超话
  323. let qr = document.getElementById("Pl_Core_PicText__265");
  324. if (qr) {
  325. qr.remove();
  326. }
  327.  
  328. //背景图片监视停止
  329. if (go1) {
  330. if (!/weibo.com\/u/.test(window.location.href)) {
  331. go1 = false;
  332. clearInterval(ba);
  333. console.log("❎不是用户主页。。。");
  334. }
  335. if (/weibo.com\/u/.test(window.location.href) && back != null) {
  336. if (back.src != urlDefault1 && back.src != urlDefault2) {
  337. go1 = false;
  338. clearInterval(ba);
  339. console.log("✅背景图片已修改。。。");
  340. }
  341. }
  342. }
  343.  
  344. //翻页
  345. let nextPage = document.getElementsByClassName(
  346. "page next S_txt1 S_line1"
  347. )[0];
  348. // console.log(nextPage);
  349. if (nextPage != undefined && go2) {
  350. go2 = false;
  351. hr = nextPage.href;
  352. console.log("🚌下一页出现,地址为:" + hr);
  353. nextPage.addEventListener("click", function () {
  354. window.location.href = hr;
  355. });
  356. }
  357.  
  358. //微博条数监控
  359. let temp = document.getElementsByClassName("WB_info").length;
  360. if (temp != length && temp > length) {
  361. wm.len = temp;
  362. }
  363. }, 1000);
  364.  
  365. window.onload = function () {
  366. //图片下载按钮生成
  367. setTimeout(() => {
  368. if (/weibo.com\/p/.test(window.location.href)) {
  369. addBtn();
  370. }
  371. }, 1000);
  372.  
  373. // addBtn();
  374. };
  375. // Your code here...
  376. })();