下载微博图片和视频(仅支持新版界面)

从新版微博界面下载图片和视频。

目前为 2023-10-12 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Download Weibo Images & Videos (Only support new version weibo UI)
  3. // @name:zh-CN 下载微博图片和视频(仅支持新版界面)
  4. // @version 1.1.2
  5. // @description Download images and videos from new version weibo UI webpage.
  6. // @description:zh-CN 从新版微博界面下载图片和视频。
  7. // @author OWENDSWANG
  8. // @match https://weibo.com/*
  9. // @match https://www.weibo.com/*
  10. // @match https://s.weibo.com/weibo*
  11. // @match https://s.weibo.com/realtime*
  12. // @match https://s.weibo.com/video*
  13. // @exclude https://weibo.com/tv/*
  14. // @exclude https://www.weibo.com/tv/*
  15. // @exclude https://weibo.com/p/*
  16. // @exclude https://www.weibo.com/p/*
  17. // @icon https://weibo.com/favicon.ico
  18. // @license MIT
  19. // @homepage https://gf.qytechs.cn/scripts/430877
  20. // @supportURL https://github.com/owendswang/Download-Weibo-Images-Videos
  21. // @grant GM_download
  22. // @grant GM_xmlhttpRequest
  23. // @grant GM_notification
  24. // @grant GM_getValue
  25. // @grant GM_setValue
  26. // @grant GM_registerMenuCommand
  27. // @connect weibo.com
  28. // @connect www.weibo.com
  29. // @connect wx1.sinaimg.cn
  30. // @connect wx2.sinaimg.cn
  31. // @connect wx3.sinaimg.cn
  32. // @connect wx4.sinaimg.cn
  33. // @connect g.us.sinaimg.cn
  34. // @connect f.video.weibocdn.com
  35. // @connect f.video.weibocdn.com
  36. // @connect localhost
  37. // @namespace http://tampermonkey.net/
  38. // @run-at document-end
  39. // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.9.1/jszip.min.js
  40. // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
  41. // ==/UserScript==
  42.  
  43. (function() {
  44. 'use strict';
  45.  
  46. let text = [];
  47. let text_zh = [
  48. /*0*/ '添加下载按钮',
  49. /*1*/ '欢迎使用“下载微博图片”脚本',
  50. /*2*/ '请选择添加下载按钮的方式:',
  51. /*3*/ '点击“添加下载按钮”来添加下载按钮。',
  52. /*4*/ '当鼠标位于浏览器页面时添加下载按钮,但这种方式会占用很多CPU资源。',
  53. /*5*/ '确定',
  54. /*6*/ '下载设置',
  55. /*7*/ '下载文件名称',
  56. /*8*/ '{original} - 原文件名\n{username} - 原博主名称\n{userid} - 原博主ID\n{mblogid} - 原博mblogid\n{uid} - 原博uid\n{ext} - 文件后缀\n{index} - 图片序号\n{YYYY} {MM} {DD} {HH} {mm} {ss} - 原博发布时\n间的年份、月份、日期、小时、分钟、秒,可\n分开独立使用\n{content} - 博文内容(最多前25个字符)',
  57. /*9*/ '下载队列',
  58. /*10*/ '重试',
  59. /*11*/ '关闭',
  60. /*12*/ '取消',
  61. /*13*/ '打包下载',
  62. /*14*/ '打包文件名',
  63. /*15*/ '与“下载文件名称”规则相同,但{original}、{ext}、{index}除外',
  64. /*16*/ '单独设置转发微博下载文件名称',
  65. /*17*/ '转发微博下载文件名称',
  66. /*18*/ '除“下载文件名”规则外,额外标签如下:\n{re.mblogid} - 转博mblogid\n{re.username} - 转发博主名称\n{re.userid} - 转发博主ID\n{re.uid} - 转博uid\n{re.content} - 转发博文内容(最多前25个字符)\n{re.YYYY} {re.MM} {re.DD} {re.HH} {re.mm} {re.ss}\n - 原博发布时间的年份、月份、日期、小时、\n分钟、秒,可分开独立使用',
  67. /*19*/ '转发微博打包文件名',
  68. /*20*/ '与“转发微博下载文件名称”规则相同,但{original}、{ext}、{index}除外',
  69. /*21*/ '使用Aria2c远程下载',
  70. /*22*/ 'RPC接口地址',
  71. /*23*/ '使用此方式下载,无法使用打包功能,无法在页面右下角显示下载进度和结果。',
  72. /*24*/ '如果接口地址不是localhost,需手动将地址添加到XHR白名单。',
  73. /*25*/ '设置',
  74. /*26*/ '<b>注意</b>:',
  75. /*27*/ '启用“打包下载”时,需区分多文件名称,\n避免重复而导致打包后只有一个文件,文件命\n名时,必须包含{original}、{index}中至少一个\n标签。',
  76. ];
  77. let text_en = [
  78. /*0*/ 'Add Download Buttons',
  79. /*1*/ 'Welcome Using \'Download Weibo Images\' Script',
  80. /*2*/ 'Which way do you like to add download buttons to each weibo post?',
  81. /*3*/ 'Click \'Add Download Buttons\' button to add download buttons.',
  82. /*4*/ 'When mouse over browser page, add download buttons automatically. But it takes a lot of CPU usage.',
  83. /*5*/ 'OK',
  84. /*6*/ 'Download Setting',
  85. /*7*/ 'Download File Name',
  86. /*8*/ '{original} - Original file name\n{username} - Original user name\n{userid} - Original user ID\n{mblogid} - Original mblogid\n{uid} - Original uid\n{ext} - File extention\n{index} - Image index\n{YYYY} {MM} {DD} {HH} {mm} {ss} - "Year", \n"Month", "Date", "Hour", "Minute", "Second" \nof the created time of the original post\n{content} - Original post content (limited to \nfirst 25 characters)',
  87. /*9*/ 'Download Queue',
  88. /*10*/ 'Retry',
  89. /*11*/ 'Close',
  90. /*12*/ 'Cancel',
  91. /*13*/ 'Pack download files as a ZIP file',
  92. /*14*/ 'ZIP File Name',
  93. /*15*/ 'The same rules as "Download File Name" except {original}, {ext} and {index}',
  94. /*16*/ 'Different File Name for Retweets',
  95. /*17*/ 'Retweet Download File Name',
  96. /*18*/ 'Except the rules for "Download File Name", there are additional tags as below.\n{re.mblogid} - Retweet mblogid\n{re.username} - Retweet user name\n{re.userid} - Retweet user ID\n{re.uid} - Retweet uid\n{re.content} - Retweet post content (limited to first 25 characters)\n{re.YYYY} {re.MM} {re.DD} {re.HH} {re.mm} {re.ss} - "Year", "Month", "Date", "Hour", "Minute", "Second" of the created time of the retweet post',
  97. /*19*/ 'Retweet Zip File Name',
  98. /*20*/ 'The same rules as "Retweet Download File Name" except {original}, {ext} and {index}',
  99. /*21*/ 'Use Aria2c remote download API',
  100. /*22*/ 'RPC Url',
  101. /*23*/ 'In this mode, You would not be able to download in ZIP mode and to observe download progress and result.',
  102. /*24*/ 'If it\'s not \'localhost\', you would have to add it to \'XHR white list\'.',
  103. /*25*/ 'Settings',
  104. /*26*/ '<b>Attention</b>: ',
  105. /*27*/ 'When \'ZIP mode\' enabled, you have \nto include one of the tags {original} or {index} \nto avoid duplicated ones being overwritten.',
  106. ];
  107. if(navigator.language.substr(0, 2) == 'zh') {
  108. text = text_zh;
  109. } else {
  110. text = text_en;
  111. }
  112.  
  113. let downloadQueueCard = document.createElement('div');
  114. downloadQueueCard.style.position = 'fixed';
  115. downloadQueueCard.style.bottom = '0.5rem';
  116. downloadQueueCard.style.left = '0.5rem';
  117. downloadQueueCard.style.maxHeight = '50vh';
  118. downloadQueueCard.style.overflowY = 'auto';
  119. downloadQueueCard.style.overflowX = 'hidden';
  120. let downloadQueueTitle = document.createElement('div');
  121. downloadQueueTitle.textContent = text[9];
  122. downloadQueueTitle.style.fontSize = '0.8rem';
  123. downloadQueueTitle.style.color = 'gray';
  124. downloadQueueTitle.style.display = 'none';
  125. downloadQueueCard.appendChild(downloadQueueTitle);
  126. document.body.appendChild(downloadQueueCard);
  127. let progressBar = document.createElement('div');
  128. progressBar.style.height = '1.4rem';
  129. progressBar.style.width = '23rem';
  130. // progressBar.style.background = 'linear-gradient(to right, red 100%, transparent 100%)';
  131. progressBar.style.borderStyle = 'solid';
  132. progressBar.style.borderWidth = '0.1rem';
  133. progressBar.style.borderColor = 'grey';
  134. progressBar.style.borderRadius = '0.5rem';
  135. progressBar.style.boxSizing = 'content-box';
  136. progressBar.style.marginTop = '0.5rem';
  137. progressBar.style.marginRight = '1rem';
  138. progressBar.style.position = 'relative';
  139. let progressText = document.createElement('div');
  140. // progressText.textContent = 'test.test';
  141. progressText.style.mixBlendMode = 'screen';
  142. progressText.style.width = '100%';
  143. progressText.style.textAlign = 'center';
  144. progressText.style.color = 'orange';
  145. progressText.style.fontSize = '0.7rem';
  146. progressText.style.lineHeight = '1.4rem';
  147. progressText.style.overflow = 'hidden';
  148. progressBar.appendChild(progressText);
  149. let progressCloseBtn = document.createElement('button');
  150. progressCloseBtn.style.border = 'unset';
  151. progressCloseBtn.style.background = 'unset';
  152. progressCloseBtn.style.color = 'orange';
  153. progressCloseBtn.style.position = 'absolute';
  154. progressCloseBtn.style.right = '0';
  155. progressCloseBtn.style.top = '0.1rem';
  156. progressCloseBtn.style.fontSize = '1rem';
  157. progressCloseBtn.style.lineHeight = '1rem';
  158. progressCloseBtn.style.cursor = 'pointer';
  159. progressCloseBtn.textContent = '×';
  160. progressCloseBtn.title = text[12];
  161. progressCloseBtn.onmouseover = function(e){
  162. this.style.color = 'red';
  163. }
  164. progressCloseBtn.onmouseout = function(e){
  165. this.style.color = 'orange';
  166. }
  167. progressBar.appendChild(progressCloseBtn);
  168. // downloadQueueCard.appendChild(progressBar);
  169.  
  170. function send2Aria2c(url, fileName, headerFlag) {
  171. // console.log(downloadUrl);
  172. return new Promise(function(resolve, reject) {
  173. let header = [ 'User-Agent: ' + window.navigator.userAgent ];
  174. if (headerFlag) {
  175. header.push('Referer: https://' + location.host);
  176. header.push('Origin: https://' + location.host);
  177. }
  178. downloadQueueTitle.style.display = 'block';
  179. let progress = downloadQueueCard.appendChild(progressBar.cloneNode(true));
  180. progress.firstChild.textContent = fileName;
  181. GM_xmlhttpRequest({
  182. method: 'POST',
  183. url: GM_getValue('ariaRpcUrl','http://localhost:6800/jsonrpc'),
  184. data: JSON.stringify({
  185. jsonrpc: '2.0',
  186. id: 'weibo',
  187. method: 'aria2.addUri',
  188. params: [ [ url ], { header, out: fileName } ],
  189. }),
  190. headers: {"Content-Type": "application/json"},
  191. onload: function(response) {
  192. // console.log(response.responseText);
  193. progress.style.background = 'green';
  194. const timeout = setTimeout(() => {
  195. progress.remove();
  196. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  197. }, 1000);
  198. progress.lastChild.onclick = function(e) {
  199. clearTimeout(timeout);
  200. this.parentNode.remove();
  201. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  202. }
  203. resolve(response);
  204. },
  205. onabort: function(e) { downloadError(e, url, fileName, headerFlag, progress); resolve(null); },
  206. onerror: function(e) { downloadError(e, url, fileName, headerFlag, progress); resolve(null); },
  207. ontimeout: function(e) { downloadError(e, url, fileName, headerFlag, progress); resolve(null); },
  208. });
  209. });
  210. }
  211.  
  212. function httpGet(theUrl) {
  213. /*let xmlHttp = new XMLHttpRequest();
  214. xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
  215. xmlHttp.send( null );
  216. return xmlHttp.responseText;*/
  217. return new Promise(function(resolve, reject) {
  218. GM_xmlhttpRequest({
  219. method: 'GET',
  220. url: theUrl,
  221. responseType: 'json',
  222. headers: {
  223. 'Referer': 'https://' + location.host,
  224. 'Origin': 'https://' + location.host
  225. },
  226. onload: ({ status, response }) => {
  227. // console.log(response);
  228. resolve(response)
  229. },
  230. onabort: function(e) { resolve(null); },
  231. onerror: function(e) { resolve(null); },
  232. ontimeout: function(e) { resolve(null); },
  233. });
  234. });
  235. }
  236.  
  237. function downloadError(e, url, name, headerFlag, progress, zipMode = false, ariaMode = false) {
  238. // console.log(e, url);
  239. /*GM_notification({
  240. title: 'Download error',
  241. text: 'Error: ' + e.error + '\nUrl: ' + url,
  242. silent: true,
  243. timeout: 3,
  244. });*/
  245. progress.style.background = 'red';
  246. progress.firstChild.textContent = name + ' [' + (e.error || 'Unknown') + ']';
  247. progress.firstChild.style.color = 'yellow';
  248. progress.firstChild.style.mixBlendMode = 'unset';
  249. if (!zipMode) {
  250. let progressRetryBtn = document.createElement('button');
  251. progressRetryBtn.style.border = 'unset';
  252. progressRetryBtn.style.background = 'unset';
  253. progressRetryBtn.style.color = 'yellow';
  254. progressRetryBtn.style.position = 'absolute';
  255. progressRetryBtn.style.right = '1.2rem';
  256. progressRetryBtn.style.top = '0.05rem';
  257. progressRetryBtn.style.fontSize = '1rem';
  258. progressRetryBtn.style.lineHeight = '1rem';
  259. progressRetryBtn.style.cursor = 'pointer';
  260. progressRetryBtn.style.letterSpacing = '-0.2rem';
  261. progressRetryBtn.textContent = '⤤⤦';
  262. progressRetryBtn.title = text[10];
  263. progressRetryBtn.onmouseover = function(e){
  264. this.style.color = 'white';
  265. }
  266. progressRetryBtn.onmouseout = function(e){
  267. this.style.color = 'yellow';
  268. }
  269. progressRetryBtn.onclick = function(e) {
  270. this.parentNode.remove();
  271. if (ariaMode) {
  272. send2Aria2c(url, name, headerFlag);
  273. } else {
  274. downloadWrapper(url, name, headerFlag);
  275. }
  276. }
  277. progress.insertBefore(progressRetryBtn, progress.lastChild);
  278. }
  279. progress.lastChild.title = text[11];
  280. progress.lastChild.style.color = 'yellow';
  281. progress.lastChild.onmouseover = function(e){
  282. this.style.color = 'white';
  283. };
  284. progress.lastChild.onmouseout = function(e){
  285. this.style.color = 'yellow';
  286. };
  287. progress.lastChild.onclick = function(e) {
  288. this.parentNode.remove();
  289. if(progress.parent.childElementCount == 1) progress.parent.firstChild.style.display = 'none';
  290. };
  291. // setTimeout(() => { progress.remove(); if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none'; }, 1000);
  292. }
  293.  
  294. function downloadWrapper(url, name, headerFlag = false, zipMode = false) {
  295. // console.log(url);
  296. downloadQueueTitle.style.display = 'block';
  297. let progress = downloadQueueCard.appendChild(progressBar.cloneNode(true));
  298. progress.firstChild.textContent = name + ' [0%]';
  299. if (zipMode) {
  300. return new Promise(function(resolve, reject) {
  301. const download = GM_xmlhttpRequest({
  302. method: 'GET',
  303. url,
  304. responseType: 'blob',
  305. headers: headerFlag ? {
  306. 'Referer': 'https://' + location.host,
  307. 'Origin': 'https://' + location.host
  308. } : null,
  309. onprogress: (e) => {
  310. // e = { int done, finalUrl, bool lengthComputable, int loaded, int position, int readyState, response, str responseHeaders, responseText, responseXML, int status, statusText, int total, int totalSize }
  311. const percent = e.done / e.total * 100;
  312. progress.style.background = 'linear-gradient(to right, green ' + percent + '%, transparent ' + percent + '%)';
  313. progress.firstChild.textContent = name + ' [' + percent.toFixed(0) + '%]';
  314. },
  315. onload: ({ status, response }) => {
  316. const timeout = setTimeout(() => {
  317. progress.remove();
  318. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  319. }, 1000);
  320. progress.lastChild.onclick = function(e) {
  321. clearTimeout(timeout);
  322. this.parentNode.remove();
  323. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  324. }
  325. resolve(response);
  326. },
  327. onabort: function(e) { downloadError(e, url, name, headerFlag, progress); resolve(null); },
  328. onerror: function(e) { downloadError(e, url, name, headerFlag, progress); resolve(null); },
  329. ontimeout: function(e) { downloadError(e, url, name, headerFlag, progress); resolve(null); },
  330. });
  331. progress.lastChild.onclick = function(e) {
  332. download.abort();
  333. this.parentNode.remove();
  334. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  335. };
  336. });
  337. } else {
  338. const download = GM_download({
  339. url,
  340. name,
  341. headers: headerFlag ? {
  342. 'Referer': 'https://' + location.host,
  343. 'Origin': 'https://' + location.host
  344. } : null,
  345. onprogress: (e) => {
  346. // e = { int done, finalUrl, bool lengthComputable, int loaded, int position, int readyState, response, str responseHeaders, responseText, responseXML, int status, statusText, int total, int totalSize }
  347. const percent = e.done / e.total * 100;
  348. progress.style.background = 'linear-gradient(to right, green ' + percent + '%, transparent ' + percent + '%)';
  349. progress.firstChild.textContent = name + ' [' + percent.toFixed(0) + '%]';
  350. },
  351. onload: ({ status, response }) => {
  352. const timeout = setTimeout(() => {
  353. progress.remove();
  354. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  355. }, 1000);
  356. progress.lastChild.onclick = function(e) {
  357. clearTimeout(timeout);
  358. this.parentNode.remove();
  359. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  360. }
  361. },
  362. onerror: (e) => { downloadError(e, url, name, headerFlag, progress); },
  363. ontimeout: (e) => { downloadError(e, url, name, headerFlag, progress); },
  364. });
  365. progress.lastChild.onclick = function(e) {
  366. download.abort();
  367. this.parentNode.remove();
  368. if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
  369. };
  370. }
  371. }
  372.  
  373. function getName(nameSetting, originalName, ext, userName, userId, postId, postUid, index, postTime, content, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetContent) {
  374. let setName = nameSetting;
  375. setName = setName.replace('{ext}', ext);
  376. setName = setName.replace('{original}', originalName);
  377. setName = setName.replace('{username}', userName);
  378. setName = setName.replace('{userid}', userId);
  379. setName = setName.replace('{mblogid}', postId);
  380. setName = setName.replace('{uid}', postUid);
  381. setName = setName.replace('{index}', index);
  382. setName = setName.replace('{content}', content.substring(0, 25));
  383. let YYYY, MM, DD, HH, mm, ss;
  384. const postAt = new Date(postTime);
  385. if (postTime) {
  386. YYYY = postAt.getFullYear().toString();
  387. MM = (postAt.getMonth() + 1).toString().padStart(2, '0');
  388. DD = postAt.getDate().toString().padStart(2, '0');
  389. HH = postAt.getHours().toString().padStart(2, '0');
  390. mm = postAt.getMinutes().toString().padStart(2, '0');
  391. ss = postAt.getSeconds().toString().padStart(2, '0');
  392. }
  393. setName = setName.replace('{YYYY}', YYYY);
  394. setName = setName.replace('{MM}', MM);
  395. setName = setName.replace('{DD}', DD);
  396. setName = setName.replace('{HH}', HH);
  397. setName = setName.replace('{mm}', mm);
  398. setName = setName.replace('{ss}', ss);
  399. if (retweetPostId && GM_getValue('retweetMode', false)) {
  400. setName = setName.replace('{re.mblogid}', retweetPostId);
  401. setName = setName.replace('{re.username}', retweetUserName);
  402. setName = setName.replace('{re.userid}', retweetUserId);
  403. setName = setName.replace('{re.uid}', retweetPostUid);
  404. setName = setName.replace('{re.content}', retweetContent.substring(0, 25));
  405. let reYYYY, reMM, reDD, reHH, remm, ress;
  406. const retweetPostAt = new Date(retweetPostTime);
  407. if (retweetPostTime) {
  408. reYYYY = retweetPostAt.getFullYear().toString();
  409. reMM = (retweetPostAt.getMonth() + 1).toString().padStart(2, '0');
  410. reDD = retweetPostAt.getDate().toString().padStart(2, '0');
  411. reHH = retweetPostAt.getHours().toString().padStart(2, '0');
  412. remm = retweetPostAt.getMinutes().toString().padStart(2, '0');
  413. ress = retweetPostAt.getSeconds().toString().padStart(2, '0');
  414. }
  415. setName = setName.replace('{re.YYYY}', reYYYY);
  416. setName = setName.replace('{re.MM}', reMM);
  417. setName = setName.replace('{re.DD}', reDD);
  418. setName = setName.replace('{re.HH}', reHH);
  419. setName = setName.replace('{re.mm}', remm);
  420. setName = setName.replace('{re.ss}', ress);
  421. }
  422. return setName.replace(/[<|>|*|"|\/|\|:|?|\n]/g, '_');
  423. }
  424.  
  425. function handleDownloadList(downloadList, packName) {
  426. if (GM_getValue('ariaMode', false)) {
  427. for (const item of downloadList) {
  428. send2Aria2c(item.url, item.name, item.headerFlag);
  429. }
  430. } else if (GM_getValue('zipMode', false)) {
  431. let zip = new JSZip();
  432. // console.log('zip', zip);
  433. let promises = downloadList.map(async function(ele, idx) {
  434. return await downloadWrapper(ele.url, ele.name, ele.headerFlag, true).then(function(data) {
  435. // console.log(ele, idx, 'data', data);
  436. if (data) zip.file(downloadList[idx].name, data);
  437. });
  438. });
  439. // console.log('promises', promises);
  440. Promise.all(promises).then(async function(responseList) {
  441. // console.log('responseList', responseList);
  442. // console.log('zip', zip);
  443. // console.log('generateAsync', zip.generateAsync());
  444. const content = await zip.generateAsync({ type: 'blob', streamFiles: true }/*, function({ percent, currentFile }) { console.log(percent); }*/);
  445. // console.log('content', content);
  446. if (zip.files && Object.keys(zip.files).length > 0) saveAs(content, packName);
  447. });
  448. } else {
  449. for (const item of downloadList) {
  450. downloadWrapper(item.url, item.name, item.headerFlag);
  451. }
  452. }
  453. }
  454.  
  455. function handleVideo(mediaInfo, padLength, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText) {
  456. const newList = [];
  457. let largeVidUrl = mediaInfo.playback_list ? mediaInfo.playback_list[0].play_info.url : mediaInfo.stream_url;
  458. let vidName = largeVidUrl.split('?')[0];
  459. vidName = vidName.split('/')[vidName.split('/').length - 1].split('?')[0];
  460. let originalName = vidName.split('.')[0];
  461. let ext = vidName.split('.')[1];
  462. const setName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetFileName', '{original}.{ext}') : GM_getValue('dlFileName', '{original}.{ext}'), originalName, ext, userName, userId, postId, postUid, index.toString().padStart(padLength, '0'), postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  463. newList.push({ url: largeVidUrl, name: setName, headerFlag: true });
  464. if(mediaInfo.hasOwnProperty('pic_info')) {
  465. let picUrl = mediaInfo.pic_info.pic_big.url;
  466. let largePicUrl = picUrl.replace('/orj480/', '/large/');
  467. let picName = largePicUrl.split('/')[largePicUrl.split('/').length - 1].split('?')[0];
  468. let originalName = picName.split('.')[0];
  469. let ext = picName.split('.')[1];
  470. const setName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetFileName', '{original}.{ext}') : GM_getValue('dlFileName', '{original}.{ext}'), originalName, ext, userName, userId, postId, postUid, index.toString().padStart(padLength, '0'), postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  471. newList.push({url: largePicUrl, name: setName, headerFlag: true });
  472. }
  473. return newList;
  474. }
  475.  
  476. function handlePic(pic, padLength, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText) {
  477. let newList = [];
  478. let largePicUrl = pic.largest.url;
  479. let picName = largePicUrl.split('/')[largePicUrl.split('/').length - 1].split('?')[0];
  480. let originalName = picName.split('.')[0];
  481. let ext = picName.split('.')[1];
  482. const setName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetFileName', '{original}.{ext}') : GM_getValue('dlFileName', '{original}.{ext}'), originalName, ext, userName, userId, postId, postUid, index.toString().padStart(padLength, '0'), postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  483. newList.push({ url: largePicUrl, name: setName, headerFlag: true });
  484. if(pic.hasOwnProperty('video')) {
  485. let videoUrl = pic.video;
  486. let videoName = videoUrl.split('%2F')[videoUrl.split('%2F').length - 1].split('?')[0];
  487. videoName = videoName.split('/')[videoName.split('/').length - 1].split('?')[0];
  488. if (!videoName.includes('.')) videoName = videoUrl.split('/')[videoUrl.split('/').length - 1].split('?')[0];
  489. // console.log(videoUrl, videoName);
  490. let originalName = videoName.split('.')[0];
  491. let ext = videoName.split('.')[1];
  492. const setName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetFileName', '{original}.{ext}') : GM_getValue('dlFileName', '{original}.{ext}'), originalName, ext, userName, userId, postId, postUid, index.toString().padStart(padLength, '0'), postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  493. newList.push({ url: videoUrl, name: setName, headerFlag: true });
  494. }
  495. return newList;
  496. }
  497.  
  498. function addDlBtn(footer) {
  499. // console.log('add download button');
  500. let dlBtnDiv = document.createElement('div');
  501. dlBtnDiv.className = 'woo-box-item-flex toolbar_item_1ky_D toolbar_cursor_34j5V';
  502. let divInDiv = document.createElement('div');
  503. divInDiv.className = 'woo-box-flex woo-box-alignCenter woo-box-justifyCenter toolbar_like_20yPI toolbar_likebox_1rLfZ toolbar_wrap_np6Ug';
  504. let dlBtn = document.createElement('button');
  505. dlBtn.className = 'woo-like-main toolbar_btn_Cg9tz download-button';
  506. dlBtn.setAttribute('tabindex', '0');
  507. dlBtn.setAttribute('title', '下载');
  508. // dlBtn.innerHTML = '<span class="woo-like-iconWrap"><svg class="woo-like-icon"><use xlink:href="#woo_svg_download"></use></svg></span><span class="woo-like-count">下载</span>';
  509. dlBtn.innerHTML = '<span class="woo-like-iconWrap"><i class="woo-font woo-font--imgSave woo-like-icon"></i></span><span class="woo-like-count">下载</span>';
  510. dlBtn.addEventListener('click', async function(event) {
  511. event.preventDefault();
  512. const article = this.closest('article.woo-panel-main');
  513. if(article) {
  514. // let contentRow = article.getElementsByClassName('content_row_-r5Tk')[0];
  515. const header = article.getElementsByTagName('header')[0];
  516. const postLink = header.getElementsByClassName('head-info_time_6sFQg')[0];
  517. let postId = postLink.href.split('/')[postLink.href.split('/').length - 1];
  518. const resJson = await httpGet('https://' + location.host + '/ajax/statuses/show?id=' + postId);
  519. // console.log(resJson);
  520. let status = resJson;
  521. let retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText;
  522. if(resJson.hasOwnProperty('retweeted_status')) {
  523. status = resJson.retweeted_status;
  524. retweetPostId = resJson.mblogid;
  525. retweetUserName = resJson.user.screen_name;
  526. retweetUserId = resJson.user.idstr;
  527. retweetPostUid = resJson.idstr;
  528. retweetPostTime = resJson.created_at;
  529. retweetText = resJson.text_raw;
  530. }
  531. postId = status.mblogid;
  532. const picInfos = status.pic_infos;
  533. const mixMediaInfo = status.mix_media_info;
  534. const userName = status.user.screen_name;
  535. const userId = status.user.idstr;
  536. const postUid = status.idstr;
  537. const postTime = status.created_at;
  538. const text = status.text_raw;
  539. let downloadList = [];
  540. if(footer.parentElement.getElementsByTagName('video').length > 0) {
  541. // console.log('download video');
  542. if(resJson.page_info?.media_info) {
  543. downloadList = downloadList.concat(handleVideo(resJson.page_info.media_info, 1, userName, userId, postId, postUid, 1, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  544. }
  545. }
  546. if (picInfos) {
  547. // console.log('download images');
  548. let index = 0;
  549. let padLength = Object.entries(picInfos).length.toString().length;
  550. for (const [id, pic] of Object.entries(picInfos)) {
  551. index += 1;
  552. downloadList = downloadList.concat(handlePic(pic, padLength, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  553. }
  554. }
  555. if (mixMediaInfo && mixMediaInfo.items) {
  556. // console.log('mix media');
  557. let index = 0;
  558. let padLength = Object.entries(mixMediaInfo.items).length.toString().length;
  559. for (const [id, media] of Object.entries(mixMediaInfo.items)) {
  560. index += 1;
  561. if(media.type === 'video') {
  562. downloadList = downloadList.concat(handleVideo(media.data.media_info, 1, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  563. } else if (media.type === 'pic') {
  564. downloadList = downloadList.concat(handlePic(media.data, padLength, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  565. }
  566. }
  567. }
  568. const packName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetPackFileName', '{mblogid}.zip') : GM_getValue('packFileName', '{mblogid}.zip'), '{original}', '{ext}', userName, userId, postId, postUid, '{index}', postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  569. handleDownloadList(downloadList, packName);
  570. }
  571. });
  572. divInDiv.appendChild(dlBtn);
  573. dlBtnDiv.appendChild(divInDiv);
  574. footer.firstChild.firstChild.firstChild.appendChild(dlBtnDiv);
  575. // console.log('added download button');
  576. }
  577.  
  578. function addSingleDlBtn(img, idx = 0) {
  579. // console.log(img);
  580. const imgCtn = img.parentElement;
  581. const dlBtn = document.createElement('div');
  582. dlBtn.style.position = 'absolute';
  583. dlBtn.style.bottom = '0';
  584. dlBtn.style.left = '0';
  585. dlBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.4)';
  586. dlBtn.style.padding = '0.3rem';
  587. dlBtn.style.borderRadius = '0 8px';
  588. dlBtn.style.width = '1rem';
  589. dlBtn.style.height = '1rem';
  590. dlBtn.style.cursor = 'pointer';
  591. dlBtn.style.zIndex = '11';
  592. dlBtn.innerHTML = '<i class="woo-font woo-font--imgSave"></i>';
  593. dlBtn.addEventListener('mouseenter', (event) => { dlBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.8)'; });
  594. dlBtn.addEventListener('mouseleave', (event) => { dlBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.4)'; });
  595. dlBtn.addEventListener('click', async function(event) {
  596. event.stopPropagation();
  597. const article = this.closest('article.woo-panel-main');
  598. if(article) {
  599. // let contentRow = article.getElementsByClassName('content_row_-r5Tk')[0];
  600. const header = article.getElementsByTagName('header')[0];
  601. const postLink = header.getElementsByClassName('head-info_time_6sFQg')[0];
  602. let postId = postLink.href.split('/')[postLink.href.split('/').length - 1];
  603. const resJson = await httpGet('https://' + location.host + '/ajax/statuses/show?id=' + postId);
  604. // console.log(resJson);
  605. let status = resJson;
  606. let retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText;
  607. if(resJson.hasOwnProperty('retweeted_status')) {
  608. status = resJson.retweeted_status;
  609. retweetPostId = resJson.mblogid;
  610. retweetUserName = resJson.user.screen_name;
  611. retweetUserId = resJson.user.idstr;
  612. retweetPostUid = resJson.idstr;
  613. retweetPostTime = resJson.created_at;
  614. retweetText = resJson.text_raw;
  615. }
  616. postId = status.mblogid;
  617. const picInfos = status.pic_infos;
  618. const mixMediaInfo = status.mix_media_info;
  619. const userName = status.user.screen_name;
  620. const userId = status.user.idstr;
  621. const postUid = status.idstr;
  622. const postTime = status.created_at;
  623. const text = status.text_raw;
  624. let downloadList = [];
  625. if (picInfos) {
  626. // console.log('download images');
  627. let padLength = Object.entries(picInfos).length.toString().length;
  628. // console.log(idx, picInfos);
  629. const pic = Object.entries(picInfos)[idx][1];
  630. downloadList = downloadList.concat(handlePic(pic, padLength, userName, userId, postId, postUid, idx + 1, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  631. }
  632. if (mixMediaInfo && mixMediaInfo.items) {
  633. // console.log('mix media');
  634. // console.log(mixMediaInfo.items);
  635. let padLength = Object.entries(mixMediaInfo.items).length.toString().length;
  636. const media = Object.entries(mixMediaInfo.items)[idx][1];
  637. if(media.type === 'video') {
  638. downloadList = downloadList.concat(handleVideo(media.data.media_info, 1, userName, userId, postId, postUid, idx + 1, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  639. } else if (media.type === 'pic') {
  640. downloadList = downloadList.concat(handlePic(media.data, padLength, userName, userId, postId, postUid, idx + 1, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  641. }
  642. }
  643. const packName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetPackFileName', '{mblogid}.zip') : GM_getValue('packFileName', '{mblogid}.zip'), '{original}', '{ext}', userName, userId, postId, postUid, '{index}', postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  644. handleDownloadList(downloadList, packName);
  645. }
  646. });
  647. imgCtn.appendChild(dlBtn);
  648. }
  649.  
  650. function sAddDlBtn(footer) {
  651. // console.log('add download button on search');
  652. const lis = footer.getElementsByTagName('li');
  653. for (const li of lis) {
  654. li.style.width = '25%';
  655. }
  656. let dlBtnLi = document.createElement('li');
  657. dlBtnLi.style.width = '25%';
  658. let aInLi = document.createElement('a');
  659. aInLi.className = 'woo-box-flex woo-box-alignCenter woo-box-justifyCenter';
  660. aInLi.setAttribute('title', '下载');
  661. aInLi.setAttribute('href', 'javascript:void(0);');
  662. let dlBtn = document.createElement('button');
  663. dlBtn.className = 'woo-like-main toolbar_btn download-button';
  664. dlBtn.innerHTML = '<span class="woo-like-iconWrap"><svg class="woo-like-icon"><use xlink:href="#woo_svg_download"></use></svg></span><span class="woo-like-count">下载</span>';
  665. aInLi.addEventListener('click', function(event) { event.preventDefault(); });
  666. dlBtn.addEventListener('click', async function(event) {
  667. // console.log('download');
  668. event.preventDefault();
  669. const card = this.parentElement.parentElement.parentElement.parentElement;
  670. const cardWrap = card.parentElement;
  671. // console.log(card, cardWrap);
  672. const mid = cardWrap.getAttribute('mid');
  673. // console.log(mid);
  674. if(mid) {
  675. // console.log('https://' + location.host + '/ajax/statuses/show?id=' + mid);
  676. const resJson = await httpGet('https://weibo.com/ajax/statuses/show?id=' + mid);
  677. // console.log(resJson);
  678. let status = resJson;
  679. let retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText;
  680. if(resJson.hasOwnProperty('retweeted_status')) {
  681. status = resJson.retweeted_status;
  682. retweetPostId = resJson.mblogid;
  683. retweetUserName = resJson.user.screen_name;
  684. retweetUserId = resJson.user.idstr;
  685. retweetPostUid = resJson.idstr;
  686. retweetPostTime = resJson.created_at;
  687. retweetText = resJson.text_raw;
  688. }
  689. const postId = status.mblogid;
  690. const picInfos = status.pic_infos;
  691. const mixMediaInfo = status.mix_media_info;
  692. const userName = status.user.screen_name;
  693. const userId = status.user.idstr;
  694. const postUid = status.idstr;
  695. const postTime = status.created_at;
  696. const text = status.text_raw;
  697. let downloadList = [];
  698. if(footer.parentElement.getElementsByTagName('video').length > 0) {
  699. // console.log('download video');
  700. if(resJson.hasOwnProperty('page_info')) {
  701. downloadList = downloadList.concat(handleVideo(resJson.page_info.media_info, 1, userName, userId, postId, postUid, 1, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  702. }
  703. }
  704. if (picInfos) {
  705. // console.log('download images');
  706. let index = 0;
  707. let padLength = Object.entries(picInfos).length.toString().length;
  708. for (const [id, pic] of Object.entries(picInfos)) {
  709. index += 1;
  710. downloadList = downloadList.concat(handlePic(pic, padLength, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  711. }
  712. }
  713. if (mixMediaInfo && mixMediaInfo.items) {
  714. // console.log('mix media');
  715. let index = 0;
  716. let padLength = Object.entries(mixMediaInfo.items).length.toString().length;
  717. for (const [id, media] of Object.entries(mixMediaInfo.items)) {
  718. index += 1;
  719. if(media.type === 'video') {
  720. downloadList = downloadList.concat(handleVideo(media.data.media_info, 1, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  721. } else if (media.type === 'pic') {
  722. downloadList = downloadList.concat(handlePic(media.data, padLength, userName, userId, postId, postUid, index, postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText));
  723. }
  724. }
  725. }
  726. const packName = getName((GM_getValue('retweetMode', false) && retweetPostId) ? GM_getValue('retweetPackFileName', '{mblogid}.zip') : GM_getValue('packFileName', '{mblogid}.zip'), '{original}', '{ext}', userName, userId, postId, postUid, '{index}', postTime, text, retweetPostId, retweetUserName, retweetUserId, retweetPostUid, retweetPostTime, retweetText);
  727. handleDownloadList(downloadList, packName);
  728. }
  729. });
  730. aInLi.appendChild(dlBtn);
  731. dlBtnLi.appendChild(dlBtn);
  732. footer.firstChild.appendChild(dlBtnLi);
  733. // console.log('added download button');
  734. }
  735. /*
  736. function bodyMouseOver(event) {
  737. if (location.host == 'weibo.com' || location.host == 'www.weibo.com') {
  738. // let arts = document.getElementsByTagName('article');
  739. const footers = document.getElementsByTagName('footer');
  740. for (const footer of footers) {
  741. if(footer.getElementsByClassName('download-button').length > 0) {
  742. // console.log('already added download button');
  743. } else {
  744. // console.log(footer.parentElement);
  745. if(footer.parentElement.tagName.toLowerCase() == 'article') {
  746. const article = footer.parentElement;
  747. const imgs = article.getElementsByTagName('img');
  748. let added = false;
  749. // console.log(imgs);
  750. if(imgs.length > 0) {
  751. let addFlag = false;
  752. for (const img of imgs) {
  753. if(['woo-picture-img', 'picture_focusImg_1z5In', 'picture-viewer_pic_37YQ3'].includes(img.className)) {
  754. addFlag = true;
  755. }
  756. }
  757. if(addFlag == true) {
  758. addDlBtn(footer);
  759. added = true;
  760. }
  761. }
  762. let videos = article.getElementsByTagName('video');
  763. if(videos.length > 0 && added == false) {
  764. addDlBtn(footer);
  765. }
  766. }
  767. }
  768. }
  769. }
  770. if (location.host == 's.weibo.com') {
  771. // let cards = document.querySelectorAll('#pl_feedlist_index .card-wrap');
  772. const footers = document.querySelectorAll('#pl_feedlist_index .card-act');
  773. for (const footer of footers) {
  774. if(footer.getElementsByClassName('download-button').length > 0) {
  775. // console.log('already added download button');
  776. } else {
  777. // console.log(footer.parentElement);
  778. if(footer.parentElement.className == 'card' && footer.parentElement.parentElement.className == 'card-wrap') {
  779. const card = footer.parentElement;
  780. let added = false;
  781. const media_prev = card.querySelector('div[node-type="feed_list_media_prev"]');
  782. // console.log(media_prev);
  783. if (media_prev) {
  784. const imgs = media_prev.getElementsByTagName('img');
  785. // console.log(imgs);
  786. if(imgs.length > 0) {
  787. sAddDlBtn(footer);
  788. added = true;
  789. }
  790. const videos = card.getElementsByTagName('video');
  791. if(videos.length > 0 && added == false) {
  792. sAddDlBtn(footer);
  793. }
  794. }
  795. }
  796. }
  797. }
  798. }
  799. }
  800. */
  801. function handleCard(card) {
  802. // console.log(card);
  803. const footer = card.querySelectorAll('footer')[1] || card.querySelector('footer');
  804. const imgs = card.querySelectorAll('img.woo-picture-img,img.picture_focusImg_1z5In,img.picture-viewer_pic_37YQ3,video.picture-viewer_pic_37YQ3');
  805. // console.log(imgs);
  806. if (footer) {
  807. if (footer.getElementsByClassName('download-button').length > 0) {
  808. // console.log('already added download button');
  809. } else {
  810. // console.log(footer.parentElement);
  811. let added = false;
  812. if (imgs.length > 0) {
  813. addDlBtn(footer);
  814. added = true;
  815. if (imgs.length > 1) {
  816. for (const [ idx, img ] of Object.entries(imgs)) {
  817. if (img.parentElement.getElementsByClassName('download-single-button').length === 0) {
  818. if (img.className.includes('picture-viewer_pic_37YQ3')) {
  819. const previews = card.querySelectorAll('div.picture-viewer_preview_2wOSq');
  820. for (const [ index, preview ] of Object.entries(previews)) {
  821. if (preview.className.includes('picture-viewer_cur_anUEY')) {
  822. addSingleDlBtn(img, parseInt(index));
  823. }
  824. }
  825. } else {
  826. addSingleDlBtn(img, parseInt(idx));
  827. }
  828. }
  829. }
  830. }
  831. }
  832. let videos = card.getElementsByTagName('video');
  833. if(videos.length > 0 && added == false) {
  834. addDlBtn(footer);
  835. }
  836. }
  837. }
  838. }
  839. /*
  840. let startButton = document.createElement('button');
  841. startButton.textContent = text[0];
  842. startButton.id = 'startButton';
  843. startButton.style.position = 'fixed';
  844. startButton.style.top = '14rem';
  845. startButton.style.left = '1rem';
  846. startButton.style.zIndex = 400;
  847. startButton.style.backgroundColor = 'black';
  848. startButton.style.color = 'lightgray';
  849. startButton.style.paddingLeft = '1rem';
  850. startButton.style.paddingRight = '1rem';
  851. startButton.style.paddingTop = '0.5rem';
  852. startButton.style.paddingBottom = '0.5rem';
  853. startButton.style.fontWeight = 'bold';
  854. startButton.style.borderWidth = '0.15rem';
  855. startButton.style.borderColor = 'lightgray';
  856. startButton.style.borderRadius = '0.4rem';
  857. startButton.style.borderStyle = 'solid';
  858. startButton.addEventListener('mouseover', function(event) {
  859. startButton.style.backgroundColor = 'lightgray';
  860. startButton.style.color = 'black';
  861. startButton.style.borderColor = 'black';
  862. });
  863. startButton.addEventListener('mouseout', function(event) {
  864. startButton.style.backgroundColor = 'black';
  865. startButton.style.color = 'lightgray';
  866. startButton.style.borderColor = 'lightgray';
  867. });
  868. startButton.addEventListener('mousedown', function(event) {
  869. startButton.style.backgroundColor = 'gray';
  870. });
  871. startButton.addEventListener('mouseup', function(event) {
  872. startButton.style.backgroundColor = 'lightgray';
  873. });
  874. startButton.addEventListener('click', bodyMouseOver);
  875.  
  876. function addStartButton() {
  877. document.body.appendChild(startButton);
  878. document.body.removeEventListener('mouseover', bodyMouseOver)
  879. }
  880.  
  881. function addEventListener() {
  882. document.body.addEventListener('mouseover', bodyMouseOver);
  883. if(document.getElementById('startButton')) {
  884. document.body.removeChild(startButton);
  885. }
  886. }
  887. */
  888. // let addDlBtnMode = GM_getValue('addDlBtnMode', 0);
  889.  
  890. function showModal(event) {
  891. // console.log(addDlBtnMode);
  892. let bg = document.createElement('div');
  893. bg.style.position = 'fixed';
  894. bg.style.top = 0;
  895. bg.style.left = 0;
  896. bg.style.zIndex = 500;
  897. bg.style.backgroundColor = 'black';
  898. bg.style.opacity = 0.5;
  899. let modal = document.createElement('div');
  900. document.body.appendChild(bg);
  901. modal.style.position = 'fixed';
  902. modal.style.width = '25rem';
  903. modal.style.height = 'auto';
  904. modal.style.maxHeight = '80vh';
  905. modal.style.zIndex = 600;
  906. modal.style.backgroundColor = 'white';
  907. modal.style.borderStyle = 'solid';
  908. modal.style.borderWidth = '0.2rem';
  909. modal.style.borderRadius = '0.5rem';
  910. modal.style.borderColor = 'black';
  911. modal.style.overflowX = 'hidden';
  912. modal.style.overflowY = 'auto';
  913. modal.style.fontSize = '1rem';
  914. let titleBar = document.createElement('div');
  915. titleBar.textContent = text[1];
  916. titleBar.style.width = '100%';
  917. titleBar.style.textAlign = 'center';
  918. titleBar.style.backgroundColor = 'black';
  919. titleBar.style.color = 'white';
  920. titleBar.style.fontSize = '1rem';
  921. titleBar.style.fontWeight = 'bold';
  922. titleBar.style.paddingTop = '0.5rem';
  923. titleBar.style.paddingBottom = '0.5rem';
  924. titleBar.style.borderTopLeftRadius = '0.3rem';
  925. titleBar.style.borderTopRightRadius = '0.3rem';
  926. modal.appendChild(titleBar);
  927. /*let question1 = document.createElement('p');
  928. question1.textContent = text[2];
  929. question1.style.paddingLeft = '2rem';
  930. question1.style.paddingRight = '2rem';
  931. question1.style.marginTop = '1rem';
  932. question1.style.marginBottom = '1rem';
  933. let chooseButton = document.createElement('input');
  934. chooseButton.type = 'radio';
  935. chooseButton.id = 'chooseButton';
  936. chooseButton.name = 'chooseSetting';
  937. chooseButton.value = 1;
  938. chooseButton.style.margin = '0.5rem 0.5rem 0 0.5rem';
  939. let labelForChooseButton = document.createElement('label');
  940. labelForChooseButton.htmlFor = 'chooseButton';
  941. labelForChooseButton.textContent = text[3];
  942. let divForChooseButton = document.createElement('div');
  943. divForChooseButton.appendChild(chooseButton);
  944. divForChooseButton.appendChild(labelForChooseButton);
  945. question1.appendChild(divForChooseButton);
  946. let chooseEvent = document.createElement('input');
  947. chooseEvent.type = 'radio';
  948. chooseEvent.id = 'chooseEvent';
  949. chooseEvent.name = 'chooseSetting';
  950. chooseEvent.value = 2;
  951. chooseEvent.style.margin = '0.5rem 0.5rem 0 0.5rem';
  952. if (addDlBtnMode == 2) {
  953. chooseEvent.checked = true;
  954. } else {
  955. chooseButton.checked = true;
  956. }
  957. let labelForChooseEvent = document.createElement('label');
  958. labelForChooseEvent.htmlFor = 'chooseEvent';
  959. labelForChooseEvent.textContent = text[4];
  960. let divForChooseEvent = document.createElement('div');
  961. divForChooseEvent.appendChild(chooseEvent);
  962. divForChooseEvent.appendChild(labelForChooseEvent);
  963. question1.appendChild(divForChooseEvent);
  964. modal.appendChild(question1);*/
  965. let question2 = document.createElement('p');
  966. question2.style.paddingLeft = '2rem';
  967. question2.style.paddingRight = '2rem';
  968. question2.style.marginTop = '1rem';
  969. question2.style.marginBottom = '1rem';
  970. let labelFileName = document.createElement('label');
  971. labelFileName.textContent = text[7];
  972. labelFileName.setAttribute('for', 'dlFileName');
  973. question2.appendChild(labelFileName);
  974. let inputFileName = document.createElement('input');
  975. inputFileName.type = 'text';
  976. inputFileName.id = 'dlFileName';
  977. inputFileName.name = 'dlFileName';
  978. inputFileName.style.marginTop = '0.5rem';
  979. inputFileName.style.width = 'calc(100% - 1rem)';
  980. inputFileName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
  981. inputFileName.style.borderStyle = 'solid';
  982. inputFileName.style.borderColor = 'gray';
  983. inputFileName.style.borderWidth = '0.14rem';
  984. inputFileName.style.borderRadius = '0.2rem';
  985. inputFileName.defaultValue = GM_getValue('dlFileName', '{original}.{ext}');
  986. question2.appendChild(inputFileName);
  987. let fileNameExplain1 = document.createElement('p');
  988. fileNameExplain1.innerHTML = text[8];
  989. fileNameExplain1.style.marginTop = '0.5rem';
  990. fileNameExplain1.style.marginBottom = '0';
  991. fileNameExplain1.style.whiteSpace = 'pre';
  992. fileNameExplain1.style.color = 'gray';
  993. question2.appendChild(fileNameExplain1);
  994. let fileNameExplain2 = document.createElement('p');
  995. fileNameExplain2.innerHTML = text[26] + text[27];
  996. fileNameExplain2.style.marginTop = '0.5rem';
  997. fileNameExplain2.style.whiteSpace = 'pre';
  998. fileNameExplain2.style.color = 'gray';
  999. question2.appendChild(fileNameExplain2);
  1000. modal.appendChild(question2);
  1001. let question3 = document.createElement('p');
  1002. question3.style.paddingLeft = '2rem';
  1003. question3.style.paddingRight = '2rem';
  1004. question3.style.marginTop = '1rem';
  1005. question3.style.marginBottom = '0';
  1006. let labelZipMode = document.createElement('label');
  1007. labelZipMode.setAttribute('for', 'zipMode');
  1008. labelZipMode.textContent = text[13];
  1009. labelZipMode.style.display = 'inline-block';
  1010. labelZipMode.style.paddingRight = '0.2rem';
  1011. labelZipMode.style.color = GM_getValue('ariaMode', false) ? 'gray' : null;
  1012. question3.appendChild(labelZipMode);
  1013. let inputZipMode = document.createElement('input');
  1014. inputZipMode.type = 'checkbox';
  1015. inputZipMode.id = 'zipMode';
  1016. inputZipMode.checked = GM_getValue('zipMode', false);
  1017. inputZipMode.disabled = GM_getValue('ariaMode', false);
  1018. question3.appendChild(inputZipMode);
  1019. let labelPackName = document.createElement('label');
  1020. labelPackName.textContent = text[14];
  1021. labelPackName.setAttribute('for', 'packFileName');
  1022. labelPackName.style.display = 'block';
  1023. labelPackName.style.marginTop = '0.5rem';
  1024. labelPackName.style.color = (GM_getValue('zipMode', false) && !GM_getValue('ariaMode', false)) ? null : 'gray';
  1025. // labelPackName.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
  1026. question3.appendChild(labelPackName);
  1027. let inputPackName = document.createElement('input');
  1028. inputPackName.type = 'text';
  1029. inputPackName.id = 'packFileName';
  1030. inputPackName.name = 'packFileName';
  1031. inputPackName.style.marginTop = '0.5rem';
  1032. inputPackName.style.width = 'calc(100% - 1rem)';
  1033. inputPackName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
  1034. inputPackName.style.borderStyle = 'solid';
  1035. inputPackName.style.borderColor = (GM_getValue('zipMode', false) && !GM_getValue('ariaMode', false)) ? 'gray' : 'lightgray';
  1036. inputPackName.style.borderWidth = '0.14rem';
  1037. inputPackName.style.borderRadius = '0.2rem';
  1038. inputPackName.defaultValue = GM_getValue('packFileName', '{mblogid}.zip');
  1039. // inputPackName.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
  1040. inputPackName.disabled = (GM_getValue('zipMode', false) && !GM_getValue('ariaMode', false)) ? false : true;
  1041. question3.appendChild(inputPackName);
  1042. let filePackExplain = document.createElement('p');
  1043. filePackExplain.textContent = text[15];
  1044. filePackExplain.style.marginTop = '0.5rem';
  1045. filePackExplain.style.marginBottom = '0';
  1046. filePackExplain.style.color = 'gray';
  1047. // filePackExplain.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
  1048. question3.appendChild(filePackExplain);
  1049. modal.appendChild(question3);
  1050. let question4 = document.createElement('p');
  1051. question4.style.paddingLeft = '2rem';
  1052. question4.style.paddingRight = '2rem';
  1053. question4.style.marginTop = '1rem';
  1054. question4.style.marginBottom = '0';
  1055. let labelRetweetMode = document.createElement('label');
  1056. labelRetweetMode.setAttribute('for', 'retweetMode');
  1057. labelRetweetMode.textContent = text[16];
  1058. labelRetweetMode.style.display = 'inline-block';
  1059. labelRetweetMode.style.paddingRight = '0.2rem';
  1060. question4.appendChild(labelRetweetMode);
  1061. let inputRetweetMode = document.createElement('input');
  1062. inputRetweetMode.type = 'checkbox';
  1063. inputRetweetMode.id = 'retweetMode';
  1064. inputRetweetMode.checked = GM_getValue('retweetMode', false);
  1065. question4.appendChild(inputRetweetMode);
  1066. let labelRetweetFileName = document.createElement('label');
  1067. labelRetweetFileName.textContent = text[17];
  1068. labelRetweetFileName.setAttribute('for', 'retweetFileName');
  1069. labelRetweetFileName.style.display = 'block';
  1070. labelRetweetFileName.style.marginTop = '0.5rem';
  1071. labelRetweetFileName.style.color = GM_getValue('retweetMode', false) ? null : 'gray';
  1072. // labelPackName.style.display = GM_getValue('retweetMode', false) ? 'block' : 'none';
  1073. question4.appendChild(labelRetweetFileName);
  1074. let inputRetweetFileName = document.createElement('input');
  1075. inputRetweetFileName.type = 'text';
  1076. inputRetweetFileName.id = 'retweetFileName';
  1077. inputRetweetFileName.name = 'retweetFileName';
  1078. inputRetweetFileName.style.marginTop = '0.5rem';
  1079. inputRetweetFileName.style.width = 'calc(100% - 1rem)';
  1080. inputRetweetFileName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
  1081. inputRetweetFileName.style.borderStyle = 'solid';
  1082. inputRetweetFileName.style.borderColor = 'lightgray';
  1083. inputRetweetFileName.style.borderWidth = '0.14rem';
  1084. inputRetweetFileName.style.borderRadius = '0.2rem';
  1085. inputRetweetFileName.defaultValue = GM_getValue('retweetFileName', '{original}.{ext}');
  1086. // inputRetweetFileName.style.display = GM_getValue('retweetMode', false) ? 'block' : 'none';
  1087. inputRetweetFileName.disabled = GM_getValue('retweetMode', false) ? false : true;
  1088. question4.appendChild(inputRetweetFileName);
  1089. let retweetFileNameExplain = document.createElement('p');
  1090. retweetFileNameExplain.textContent = text[18];
  1091. retweetFileNameExplain.style.marginTop = '0.5rem';
  1092. retweetFileNameExplain.style.whiteSpace = 'pre';
  1093. retweetFileNameExplain.style.marginBottom = '0';
  1094. retweetFileNameExplain.style.color = 'gray';
  1095. // retweetFileNameExplain.style.display = GM_getValue('retweetMode', false) ? 'block' : 'none';
  1096. question4.appendChild(retweetFileNameExplain);
  1097. let labelRetweetPackName = document.createElement('label');
  1098. labelRetweetPackName.textContent = text[19];
  1099. labelRetweetPackName.setAttribute('for', 'retweetPackFileName');
  1100. labelRetweetPackName.style.display = 'block';
  1101. labelRetweetPackName.style.marginTop = '0.5rem';
  1102. labelRetweetPackName.style.color = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? null : 'gray';
  1103. // labelRetweetPackName.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
  1104. question4.appendChild(labelRetweetPackName);
  1105. let inputRetweetPackName = document.createElement('input');
  1106. inputRetweetPackName.type = 'text';
  1107. inputRetweetPackName.id = 'retweetPackFileName';
  1108. inputRetweetPackName.name = 'retweetPackFileName';
  1109. inputRetweetPackName.style.marginTop = '0.5rem';
  1110. inputRetweetPackName.style.width = 'calc(100% - 1rem)';
  1111. inputRetweetPackName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
  1112. inputRetweetPackName.style.borderStyle = 'solid';
  1113. inputRetweetPackName.style.borderColor = 'lightgray';
  1114. inputRetweetPackName.style.borderWidth = '0.14rem';
  1115. inputRetweetPackName.style.borderRadius = '0.2rem';
  1116. inputRetweetPackName.defaultValue = GM_getValue('retweetPackFileName', '{mblogid}.zip');
  1117. // inputRetweetPackName.style.display = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? 'block' : 'none';
  1118. inputRetweetPackName.disabled = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? false : true;
  1119. question4.appendChild(inputRetweetPackName);
  1120. let retweetPackExplain = document.createElement('p');
  1121. retweetPackExplain.textContent = text[20];
  1122. retweetPackExplain.style.marginTop = '0.5rem';
  1123. retweetPackExplain.style.marginBottom = '0';
  1124. retweetPackExplain.style.color = 'gray';
  1125. // retweetPackExplain.style.display = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? 'block' : 'none';
  1126. question4.appendChild(retweetPackExplain);
  1127. modal.appendChild(question4);
  1128. let question5 = document.createElement('p');
  1129. question5.style.paddingLeft = '2rem';
  1130. question5.style.paddingRight = '2rem';
  1131. question5.style.marginTop = '1rem';
  1132. question5.style.marginBottom = '0';
  1133. let labelAriaMode = document.createElement('label');
  1134. labelAriaMode.setAttribute('for', 'ariaMode');
  1135. labelAriaMode.textContent = text[21];
  1136. labelAriaMode.style.display = 'inline-block';
  1137. labelAriaMode.style.paddingRight = '0.2rem';
  1138. question5.appendChild(labelAriaMode);
  1139. let inputAriaMode = document.createElement('input');
  1140. inputAriaMode.type = 'checkbox';
  1141. inputAriaMode.id = 'ariaMode';
  1142. inputAriaMode.checked = GM_getValue('ariaMode', false);
  1143. question5.appendChild(inputAriaMode);
  1144. let ariaModeExplain = document.createElement('p');
  1145. ariaModeExplain.textContent = text[23];
  1146. ariaModeExplain.style.marginTop = '0.5rem';
  1147. ariaModeExplain.style.marginBottom = '0';
  1148. ariaModeExplain.style.color = 'gray';
  1149. question5.appendChild(ariaModeExplain);
  1150. let labelAriaRpcUrl = document.createElement('label');
  1151. labelAriaRpcUrl.textContent = text[22];
  1152. labelAriaRpcUrl.setAttribute('for', 'ariaRpcUrl');
  1153. labelAriaRpcUrl.style.display = 'block';
  1154. labelAriaRpcUrl.style.marginTop = '0.5rem';
  1155. labelAriaRpcUrl.style.color = GM_getValue('ariaMode', false) ? null : 'gray';
  1156. question5.appendChild(labelAriaRpcUrl);
  1157. let inputAriaRpcUrl = document.createElement('input');
  1158. inputAriaRpcUrl.type = 'text';
  1159. inputAriaRpcUrl.id = 'ariaRpcUrl';
  1160. inputAriaRpcUrl.name = 'ariaRpcUrl';
  1161. inputAriaRpcUrl.style.marginTop = '0.5rem';
  1162. inputAriaRpcUrl.style.width = 'calc(100% - 1rem)';
  1163. inputAriaRpcUrl.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
  1164. inputAriaRpcUrl.style.borderStyle = 'solid';
  1165. inputAriaRpcUrl.style.borderColor = 'lightgray';
  1166. inputAriaRpcUrl.style.borderWidth = '0.14rem';
  1167. inputAriaRpcUrl.style.borderRadius = '0.2rem';
  1168. inputAriaRpcUrl.defaultValue = GM_getValue('ariaRpcUrl', 'http://localhost:6800/jsonrpc');
  1169. // inputAriaRpcUrl.style.display = GM_getValue('ariaMode', false) ? 'block' : 'none';
  1170. inputAriaRpcUrl.disabled = GM_getValue('ariaMode', false) ? false : true;
  1171. question5.appendChild(inputAriaRpcUrl);
  1172. let inputAriaExplain = document.createElement('p');
  1173. inputAriaExplain.textContent = text[24];
  1174. inputAriaExplain.style.marginTop = '0.5rem';
  1175. inputAriaExplain.style.marginBottom = '0';
  1176. inputAriaExplain.style.color = 'gray';
  1177. question5.appendChild(inputAriaExplain);
  1178. modal.appendChild(question5);
  1179. inputRetweetMode.addEventListener('change', function(event) {
  1180. if (event.currentTarget.checked) {
  1181. // labelRetweetFileName.style.display = 'block';
  1182. // inputRetweetFileName.style.display = 'block';
  1183. // retweetFileNameExplain.style.display = 'block';
  1184. inputRetweetFileName.disabled = false;
  1185. labelRetweetFileName.style.color = null;
  1186. inputRetweetFileName.style.borderColor = 'gray';
  1187. } else {
  1188. // labelRetweetFileName.style.display = 'none';
  1189. // inputRetweetFileName.style.display = 'none';
  1190. // retweetFileNameExplain.style.display = 'none';
  1191. inputRetweetFileName.disabled = true;
  1192. labelRetweetFileName.style.color = 'gray';
  1193. inputRetweetFileName.style.borderColor = 'lightgray';
  1194. }
  1195. if (event.currentTarget.checked && inputZipMode.checked && !inputAriaMode.checked) {
  1196. inputRetweetPackName.disabled = false;
  1197. labelRetweetPackName.style.color = null;
  1198. inputRetweetPackName.style.borderColor = 'gray';
  1199. } else {
  1200. inputRetweetPackName.disabled = true;
  1201. labelRetweetPackName.style.color = 'gray';
  1202. inputRetweetPackName.style.borderColor = 'lightgray';
  1203. }
  1204. });
  1205. inputZipMode.addEventListener('change', function(event) {
  1206. if (event.currentTarget.checked) {
  1207. // labelPackName.style.display = 'block';
  1208. // inputPackName.style.display = 'block';
  1209. // filePackExplain.style.display = 'block';
  1210. inputPackName.disabled = false;
  1211. labelPackName.style.color = null;
  1212. inputPackName.style.borderColor = 'gray';
  1213. } else {
  1214. // labelPackName.style.display = 'none';
  1215. // inputPackName.style.display = 'none';
  1216. // filePackExplain.style.display = 'none';
  1217. inputPackName.disabled = true;
  1218. labelPackName.style.color = 'gray';
  1219. inputPackName.style.borderColor = 'lightgray';
  1220. }
  1221. if (event.currentTarget.checked && inputRetweetMode.checked) {
  1222. inputRetweetPackName.disabled = false;
  1223. labelRetweetPackName.style.color = null;
  1224. inputRetweetPackName.style.borderColor = 'gray';
  1225. } else {
  1226. inputRetweetPackName.disabled = true;
  1227. labelRetweetPackName.style.color = 'gray';
  1228. inputRetweetPackName.style.borderColor = 'lightgray';
  1229. }
  1230. });
  1231. inputAriaMode.addEventListener('change', function(event) {
  1232. if (event.currentTarget.checked) {
  1233. // labelAriaRpcUrl.style.display = 'block';
  1234. // inputAriaRpcUrl.style.display = 'block';
  1235. inputAriaRpcUrl.disabled = false;
  1236. labelAriaRpcUrl.style.color = null;
  1237. inputAriaRpcUrl.style.borderColor = 'gray';
  1238. inputZipMode.disabled = true;
  1239. labelZipMode.style.color = 'gray';
  1240. } else {
  1241. // labelAriaRpcUrl.style.display = 'none';
  1242. // inputAriaRpcUrl.style.display = 'none';
  1243. inputAriaRpcUrl.disabled = true;
  1244. labelAriaRpcUrl.style.color = 'gray';
  1245. inputAriaRpcUrl.style.borderColor = 'lightgray';
  1246. inputZipMode.disabled = false;
  1247. labelZipMode.style.color = null;
  1248. }
  1249. if (!event.currentTarget.checked && inputZipMode.checked) {
  1250. inputPackName.disabled = false;
  1251. labelPackName.style.color = null;
  1252. inputPackName.style.borderColor = 'gray';
  1253. } else {
  1254. inputPackName.disabled = true;
  1255. labelPackName.style.color = 'gray';
  1256. inputPackName.style.borderColor = 'lightgray';
  1257. }
  1258. if (!event.currentTarget.checked && inputZipMode.checked && inputRetweetMode.checked) {
  1259. inputRetweetPackName.disabled = false;
  1260. labelRetweetPackName.style.color = null;
  1261. inputRetweetPackName.style.borderColor = 'gray';
  1262. } else {
  1263. inputRetweetPackName.disabled = true;
  1264. labelRetweetPackName.style.color = 'gray';
  1265. inputRetweetPackName.style.borderColor = 'lightgray';
  1266. }
  1267. });
  1268. let okButton = document.createElement('button');
  1269. okButton.textContent = text[5];
  1270. okButton.style.paddingTop = '0.5rem';
  1271. okButton.style.paddingBottom = '0.5rem';
  1272. okButton.style.margin = '2rem';
  1273. okButton.style.backgroundColor = 'darkblue';
  1274. okButton.style.color = 'white';
  1275. okButton.style.fontSize = '1.5rem';
  1276. okButton.style.fontWeight = 'bold';
  1277. okButton.style.width = '21rem';
  1278. okButton.style.borderStyle = 'solid';
  1279. okButton.style.borderRadius = '0.5rem';
  1280. okButton.style.borderColor = 'black';
  1281. okButton.style.borderWidth = '0.2rem';
  1282. okButton.addEventListener('mouseover', function(event) {
  1283. okButton.style.backgroundColor = 'blue';
  1284. });
  1285. okButton.addEventListener('mouseout', function(event) {
  1286. okButton.style.backgroundColor = 'darkblue';
  1287. });
  1288. okButton.addEventListener('mousedown', function(event) {
  1289. okButton.style.backgroundColor = 'darkblue';
  1290. });
  1291. okButton.addEventListener('mouseover', function(event) {
  1292. okButton.style.backgroundColor = 'blue';
  1293. });
  1294. function resizeWindow(event) {
  1295. // console.log('resize');
  1296. bg.style.width = document.documentElement.clientWidth.toString() + 'px';
  1297. bg.style.height = document.documentElement.clientHeight.toString() + 'px';
  1298. modal.style.top = (( document.documentElement.clientHeight - modal.offsetHeight ) / 2).toString() + 'px';
  1299. modal.style.left = (( document.documentElement.clientWidth - modal.offsetWidth ) / 2).toString() + 'px';
  1300. }
  1301. okButton.addEventListener('click', function(event) {
  1302. /*if(document.getElementById('chooseButton').checked == true) {
  1303. GM_setValue('addDlBtnMode', 1);
  1304. addDlBtnMode = 1;
  1305. addStartButton();
  1306. } else {
  1307. GM_setValue('addDlBtnMode', 2);
  1308. addDlBtnMode = 2;
  1309. addEventListener();
  1310. }*/
  1311. if (document.getElementById('zipMode').checked && (!document.getElementById('dlFileName').value.includes('{original}') || !document.getElementById('dlFileName').value.includes('{original}'))) {
  1312. document.getElementById('dlFileName').focus();
  1313. alert(text[27].replaceAll(/\n/g, ''));
  1314. return;
  1315. }
  1316. GM_setValue('dlFileName', document.getElementById('dlFileName').value);
  1317. GM_setValue('retweetMode', document.getElementById('retweetMode').checked);
  1318. GM_setValue('retweetFileName', document.getElementById('retweetFileName').value);
  1319. GM_setValue('zipMode', document.getElementById('zipMode').checked);
  1320. GM_setValue('packFileName', document.getElementById('packFileName').value);
  1321. GM_setValue('retweetPackFileName', document.getElementById('retweetPackFileName').value);
  1322. GM_setValue('ariaMode', document.getElementById('ariaMode').checked);
  1323. GM_setValue('ariaRpcUrl', document.getElementById('ariaRpcUrl').value);
  1324. document.body.removeChild(modal);
  1325. document.body.removeChild(bg);
  1326. window.removeEventListener('resize', resizeWindow);
  1327. });
  1328. modal.appendChild(okButton);
  1329. document.body.appendChild(modal);
  1330. bg.addEventListener('click', function(event) {
  1331. document.body.removeChild(modal);
  1332. document.body.removeChild(bg);
  1333. window.removeEventListener('resize', resizeWindow);
  1334. });
  1335. resizeWindow();
  1336. window.addEventListener('resize', resizeWindow);
  1337. }
  1338.  
  1339. let svg = document.getElementById('__SVG_SPRITE_NODE__');
  1340. let symbol = document.createElementNS('http://www.w3.org/2000/svg', 'symbol');
  1341. symbol.id = 'woo_svg_download';
  1342. symbol.setAttribute('viewBox', '0 0 100 100');
  1343. symbol.innerHTML = '<path d="m25,0l50,0l0,50l25,0l-50,50l-50,-50l25,0l0,-50" fill="currentColor"></path><path d="m30,5l40,0l0,50l20,0l-40,40l-40,-40l20,0l0,-50" fill="white"></path>';
  1344. svg.appendChild(symbol);
  1345. /*
  1346. if(addDlBtnMode == 0) {
  1347. showModal();
  1348. } else if (addDlBtnMode == 1) {
  1349. addStartButton();
  1350. } else if (addDlBtnMode == 2) {
  1351. addEventListener();
  1352. }
  1353. */
  1354. if(GM_getValue('dlFileName', null) === null) {
  1355. showModal();
  1356. }
  1357. new MutationObserver((mutationList, observer) => {
  1358. // console.log(mutationList);
  1359. if (location.host == 'weibo.com' || location.host == 'www.weibo.com') {
  1360. const cards = document.body.querySelectorAll('article.woo-panel-main');
  1361. // console.log(cards);
  1362. for (const card of cards) {
  1363. handleCard(card);
  1364. }
  1365. for (const mutation of mutationList) {
  1366. // console.log(mutation.target);
  1367. if (mutation.type === 'childList' && mutation.target.tagName === 'DIV' && (mutation.target.className.includes('wbpro-feed-content') || mutation.target.className.includes('Feed_retweet_JqZJb'))) {
  1368. for (const node of mutation.addedNodes) {
  1369. // console.log(node);
  1370. const imgs = node.querySelectorAll('img.woo-picture-img,img.picture_focusImg_1z5In,img.picture-viewer_pic_37YQ3,video.picture-viewer_pic_37YQ3');
  1371. // console.log(imgs);
  1372. for (const [ idx, img ] of Object.entries(imgs)) {
  1373. if (img.parentElement.getElementsByClassName('download-single-button').length === 0) {
  1374. if (img.className.includes('picture-viewer_pic_37YQ3')) {
  1375. const previews = node.querySelectorAll('div.picture-viewer_preview_2wOSq');
  1376. for (const [ index, preview ] of Object.entries(previews)) {
  1377. if (preview.className.includes('picture-viewer_cur_anUEY')) {
  1378. addSingleDlBtn(img, parseInt(index));
  1379. }
  1380. }
  1381. } else {
  1382. addSingleDlBtn(img, parseInt(idx));
  1383. }
  1384. }
  1385. }
  1386. }
  1387. }
  1388. }
  1389. } else if (location.host == 's.weibo.com') {
  1390. // let cards = document.querySelectorAll('#pl_feedlist_index .card-wrap');
  1391. const footers = document.querySelectorAll('#pl_feedlist_index .card-act');
  1392. for (const footer of footers) {
  1393. if(footer.getElementsByClassName('download-button').length > 0) {
  1394. // console.log('already added download button');
  1395. } else {
  1396. // console.log(footer.parentElement);
  1397. if(footer.parentElement.className == 'card' && footer.parentElement.parentElement.className == 'card-wrap') {
  1398. const card = footer.parentElement;
  1399. let added = false;
  1400. const media_prev = card.querySelector('div[node-type="feed_list_media_prev"]');
  1401. // console.log(media_prev);
  1402. if (media_prev) {
  1403. const imgs = media_prev.getElementsByTagName('img');
  1404. // console.log(imgs);
  1405. if(imgs.length > 0) {
  1406. sAddDlBtn(footer);
  1407. added = true;
  1408. }
  1409. const videos = card.getElementsByTagName('video');
  1410. if(videos.length > 0 && added == false) {
  1411. sAddDlBtn(footer);
  1412. }
  1413. }
  1414. }
  1415. }
  1416. }
  1417. }
  1418. }).observe(document.body, { attributes: false, childList: true, subtree: true });
  1419.  
  1420. let settingButton = document.createElement('button');
  1421. settingButton.textContent = text[6];
  1422. settingButton.style.position = 'fixed';
  1423. settingButton.style.top = '4rem';
  1424. settingButton.style.left = '0rem';
  1425. settingButton.style.fontSize = '0.7rem';
  1426. settingButton.style.backgroundColor = 'gray';
  1427. settingButton.style.color = 'white';
  1428. settingButton.style.borderWidth = '0.2rem';
  1429. settingButton.style.borderStyle = 'solid';
  1430. settingButton.style.borderRadius = '0.5rem';
  1431. settingButton.style.borderColor = 'lightgrey';
  1432. settingButton.style.zIndex = 400;
  1433. settingButton.style.paddingLeft = '1rem';
  1434. settingButton.style.paddingRight = '1rem';
  1435. settingButton.style.paddingTop = '0.2rem';
  1436. settingButton.style.paddingBottom = '0.2rem';
  1437. settingButton.addEventListener('mouseover', function(event) {
  1438. settingButton.style.backgroundColor = 'darkgray';
  1439. settingButton.style.color = 'black';
  1440. });
  1441. settingButton.addEventListener('mouseout', function(event) {
  1442. settingButton.style.backgroundColor = 'gray';
  1443. settingButton.style.color = 'white';
  1444. });
  1445. settingButton.addEventListener('mousedown', function(event) {
  1446. settingButton.style.backgroundColor = 'gray';
  1447. settingButton.style.color = 'white';
  1448. });
  1449. settingButton.addEventListener('mouseup', function(event) {
  1450. settingButton.style.backgroundColor = 'darkgray';
  1451. settingButton.style.color = 'black';
  1452. });
  1453. settingButton.addEventListener('click', showModal);
  1454. document.body.appendChild(settingButton);
  1455. GM_registerMenuCommand(text[25], showModal, "0");
  1456. })();

QingJ © 2025

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