P站画师个人作品批量下载工具

配合Aria2,一键批量下载P站画师的全部作品

目前为 2019-04-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name PixivUserBatchDownload
  3. // @name:zh-CN P站画师个人作品批量下载工具
  4. // @name:zh-TW P站畫師個人作品批量下載工具
  5. // @name:zh-HK P站畫師個人作品批量下載工具
  6. // @namespace http://www.mapaler.com/
  7. // @homepage https://github.com/Mapaler/PixivUserBatchDownload
  8. // @supportURL https://github.com/Mapaler/PixivUserBatchDownload/issues
  9. // @description Batch download pixiv user's images in one key.
  10. // @description:zh-CN 配合Aria2,一键批量下载P站画师的全部作品
  11. // @description:zh-TW 配合Aria2,一鍵批量下載P站畫師的全部作品
  12. // @description:zh-HK 配合Aria2,一鍵批量下載P站畫師的全部作品
  13. // @homepage https://github.com/Mapaler/PixivUserBatchDownload
  14. // @supportURL https://github.com/Mapaler/PixivUserBatchDownload/issues
  15. // @include *://www.pixiv.net/*
  16. // @exclude *://www.pixiv.net/*mode=manga&illust_id*
  17. // @exclude *://www.pixiv.net/*mode=big&illust_id*
  18. // @exclude *://www.pixiv.net/*mode=manga_big*
  19. // @exclude *://www.pixiv.net/*search.php*
  20. // @version 5.7.65
  21. // @author Mapaler <mapaler@163.com>
  22. // @copyright 2018+, Mapaler <mapaler@163.com>
  23. // @icon http://www.pixiv.net/favicon.ico
  24. // @grant unsafeWindow
  25. // @grant window.close
  26. // @grant window.focus
  27. // @grant GM_xmlhttpRequest
  28. // @grant GM_getValue
  29. // @grant GM_setValue
  30. // @grant GM_deleteValue
  31. // @grant GM_listValues
  32. // @grant GM_addValueChangeListener
  33. //-@grant GM_notification
  34. // @grant GM_registerMenuCommand
  35. // @connect localhost
  36. // @connect pixiv.net
  37. // @connect 127.0.0.1
  38. // @connect *
  39. // @noframes
  40. // ==/UserScript==
  41.  
  42. //非顶级页面退出程序
  43. if (
  44. self.frameElement && self.frameElement.tagName == "IFRAME" || //iframe判断方式1
  45. window.frames.length != parent.frames.length || //iframe判断方式2
  46. self != top //iframe判断方式3
  47. )
  48. { //iframe退出执行
  49. return;
  50. }
  51. /*
  52. * 公共变量区
  53. */
  54. var pubd = { //储存设置
  55. configVersion: 0, //当前设置版本,用于提醒是否需要重置
  56. cssVersion: 9, //当前需求CSS版本,用于提醒是否需要更新CSS
  57. touch: false, //是触屏
  58. loggedIn: false, //登陆了
  59. start: null, //开始按钮
  60. menu: null, //菜单
  61. dialog: { //窗口些个
  62. config: null, //设置窗口
  63. login: null, //登陆窗口
  64. downthis: null, //下载当前窗口
  65. },
  66. auth: null,
  67. downSchemes: [],
  68. downbreak: false,
  69. staruser: [],
  70. };
  71.  
  72. var lang = (navigator.language||navigator.userLanguage).replace("-","_"); //获取浏览器语言
  73. var scriptVersion = "LocalDebug"; //本程序的版本
  74. var scriptName = "PixivUserBatchDownload"; //本程序的名称
  75. var scriptIcon = "http://www.pixiv.net/favicon.ico"; //本程序的图标
  76. if (typeof(GM_info)!="undefined")
  77. {
  78. scriptVersion = GM_info.script.version.replace(/(^\s*)|(\s*$)/g, "");
  79. scriptName = GM_info.script.localizedName || GM_info.script.name_i18n[lang] || GM_info.script.name;
  80. scriptIcon = GM_info.script.icon || scriptIcon; //本程序的图标
  81. }
  82.  
  83. var illustPattern = '(https?://([^/]+)/.+/\\d{4}/\\d{2}/\\d{2}/\\d{2}/\\d{2}/\\d{2}/(\\d+(?:-([0-9a-zA-Z]+))?(?:_p|_ugoira)))\\d+(?:_\\w+)?\\.([\\w\\d]+)'; //P站图片地址正则匹配式
  84. var limitingPattern = '(https?://([^/]+)/common/images/(limit_(mypixiv|unknown)))_\\d+\\.([\\w\\d]+)'; //P站上锁图片完整地址正则匹配式
  85. var limitingFilenamePattern = 'limit_(mypixiv|unknown)'; //P站上锁图片文件名正则匹配式
  86.  
  87. var UA = "PixivAndroidApp/5.0.115 (Android 9.0.0; Android SDK built for x86)"; //向P站请求数据时的UA
  88. var thisPageUserid = 0; //当前页面的画师ID
  89. var findInsertPlaceHook; //储存循环钩子
  90. var btnStartInsertPlace; //储存开始按钮插入点
  91. /*
  92. * 获取初始状态
  93. */
  94. //1、获取原网页数据对象
  95. if (typeof(unsafeWindow) != "undefined")
  96. {
  97. var pixiv = unsafeWindow.pixiv; //原来的信息
  98. var globalInitData = unsafeWindow.globalInitData; //新版的插画页面信息
  99. }
  100. //2、获取是否为登录状态与当前页面画师ID
  101. if (typeof(pixiv) == "undefined" && typeof(globalInitData) == "undefined")
  102. {
  103. console.error("PUBD:当前网页没有找到 pixiv 对象或 globalInitData 对象");
  104. }
  105. else
  106. {
  107. if (typeof(globalInitData) != "undefined") //新版的插画页面信息
  108. {
  109. pubd.loggedIn = true;
  110. thisPageUserid = Object.keys(globalInitData.preload.user)[0]; //id不是属性值,而是子对象名,所以需要通过这样的方式获取
  111. }
  112. else if (typeof(pixiv) != "undefined") //原来的信息
  113. {
  114. thisPageUserid = pixiv.context.userId;
  115. if (pixiv.user.loggedIn)
  116. {
  117. pubd.loggedIn = true; //判断是否已经登陆
  118. }
  119. }
  120. }
  121. //3、获取是否为手机版
  122. if (location.host.indexOf("touch") >= 0) //typeof(pixiv.AutoView)!="undefined"
  123. {
  124. pubd.touch = true;
  125. console.info("PUBD:当前访问的是P站触屏手机版,我没开发。");
  126. } else {
  127. console.info("PUBD:当前访问的是P站桌面版");
  128. }
  129.  
  130. /*
  131. * Debug 用 仿GM函数区
  132. */
  133. //仿GM_xmlhttpRequest函数v1.3
  134. if (typeof(GM_xmlhttpRequest) == "undefined") {
  135. var GM_xmlhttpRequest = function(GM_param) {
  136.  
  137. var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
  138. xhr.open(GM_param.method, GM_param.url, true);
  139. if (GM_param.responseType) xhr.responseType = GM_param.responseType;
  140. if (GM_param.overrideMimeType) xhr.overrideMimeType(GM_param.overrideMimeType);
  141. xhr.onreadystatechange = function() //设置回调函数
  142. {
  143. if (xhr.readyState === xhr.DONE) {
  144. if (xhr.status === 200 && GM_param.onload)
  145. GM_param.onload(xhr);
  146. if (xhr.status !== 200 && GM_param.onerror)
  147. GM_param.onerror(xhr);
  148. }
  149. }
  150.  
  151. for (var header in GM_param.headers) {
  152. xhr.setRequestHeader(header, GM_param.headers[header]);
  153. }
  154.  
  155. xhr.send(GM_param.data ? GM_param.data : null);
  156. }
  157. }
  158. //仿GM_getValue函数v1.0
  159. if (typeof(GM_getValue) == "undefined") {
  160. var GM_getValue = function(name, type) {
  161. var value = localStorage.getItem(name);
  162. if (value == undefined) return value;
  163. if ((/^(?:true|false)$/i.test(value) && type == undefined) || type == "boolean") {
  164. if (/^true$/i.test(value))
  165. return true;
  166. else if (/^false$/i.test(value))
  167. return false;
  168. else
  169. return Boolean(value);
  170. } else if ((/^\-?[\d\.]+$/i.test(value) && type == undefined) || type == "number")
  171. return Number(value);
  172. else
  173. return value;
  174. }
  175. }
  176. //仿GM_setValue函数v1.0
  177. if (typeof(GM_setValue) == "undefined") {
  178. var GM_setValue = function(name, value) {
  179. localStorage.setItem(name, value);
  180. }
  181. }
  182. //仿GM_deleteValue函数v1.0
  183. if (typeof(GM_deleteValue) == "undefined") {
  184. var GM_deleteValue = function(name) {
  185. localStorage.removeItem(name);
  186. }
  187. }
  188. //仿GM_listValues函数v1.0
  189. if (typeof(GM_listValues) == "undefined") {
  190. var GM_listValues = function() {
  191. var keys = new Array();
  192. for (var ki = 0, kilen = localStorage.length; ki < kilen; ki++) {
  193. keys.push(localStorage.key(ki));
  194. }
  195. return keys;
  196. }
  197. }
  198.  
  199. //仿GM_notification函数v1.2,发送网页通知。
  200. //此函数非Debug用,为了替换选项较少但是兼容其格式的GM_notification插件
  201. if (typeof(GM_notification) == "undefined") {
  202. var GM_notification = function(text, title, image, onclick) {
  203. var options = {},rTitle,rText;
  204. var dataMode = (typeof(text) == "string"); //GM_notification有两种模式,普通4参数模式和option对象模式
  205. if (dataMode)
  206. { //普通模式
  207. rTitle = title;
  208. rText = text;
  209. options.body = text;
  210. options.icon = image;
  211. }else
  212. { //选项模式
  213. var details = text, ondone = title, onclose = image;
  214. rTitle = details.title;
  215. rText = details.text;
  216. if (details.text) options.body = details.text;
  217. if (details.image) options.icon = details.image;
  218. if (details.timeout) options.timestamp = details.timeout;
  219. //if (details.highlight) options.highlight = details.highlight; //没找到这个功能
  220. }
  221.  
  222. function sendNotification(general){
  223. var n = new Notification(rTitle, options);
  224. if (general)
  225. { //普通模式
  226. if (onclick) n.onclick = onclick;
  227. }else
  228. { //选项模式,这里和TamperMonkey API不一样,区分了关闭和点击。
  229. if (ondone) n.onclick = ondone;
  230. if (onclose) n.onclose = onclose;
  231. }
  232. }
  233. // 先检查浏览器是否支持
  234. if (!("Notification" in window)) {
  235. alert(rTitle + "\r\n" + rText);
  236. // 检查用户是否同意接受通知
  237. } else if (Notification.permission === "granted") {
  238. Notification.requestPermission(function(permission) {
  239. sendNotification(dataMode);
  240. });
  241. }
  242. // 否则我们需要向用户获取权限
  243. else if (Notification.permission !== 'denied') {
  244. Notification.requestPermission(function(permission) {
  245. // 如果用户同意,就可以向他们发送通知
  246. if (permission === "granted") {
  247. sendNotification(dataMode);
  248. }
  249. });
  250. }
  251. }
  252. }
  253.  
  254. //Debug兼容,留空函数
  255. if (typeof(GM_addValueChangeListener) == "undefined") {
  256. var GM_addValueChangeListener = function() {return;}
  257. }
  258. if (typeof(GM_registerMenuCommand) == "undefined") {
  259. var GM_registerMenuCommand = function() {return;}
  260. }
  261.  
  262. /*
  263. * 现成函数库,好像根本没用上
  264. */
  265. //String.format实现占位符输出
  266. String.prototype.format = function() {
  267. if (arguments.length == 0) return this;
  268. for (var s = this, i = 0; i < arguments.length; i++)
  269. s = s.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);
  270. return s;
  271. };
  272.  
  273. /*
  274. * 简化函数区,简化常用函数
  275. */
  276. //document.createElement
  277. var dBd = document.body;
  278. function dcE(tagName, options) {
  279. return document.createElement(tagName, options);
  280. }
  281. //document.createTextNode
  282. function dcTN(data) {
  283. return document.createTextNode(data);
  284. }
  285. //document.querySelector
  286. function dqS(data) {
  287. return document.querySelector(data);
  288. }
  289. //document.querySelectorAll
  290. function dqSA(selectors) {
  291. return document.querySelectorAll(selectors);
  292. }
  293. /*
  294. * 自定义对象区
  295. */
  296.  
  297.  
  298. //一个用户的信息
  299. var UserInfo = function() {
  300. var obj = {
  301. done: false,
  302. info: {
  303. profile: null,
  304. user: null,
  305. profile: null,
  306. },
  307. illusts: {
  308. done: false,
  309. item: [],
  310. break: false,
  311. runing: false,
  312. next_url: "",
  313. },
  314. bookmarks: {
  315. done: false,
  316. item: [],
  317. break: false,
  318. runing: false,
  319. next_url: "",
  320. },
  321. }
  322. return obj;
  323. }
  324.  
  325. //一个Post数据
  326. var PostDataObject = (function() {
  327.  
  328. return function(obj) {
  329. var postdata = new Object;
  330. if (obj)
  331. postdata.data = Object.assign({}, obj); //合并obj
  332. postdata.increase = function(obj) {
  333. postdata.data = Object.assign(postdata.data, obj); //合并obj
  334. }
  335. postdata.toPostString = function() {
  336. var arr = new Array;
  337. for (var na in postdata.data) {
  338. var item = [na, postdata.data[na]];
  339. arr.push(item);
  340. }
  341.  
  342. var str = arr.map(
  343. function(item) {
  344. return item.join("=");
  345. }
  346. ).join("&");
  347. return str;
  348. }
  349. return postdata;
  350. }
  351. })();
  352.  
  353. //一个本程序使用的headers数据
  354. var HeadersObject = function(obj) {
  355. var headers = {
  356. 'App-OS': 'android',
  357. 'App-OS-Version': '9.0.0',
  358. 'App-Version': '5.0.115',
  359. 'User-Agent': UA,
  360. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', //重要
  361. "Referer": "https://app-api.pixiv.net/",
  362. }
  363. if (obj)
  364. headers = Object.assign(headers, obj); //合并obj
  365. return headers;
  366. }
  367.  
  368. //一个认证方案
  369. var Auth = (function() {
  370.  
  371. return function(username, password, remember) {
  372. if (!username) username = "";
  373. if (!password) password = "";
  374. if (!remember) remember = false;
  375. var auth = { //原始结构
  376. response: {
  377. access_token: "",
  378. expires_in: 0,
  379. token_type: "",
  380. scope: "",
  381. refresh_token: "",
  382. user: {
  383. profile_image_urls: {
  384. px_16x16: "",
  385. px_50x50: "",
  386. px_170x170: "",
  387. },
  388. id: "",
  389. name: "",
  390. account: "",
  391. mail_address: "",
  392. is_premium: false,
  393. x_restrict: 0,
  394. is_mail_authorized: true,
  395. },
  396. device_token: "",
  397. },
  398. needlogin: false,
  399. username: username,
  400. password: password,
  401. save_account: remember,
  402. login_date: null,
  403. }
  404. auth.newAccount = function(username, password, remember) {
  405. if (typeof(remember) == "boolean") auth.save_account = remember;
  406. auth.username = username;
  407. auth.password = password;
  408. }
  409. auth.loadFromResponse = function(response) {
  410. auth = Object.assign(auth, response);
  411. }
  412. auth.save = function() {
  413. var saveObj = JSON.parse(JSON.stringify(auth)); //深度拷贝
  414. if (!saveObj.save_account) {
  415. saveObj.username = "";
  416. saveObj.password = "";
  417. }
  418. GM_setValue("pubd-auth", JSON.stringify(saveObj));
  419. }
  420.  
  421. auth.login = function(onload_suceess_Cb, onload_hasError_Cb, onload_notJson_Cb, onerror_Cb) {
  422. var postObj = new PostDataObject({ //Post时发送的数据
  423. client_id: "MOBrBDS8blbauoSck0ZfDbtuzpyT", //安卓某个版本的数据
  424. client_secret: "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj", //安卓某个版本的数据
  425. grant_type: "password",
  426. username: auth.username,
  427. password: auth.password,
  428. device_token: "pixiv",
  429. get_secure_url: "true",
  430. })
  431.  
  432. //登陆是老的API
  433. GM_xmlhttpRequest({
  434. url: "https://oauth.secure.pixiv.net/auth/token",
  435. method: "post",
  436. responseType: "text",
  437. headers: new HeadersObject(),
  438. data: postObj.toPostString(),
  439. onload: function(response) {
  440. try {
  441. var jo = JSON.parse(response.responseText);
  442. if (jo.has_error || jo.errors) {
  443. console.error("登录失败,返回错误消息", jo);
  444. onload_hasError_Cb(jo);
  445. } else { //登陆成功
  446. auth.loadFromResponse(jo);
  447. auth.login_date = new Date();
  448. console.info("登陆成功", jo);
  449. onload_suceess_Cb(jo);
  450. }
  451. } catch (e) {
  452. console.error("登录失败,返回可能不是JSON,或程序异常", e, response);
  453. onload_notJson_Cb(response);
  454. }
  455. },
  456. onerror: function(response) {
  457. console.error("登录失败,AJAX发送失败", response);
  458. onerror_Cb(response);
  459. }
  460. })
  461. }
  462. return auth;
  463. };
  464. })();
  465.  
  466. //一个下载方案
  467. var DownScheme = (function() {
  468. //一个自定义掩码
  469. return function(name) {
  470. var obj = {
  471. name: name ? name : "默认方案",
  472. rpcurl: "http://localhost:6800/jsonrpc",
  473. https2http: false,
  474. downfilter: "",
  475. savedir: "D:/PixivDownload/",
  476. savepath: "%{illust.user.id}/%{illust.filename}%{page}.%{illust.extention}",
  477. textout: "%{illust.url_without_page}%{page}.%{illust.extention}\n",
  478. masklist: [],
  479. mask: {
  480. add: function(name, logic, content) {
  481. var mask = {
  482. name: name,
  483. logic: logic,
  484. content: content,
  485. };
  486. obj.masklist.push(mask);
  487. return mask;
  488. },
  489. remove: function(index) {
  490. obj.masklist.splice(index, 1);
  491. },
  492. },
  493. loadFromJson: function(ojson) {
  494. var json = ojson;
  495. if (typeof(ojson) == "string") {
  496. try {
  497. json = JSON.parse(ojson);
  498. } catch (e) {
  499. console.error(e);
  500. return false;
  501. }
  502. }
  503. this.name = json.name;
  504. this.https2http = [0, "false", false, undefined, null].indexOf(json.https2http) < 0; //存在任一条件时即为false
  505. this.rpcurl = json.rpcurl;
  506. this.downfilter = json.downfilter || "";
  507. this.savedir = json.savedir;
  508. this.savepath = json.savepath;
  509. this.textout = json.textout;
  510. this.masklist = JSON.parse(JSON.stringify(json.masklist));
  511. return true;
  512. },
  513. }
  514. return obj;
  515. };
  516. })();
  517.  
  518. //创建菜单类
  519. var pubdMenu = (function() {
  520. //生成菜单项
  521. function buildMenuItem(title, classname, callback, submenu) {
  522. var item = dcE("li");
  523. if (title == 0) //title为0时,只添加一条菜单分割线
  524. {
  525. item.className = "pubd-menu-line" + (classname ? " " + classname : "");
  526. return item;
  527. }
  528. item.className = "pubd-menu-item" + (classname ? " " + classname : "");
  529.  
  530. //如果有子菜单则添加子菜单
  531. if (typeof(submenu) == "object") {
  532. item.classList.add("pubd-menu-includesub"); //表明该菜单项有子菜单
  533. submenu.classList.add("pubd-menu-submenu"); //表明该菜单是子菜单
  534. //a.addEventListener("mouseenter",function(){callback.show()});
  535. //a.addEventListener("mouseleave",function(){callback.hide()});
  536. item.appendChild(submenu);
  537. item.subitem = submenu;
  538. }else
  539. {
  540. item.subitem = null; //子菜单默认为空
  541. }
  542.  
  543. //添加链接
  544. var a = item.appendChild(dcE("a"));
  545. a.className = "pubd-menu-item-a"
  546. //添加图标
  547. var icon = a.appendChild(dcE("i"));
  548. icon.className = "pubd-icon";
  549. //添加文字
  550. var span = a.appendChild(dcE("span"));
  551. span.className = "text";
  552. span.innerHTML = title;
  553.  
  554. //添加菜单操作
  555. if (typeof(callback) == "string") { //为字符串时,当作链接处理
  556. a.target = "_blank";
  557. a.href = callback;
  558. } else if (typeof(callback) == "function") { //为函数时,当作按钮处理
  559. item.addEventListener("click", callback);
  560. //a.onclick = callback;
  561. }
  562. return item;
  563. }
  564.  
  565. return function(touch, classname) {
  566. var menu = dcE("ul");
  567. menu.className = "pubd-menu display-none" + (classname ? " " + classname : "");
  568. menu.item = new Array();
  569. //显示该菜单
  570. menu.show = function() {
  571. menu.classList.remove("display-none");
  572. }
  573. menu.hide = function() {
  574. menu.classList.add("display-none");
  575. }
  576. //添加菜单项
  577. menu.add = function(title, classname, callback, submenu) {
  578. var itm = buildMenuItem(title, classname, callback, submenu);
  579. this.appendChild(itm);
  580. this.item.push(itm)
  581. return itm;
  582. }
  583. //鼠标移出菜单时消失
  584. menu.addEventListener("mouseleave", function(e) {
  585. this.hide();
  586. });
  587. return menu;
  588. };
  589. })();
  590.  
  591. //创建通用对话框类
  592. var Dialog = (function() {
  593. //构建标题栏按钮
  594. function buildDlgCptBtn(text, classname, callback) {
  595. if (!callback) classname = "";
  596. var btn = dcE("a");
  597. btn.className = "dlg-cpt-btn" + (classname ? " " + classname : "");
  598. if (typeof(callback) == "string") {
  599. btn.target = "_blank";
  600. btn.href = callback;
  601. } else {
  602. if (callback)
  603. btn.addEventListener("click", callback);
  604. }
  605. var btnTxt = btn.appendChild(dcE("div"));
  606. btnTxt.className = "dlg-cpt-btn-text";
  607. btnTxt.innerHTML = text;
  608.  
  609. return btn;
  610. }
  611.  
  612. return function(caption, id, classname) {
  613. var dlg = dcE("div");
  614. dlg.className = "pubd-dialog display-none" + (classname ? " " + classname : "");
  615.  
  616. //添加图标与标题
  617. var cpt = dlg.appendChild(dcE("div"));
  618. cpt.className = "caption";
  619. dlg.icon = cpt.appendChild(dcE("i"));
  620. dlg.icon.className = "pubd-icon";
  621. dlg.caption = cpt.appendChild(dcE("span"));
  622. dlg.caption.innerHTML = caption;
  623.  
  624. //添加标题栏右上角按钮 captionButtons
  625. var cptBtns = dlg.cptBtns = dlg.appendChild(dcE("div"));
  626. cptBtns.className = "dlg-cpt-btns";
  627. //添加按钮的函数
  628. cptBtns.add = function(text, classname, callback) {
  629. var btn = buildDlgCptBtn(text, classname, callback);
  630. this.insertBefore(btn, this.firstChild);
  631. return btn;
  632. }
  633. //添加关闭按钮
  634. cptBtns.close = cptBtns.add("X", "dlg-btn-close", (function() {
  635. dlg.classList.add("display-none");
  636. }));
  637.  
  638. //添加内容区域
  639. var content = dlg.content = dlg.appendChild(dcE("div"));
  640. content.className = "dlg-content";
  641.  
  642. //窗口激活
  643. dlg.active = function() {
  644. if (!this.classList.contains("pubd-dlg-active")) { //如果没有激活的话才执行
  645. var dlgs = dqSA(".pubd-dialog"); //获取网页已经载入的所有的窗口
  646. for (var dlgi = 0; dlgi < dlgs.length; dlgi++) { //循环所有窗口
  647. if (dlgs[dlgi] != this)
  648. {
  649. dlgs[dlgi].classList.remove("pubd-dlg-active"); //取消激活
  650. dlgs[dlgi].style.zIndex = parseInt(window.getComputedStyle(dlgs[dlgi], null).getPropertyValue("z-index")) - 1; //从当前网页最终样式获取该窗体z级,并-1.
  651. }
  652. }
  653. this.classList.add("pubd-dlg-active"); //添加激活
  654. this.style.zIndex = ""; //z级归零
  655. }
  656. }
  657. //窗口初始化
  658. dlg.initialise = function() { //窗口初始化默认情况下什么也不做,具体在每个窗口再设置
  659. return;
  660. }
  661. //窗口显示
  662. dlg.show = function(posX, posY) {
  663. if (posX) dlg.style.left = posX + "px"; //更改显示时初始坐标
  664. if (posY) dlg.style.top = posY + "px";
  665. this.initialise(); //对窗体进行初始化(激活为可见前提前修改窗体内容)
  666. this.classList.remove("display-none");
  667. this.active(); //激活窗口
  668. }
  669. //窗口隐藏
  670. dlg.hide = function() { //默认情况下等同于关闭窗口
  671. this.cptBtns.close.click;
  672. }
  673. //添加鼠标拖拽移动
  674. var drag = dlg.drag = [0, 0]; //[X,Y] 用以储存窗体开始拖动时的鼠标相对窗口坐标差值。
  675. //startDrag(cpt, dlg);
  676. cpt.addEventListener("mousedown", function(e) { //按下鼠标则添加移动事件
  677. var eX = e.pageX>0?e.pageX:0, eY = e.pageY>0?e.pageY:0; //不允许鼠标坐标向上、左超出网页。
  678. drag[0] = eX - dlg.offsetLeft;
  679. drag[1] = eY - dlg.offsetTop;
  680. var handler_mousemove = function(e) { //移动鼠标则修改窗体坐标
  681. var eX = e.pageX>0?e.pageX:0, eY = e.pageY>0?e.pageY:0; //不允许鼠标坐标向上、左超出网页。
  682. dlg.style.left = (eX - drag[0]) + 'px';
  683. dlg.style.top = (eY - drag[1]) + 'px';
  684. };
  685. var handler_mouseup = function(e) { //抬起鼠标则取消移动事件
  686. document.removeEventListener("mousemove", handler_mousemove);
  687. };
  688. document.addEventListener("mousemove", handler_mousemove);
  689. document.addEventListener("mouseup", handler_mouseup, { once: true });
  690. });
  691. //点击窗口任何区域激活窗口
  692. dlg.addEventListener("mousedown", function(e) {
  693. dlg.active();
  694. });
  695. return dlg;
  696. };
  697. })();
  698.  
  699. //创建选项卡类,暂时没有开发
  700. var Tab = (function() {
  701.  
  702. return function(title) {
  703. var obj = {
  704. title: dcE("li"),
  705. content: dcE("li"),
  706. }
  707. obj.title = dcE("li");
  708. obj.title.className = "pubd-tab-title";
  709. obj.title.innerHTML = title;
  710. obj.name = function() {
  711. return this.title.textContent;
  712. }
  713. obj.rename = function(newName) {
  714. if (typeof(newName) == "string" && newName.length > 0) {
  715. this.title.innerHTML = newName;
  716. return true;
  717. } else
  718. return false;
  719. }
  720.  
  721. obj.content.className = "pubd-tab-content";
  722. obj.content.innerHTML = "设置内容";
  723.  
  724. return obj;
  725. };
  726. })();
  727.  
  728. //创建复数选项卡类,暂时没有开发
  729. var Tabs = (function() {
  730.  
  731. return function() {
  732. var tabs = dcE("div");
  733. tabs.className = "pubd-tabs";
  734. tabs.item = new Array(); //储存卡
  735. //添加卡名区域
  736. var ult = tabs.appendChild(dcE("ul"));
  737. ult.className = "tab-title";
  738. //添加卡内容区域
  739. var ulc = tabs.appendChild(dcE("ul"));
  740. ulc.className = "tab-content";
  741. tabs.add = function(name) {
  742. var tab = new Tab(name);
  743. tabs.item.push(tab);
  744. ult.appendChild(tab.title);
  745. ulc.appendChild(tab.content);
  746. }
  747. return tabs;
  748. };
  749. })();
  750.  
  751. //创建框架类
  752. var Frame = (function() {
  753.  
  754. return function(title, classname) {
  755. var frame = dcE("div");
  756. frame.className = "pubd-frame" + (classname ? " " + classname : "");
  757.  
  758. var caption = frame.caption = frame.appendChild(dcE("div"));
  759. caption.className = "pubd-frame-caption";
  760. caption.innerHTML = title;
  761. var content = frame.content = frame.appendChild(dcE("div"));
  762. content.className = "pubd-frame-content";
  763.  
  764. frame.name = function() {
  765. return this.caption.textContent;
  766. }
  767. frame.rename = function(newName) {
  768. if (typeof(newName) == "string" && newName.length > 0) {
  769. this.caption.innerHTML = newName;
  770. return true;
  771. } else
  772. return false;
  773. }
  774.  
  775. return frame;
  776. };
  777. })();
  778.  
  779. //创建带Label的Input类
  780. var LabelInput = (function() {
  781.  
  782. return function(text, classname, name, type, value, beforeText, title) {
  783. var label = dcE("label");
  784. label.innerHTML = text;
  785. label.className = classname;
  786. if (typeof(title) != "undefined")
  787. label.title = title;
  788.  
  789. var ipt = label.input = dcE("input");
  790. ipt.name = name;
  791. ipt.id = ipt.name;
  792. ipt.type = type;
  793. ipt.value = value;
  794.  
  795. if (beforeText)
  796. label.insertBefore(ipt, label.firstChild);
  797. else
  798. label.appendChild(ipt);
  799. return label;
  800. };
  801. })();
  802.  
  803. //创建进度条类
  804. var Progress = (function() {
  805. //强制保留pos位小数,如:2,会在2后面补上00.即2.00
  806. function toDecimal2(num, pos) {
  807. var f = parseFloat(num);
  808. if (isNaN(f)) {
  809. return false;
  810. }
  811. f = Math.round(num * Math.pow(10, pos)) / Math.pow(10, pos);
  812. var s = f.toString();
  813. var rs = s.indexOf('.');
  814. if (pos > 0 && rs < 0) {
  815. rs = s.length;
  816. s += '.';
  817. }
  818. while (s.length <= rs + pos) {
  819. s += '0';
  820. }
  821. return s;
  822. }
  823.  
  824. return function(classname, align_right) {
  825. var progress = dcE("div");
  826. progress.className = "pubd-progress" + (classname ? " " + classname : "");
  827. if (align_right) progress.classList.add("pubd-progress-right");
  828.  
  829. progress.scaleNum = 0;
  830.  
  831. var bar = progress.appendChild(dcE("div"));
  832. bar.className = "pubd-progress-bar";
  833.  
  834. var txt = progress.appendChild(dcE("span"));
  835. txt.className = "pubd-progress-text";
  836.  
  837. progress.set = function(scale, pos, str) {
  838. if (!pos) pos = 2;
  839. var percentStr = toDecimal2((scale * 100), pos) + "%";
  840. scale = scale > 1 ? 1 : (scale < 0 ? 0 : scale);
  841. this.scaleNum = scale;
  842. bar.style.width = percentStr;
  843. if (str)
  844. txt.innerHTML = str;
  845. else
  846. txt.innerHTML = percentStr;
  847. }
  848. progress.scale = function() {
  849. return this.scaleNum;
  850. }
  851.  
  852. return progress;
  853. };
  854. })();
  855.  
  856. //创建用户卡片类
  857. var UserCard = (function() {
  858.  
  859. return function(userid) {
  860. var uinfo = dcE("div");
  861. uinfo.userid = userid;
  862. uinfo.className = "pubd-user-info";
  863. var uhead = uinfo.appendChild(dcE("div"));
  864. uhead.className = "pubd-user-info-head";
  865. var uhead_img = uinfo.uhead = uhead.appendChild(dcE("img"));
  866.  
  867. var infos = uinfo.infos = uinfo.appendChild(dcE("dl"));
  868. infos.className = "pubd-user-info-dl";
  869. //ID
  870. var dt = infos.appendChild(dcE("dt"));
  871. dt.className = "pubd-user-info-id-dt";
  872. dt.innerHTML = "ID";
  873. var dd = uinfo.uid = infos.appendChild(dcE("dd"));
  874. dd.className = "pubd-user-info-id-dd";
  875. dd.innerHTML = uinfo.userid;
  876. //作品数
  877. var dt = infos.appendChild(dcE("dt"));
  878. dt.className = "pubd-user-info-illusts-dt";
  879. dt.innerHTML = "作品投稿数";
  880. var dd = uinfo.uillusts = infos.appendChild(dcE("dd"));
  881. dd.className = "pubd-user-info-illusts-dd";
  882. //昵称
  883. var dt = infos.appendChild(dcE("dt"));
  884. dt.className = "pubd-user-info-name-dt";
  885. dt.innerHTML = "昵称";
  886. var dd = uinfo.uname = infos.appendChild(dcE("dd"));
  887. dd.className = "pubd-user-info-name-dd";
  888. //收藏数
  889. var dt = infos.appendChild(dcE("dt"));
  890. dt.className = "pubd-user-info-bookmarks-dt";
  891. dt.innerHTML = "公开收藏数";
  892. var dd = uinfo.ubookmarks = infos.appendChild(dcE("dd"));
  893. dd.className = "pubd-user-info-bookmarks-dd";
  894.  
  895. uinfo.set = function(obj) {
  896. if (obj.id) {
  897. uinfo.userid = obj.id;
  898. uinfo.uid.innerHTML = obj.id;
  899. }
  900. if (obj.head) uinfo.uhead.src = obj.head;
  901. if (obj.name) uinfo.uname.innerHTML = obj.name;
  902. if (obj.illusts >= 0) uinfo.uillusts.innerHTML = obj.illusts;
  903. if (obj.bookmarks >= 0) uinfo.ubookmarks.innerHTML = obj.bookmarks;
  904. }
  905. return uinfo;
  906. };
  907. })();
  908.  
  909. //创建下拉框类
  910. var Select = (function() {
  911. return function(classname, name) {
  912. var select = dcE("select");
  913. select.className = "pubd-select" + (classname ? " " + classname : "");
  914. select.name = name;
  915. select.id = select.name;
  916.  
  917. select.add = function(text, value) {
  918. var opt = new Option(text, value);
  919. this.options.add(opt);
  920. }
  921. select.remove = function(index) {
  922. this.options.remove(index);
  923. }
  924.  
  925. return select;
  926. };
  927. })();
  928.  
  929. //创建Aria2类
  930. var Aria2 = (function() {
  931. var jsonrpc_version = '2.0';
  932.  
  933. function get_auth(url) {
  934. return url.match(/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(?:\/\/)?(?:([^:@]*(?::[^:@]*)?)?@)?/)[1];
  935. };
  936.  
  937. function request(jsonrpc_path, method, params, callback, priority) {
  938. if (callback == undefined) callback = function() { return; }
  939. var auth = get_auth(jsonrpc_path);
  940. jsonrpc_path = jsonrpc_path.replace(/^((?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(\/\/)?(?:(?:[^:@]*(?::[^:@]*)?)?@)?(.*)/, '$1$2$3'); // auth string not allowed in url for firefox
  941.  
  942. var request_obj = {
  943. jsonrpc: jsonrpc_version,
  944. method: method,
  945. id: priority ? "1" : (new Date()).getTime().toString(),
  946. };
  947. if (params) request_obj['params'] = params;
  948. if (auth && auth.indexOf('token:') == 0)
  949. {
  950. if (method == "system.multicall")
  951. { //多项目操作时单独设置token
  952. params.forEach(function(param){
  953. param.forEach(function(method){
  954. method.params.unshift(auth);
  955. })
  956. })
  957. }else
  958. {
  959. params.unshift(auth);
  960. }
  961. }
  962.  
  963. var headers = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }
  964. if (auth && auth.indexOf('token:') != 0) {
  965. headers.Authorization = "Basic " + btoa(auth);
  966. }
  967. GM_xmlhttpRequest({
  968. url: jsonrpc_path + "?tm=" + (new Date()).getTime().toString(),
  969. method: "POST",
  970. responseType: "text",
  971. data: JSON.stringify(request_obj),
  972. headers: headers,
  973. onload: function(response) {
  974. try {
  975. var JSONreq = JSON.parse(response.response);
  976. callback(JSONreq);
  977. } catch (e) {
  978. console.error("Aria2发送信息错误", e, response);
  979. callback(false);
  980. }
  981. },
  982. onerror: function(response) {
  983. console.error(response);
  984. callback(false);
  985. }
  986. })
  987. };
  988.  
  989. return function(jsonrpc_path) {
  990. _this = this;
  991. _this.jsonrpc_path = jsonrpc_path;
  992. _this.addUri = function(uri, options, callback) {
  993. request(_this.jsonrpc_path, 'aria2.addUri', [
  994. [uri, ], options
  995. ], callback);
  996. };
  997. _this.addTorrent = function(base64txt, options, callback) {
  998. request(_this.jsonrpc_path, 'aria2.addTorrent', [base64txt, [], options], callback);
  999. };
  1000. _this.getVersion = function(callback) {
  1001. request(_this.jsonrpc_path, 'aria2.getVersion', [], callback, true);
  1002. };
  1003. _this.getGlobalOption = function(callback) {
  1004. request(_this.jsonrpc_path, 'aria2.getGlobalOption', [], callback, true);
  1005. };
  1006. _this.system = {
  1007. multicall:function(params,callback){
  1008. request(_this.jsonrpc_path, 'system.multicall', params, callback);
  1009. },
  1010. };
  1011. return this;
  1012. }
  1013. })();
  1014.  
  1015. /*
  1016. * 自定义函数区
  1017. */
  1018.  
  1019. //构建开始按钮
  1020. function buildbtnStart(touch) {
  1021. if (touch) //手机版
  1022. {
  1023.  
  1024. } else {
  1025. var btnStart = dcE("a");
  1026. btnStart.id = "pubd-start";
  1027. btnStart.className = "pubd-start";
  1028. //添加图标
  1029. var icon = btnStart.icon = btnStart.appendChild(dcE("i"));
  1030. icon.className = "pubd-icon";
  1031. //添加文字
  1032. var span = btnStart.caption = btnStart.appendChild(dcE("span"));
  1033. span.className = "text";
  1034. span.innerHTML = "使用PUBD扒图";
  1035.  
  1036. //鼠标移入和按下都起作用
  1037. //btnStart.addEventListener("mouseenter",function(){pubd.menu.show()});
  1038. btnStart.addEventListener("click", function() { pubd.menu.classList.toggle("display-none") });
  1039. }
  1040. return btnStart;
  1041. }
  1042.  
  1043. //构建开始菜单
  1044. function buildbtnMenu(touch) {
  1045. if (touch) //手机版
  1046. {
  1047.  
  1048. } else {
  1049. /*
  1050. var menu2 = new pubdMenu(touch);
  1051. menu2.add("子菜单1","",function(){alert("子菜单1")});
  1052. menu2.add("子菜单2","",function(){alert("子菜单2")});
  1053. var menu1 = new pubdMenu(touch);
  1054. menu1.add("子菜单1","",function(){alert("子菜单1")});
  1055. menu1.add("子菜单2","",null,menu2);
  1056. var menu3 = new pubdMenu(touch);
  1057. menu3.add("子菜单1","",function(){alert("子菜单1")});
  1058. menu3.add("子菜单2","",function(){alert("子菜单2")});
  1059. menu3.add("子菜单2","",function(){alert("子菜单3")});
  1060. menu3.add("子菜单2","",function(){alert("子菜单4")});
  1061. var menu4 = new pubdMenu(touch);
  1062. menu4.add("子菜单1","",null,menu3);
  1063. menu4.add("子菜单2","",function(){alert("子菜单2")});
  1064. menu4.add("子菜单2","",function(){alert("子菜单5")});
  1065. menu4.add("子菜单2","",function(){alert("子菜单6")});
  1066. */
  1067. var menu = new pubdMenu(touch, "pubd-menu-main");
  1068. menu.id = "pubd-menu";
  1069. menu.add("下载该画师", "pubd-menu-this-user", function(e) {
  1070. pubd.dialog.downthis.show(
  1071. (dBd.clientWidth - 440)/2,
  1072. window.pageYOffset+100
  1073. );
  1074. menu.hide();
  1075. });
  1076. /*
  1077. menu.add("占位用","",null,menu1);
  1078. menu.add("没功能","",null,menu4);
  1079. menu.add("多个画师下载",null,function()
  1080. {//做成“声音”的设备样子
  1081. alert("这个功能也没有开发")
  1082. }
  1083. );
  1084. */
  1085. /*
  1086. if (typeof(pixiv.context.illustId) != "undefined")
  1087. { //需要子菜单,显示不同的下载方案
  1088. menu.add("下载当前作品","",function()
  1089. {
  1090. pubd.dialog.downthis.show();
  1091. menu.hide();
  1092. }
  1093. );
  1094. }
  1095. if (typeof(pixiv.context.userId) != "undefined")
  1096. {
  1097. menu.add("收藏作者","",function()
  1098. {
  1099.  
  1100. pubd.staruser.push(pixiv.context.userId);
  1101. var starStr = JSON.stringify(pubd.staruser);
  1102. GM_setValue("pubd-staruser",starStr); //下载方案
  1103.  
  1104. menu.hide();
  1105. }
  1106. );
  1107. }
  1108. */
  1109. menu.add(0);
  1110. menu.add("选项", "pubd-menu-setting", function(e) {
  1111. pubd.dialog.config.show(
  1112. (dBd.clientWidth - 400)/2,
  1113. window.pageYOffset+50
  1114. );
  1115. menu.hide();
  1116. });
  1117. }
  1118. return menu;
  1119. }
  1120.  
  1121. //有默认值的获取设置
  1122. function getValueDefault(name, defaultValue) {
  1123. var value = GM_getValue(name);
  1124. if (value != undefined)
  1125. return value;
  1126. else
  1127. return defaultValue;
  1128. }
  1129. //构建设置对话框
  1130. function buildDlgConfig(touch) {
  1131. var dlg = new Dialog("PUBD选项 v" + scriptVersion, "pubd-config", "pubd-config");
  1132. dlg.cptBtns.add("反馈", "dlg-btn-debug", "https://github.com/Mapaler/PixivUserBatchDownload/issues");
  1133. dlg.cptBtns.add("?", "dlg-btn-help", "https://github.com/Mapaler/PixivUserBatchDownload/wiki");
  1134. dlg.token_ani = null; //储存Token进度条动画句柄
  1135. var dlgc = dlg.content;
  1136.  
  1137. var dl = dcE("dl");
  1138. dlgc.appendChild(dl);
  1139. var dt = dcE("dt");
  1140. dl.appendChild(dt);
  1141. //dt.innerHTML = "Pixiv访问权限,默认仅能访问公开作品";
  1142. var dd = dcE("dd");
  1143. dl.appendChild(dd);
  1144.  
  1145. var frm = new Frame("Pixiv访问权限", "pubd-token");
  1146. dd.appendChild(frm);
  1147.  
  1148. var dl_t = dcE("dl");
  1149. frm.content.appendChild(dl_t);
  1150.  
  1151. var dd = dcE("dd");
  1152. dl_t.appendChild(dd);
  1153. var checkbox = new LabelInput("开启登陆功能,解除浏览限制", "pubd-needlogin", "pubd-needlogin", "checkbox", "1", true);
  1154. dlg.needlogin = checkbox.input;
  1155. dlg.needlogin.onclick = function() {
  1156. if (dlg.needlogin.checked) {
  1157. dlg.token_info.classList.remove("height-none");
  1158. dlg.start_token_animate();
  1159. } else {
  1160. dlg.token_info.classList.add("height-none");
  1161. dlg.stop_token_animate();
  1162. }
  1163. pubd.dialog.login.cptBtns.close.click();
  1164. }
  1165. dd.appendChild(checkbox);
  1166.  
  1167. var a_setting = dcE("a");
  1168. a_setting.className = "pubd-browsing-restriction";
  1169. a_setting.href = "http://www.pixiv.net/setting_user.php#over-18";
  1170. a_setting.target = "_blank";
  1171. a_setting.innerHTML = "设置我的账户浏览限制";
  1172. dd.appendChild(a_setting);
  1173. var dd = dcE("dd");
  1174. dl_t.appendChild(dd);
  1175. dd.className = "pubd-token-info height-none";
  1176. dlg.token_info = dd;
  1177. var progress = new Progress("pubd-token-expires", true);
  1178. dlg.token_expires = progress;
  1179. dd.appendChild(progress);
  1180. //开始动画
  1181. dlg.start_token_animate = function() {
  1182. //if (!dlg.classList.contains("display-none"))
  1183. //{
  1184. dlg.stop_token_animate();
  1185. requestAnimationFrame(token_animate);
  1186. dlg.token_ani = setInterval(function() { requestAnimationFrame(token_animate) }, 1000);
  1187. //}
  1188. }
  1189. //停止动画
  1190. dlg.stop_token_animate = function() {
  1191. clearInterval(dlg.token_ani);
  1192. }
  1193. //动画具体实现
  1194. function token_animate() {
  1195. var nowdate = new Date();
  1196. var olddate = new Date(pubd.auth.login_date);
  1197. var expires_in = parseInt(pubd.auth.response.expires_in);
  1198. var differ = expires_in - (nowdate - olddate) / 1000;
  1199. var scale = differ / expires_in;
  1200. if (differ > 0) {
  1201. progress.set(scale, 2, "Token有效剩余" + parseInt(differ) + "秒");
  1202. } else {
  1203. progress.set(0, 2, "Token已失效,请重新登录");
  1204. clearInterval(dlg.token_ani);
  1205. }
  1206. //console.log("Token有效剩余" + differ + "秒"); //检测动画后台是否停止
  1207. }
  1208.  
  1209. var ipt = dcE("input");
  1210. ipt.type = "button";
  1211. ipt.className = "pubd-tologin";
  1212. ipt.value = "账户登陆"
  1213. ipt.onclick = function(e) {
  1214. pubd.dialog.login.show(
  1215. (dBd.clientWidth - 370)/2,
  1216. window.pageYOffset+200
  1217. );
  1218. }
  1219. dd.appendChild(ipt);
  1220.  
  1221. //“通用分析选项”窗口选项
  1222. var dt = dcE("dt");
  1223. dl.appendChild(dt);
  1224. var dd = dcE("dd");
  1225.  
  1226. var frm = new Frame("通用分析选项", "pubd-commonanalyseoptions");
  1227. var chk_getugoiraframe = new LabelInput("获取动图帧数", "pubd-getugoiraframe", "pubd-getugoiraframe", "checkbox", "1", true);
  1228. dlg.getugoiraframe = chk_getugoiraframe.input;
  1229.  
  1230. frm.content.appendChild(chk_getugoiraframe);
  1231. dd.appendChild(frm);
  1232. dl.appendChild(dd);
  1233.  
  1234. //“下载该画师”窗口选项
  1235. var dt = dcE("dt");
  1236. dl.appendChild(dt);
  1237. var dd = dcE("dd");
  1238.  
  1239. var frm = new Frame("“下载该画师”窗口", "pubd-frm-downthis");
  1240. var chk_autoanalyse = new LabelInput("打开窗口时自动获取", "pubd-autoanalyse", "pubd-autoanalyse", "checkbox", "1", true);
  1241. dlg.autoanalyse = chk_autoanalyse.input;
  1242. var chk_autodownload = new LabelInput("获取完成后自动发送", "pubd-autodownload", "pubd-autodownload", "checkbox", "1", true);
  1243. dlg.autodownload = chk_autodownload.input;
  1244.  
  1245. frm.content.appendChild(chk_autoanalyse);
  1246. frm.content.appendChild(chk_autodownload);
  1247. dd.appendChild(frm);
  1248. dl.appendChild(dd);
  1249.  
  1250. //向Aria2的发送模式
  1251. var dt = dl.appendChild(dcE("dt"));
  1252. var dd = dl.appendChild(dcE("dd"));
  1253.  
  1254. var frm = dd.appendChild(new Frame("向Aria2逐项发送模式", "pubd-frm-termwisetype"));
  1255. var radio0 = frm.content.appendChild(new LabelInput("完全逐项(按图片)", "pubd-termwisetype", "pubd-termwisetype", "radio", "0", true));
  1256. var radio1 = frm.content.appendChild(new LabelInput("半逐项(按作品)", "pubd-termwisetype", "pubd-termwisetype", "radio", "1", true));
  1257. var radio2 = frm.content.appendChild(new LabelInput("不逐项(按作者)", "pubd-termwisetype", "pubd-termwisetype", "radio", "2", true));
  1258. dlg.termwiseType = [radio0.input, radio1.input, radio2.input];
  1259.  
  1260. //“发送完成后,点击通知”窗口选项
  1261. var dt = dl.appendChild(dcE("dt"));
  1262. var dd = dl.appendChild(dcE("dd"));
  1263.  
  1264. var frm = dd.appendChild(new Frame("发送完成通知", "pubd-frm-clicknotification"));
  1265. var radio0 = frm.content.appendChild(new LabelInput("点击通知什么也不做", "pubd-clicknotification", "pubd-clicknotification", "radio", "0", true));
  1266. var radio1 = frm.content.appendChild(new LabelInput("点击通知激活该窗口", "pubd-clicknotification", "pubd-clicknotification", "radio", "1", true));
  1267. var radio2 = frm.content.appendChild(new LabelInput("点击通知关闭该窗口", "pubd-clicknotification", "pubd-clicknotification", "radio", "2", true));
  1268. var radio3 = frm.content.appendChild(new LabelInput("通知自动消失关闭该窗口", "pubd-clicknotification", "pubd-clicknotification", "radio", "3", true));
  1269. dlg.noticeType = [radio0.input, radio1.input, radio2.input, radio3.input];
  1270.  
  1271. /*
  1272. //选项卡栏
  1273. var dt=dcE("dt");
  1274. dl.appendChild(dt);
  1275. var dd=dcE("dd");
  1276. dd.className = "pubd-config-tab"
  1277. var tabs = new Tabs();
  1278. tabs.add("第一选项卡");
  1279. tabs.add("第二选项卡");
  1280. dd.appendChild(tabs);
  1281. dl.appendChild(dd);
  1282. */
  1283. //配置方案储存
  1284. dlg.schemes = null;
  1285. dlg.reloadSchemes = function() { //重新读取所有下载方案
  1286. if (dlg.schemes.length < 1) {
  1287. alert("目前本程序没有任何下载方案,需要正常使用请先新建方案。");
  1288. }
  1289. dlg.downScheme.options.length = 0;
  1290. dlg.schemes.forEach(function(item, index) {
  1291. dlg.downScheme.add(item.name, index);
  1292. })
  1293. if (dlg.downScheme.options.length > 0)
  1294. dlg.selectScheme(0);
  1295. }
  1296. dlg.loadScheme = function(scheme) { //读取一个下载方案
  1297. if (scheme == undefined) {
  1298. dlg.rpcurl.value = "";
  1299. dlg.https2http.checked = false;
  1300. dlg.downfilter.value = "";
  1301. dlg.savedir.value = "";
  1302. dlg.savepath.value = "";
  1303. dlg.textout.value = "";
  1304. dlg.loadMasklistFromArray([]);
  1305. } else {
  1306. dlg.rpcurl.value = scheme.rpcurl;
  1307. dlg.https2http.checked = scheme.https2http;
  1308. dlg.downfilter.value = scheme.downfilter;
  1309. dlg.savedir.value = scheme.savedir;
  1310. dlg.savepath.value = scheme.savepath;
  1311. dlg.textout.value = scheme.textout;
  1312. dlg.loadMasklistFromArray(scheme.masklist);
  1313. }
  1314. }
  1315. dlg.addMask = function(name, logic, content, value) { //向掩码列表添加一个新的掩码
  1316. if (value == undefined)
  1317. value = dlg.masklist.options.length;
  1318. var text = name + " : " + logic + " : " + content;
  1319. var opt = new Option(text, value);
  1320. dlg.masklist.options.add(opt);
  1321. }
  1322. dlg.loadMask = function(mask) { //读取一个掩码到三个文本框,只是用来查看
  1323. dlg.mask_name.value = mask.name;
  1324. dlg.mask_logic.value = mask.logic;
  1325. dlg.mask_content.value = mask.content;
  1326. }
  1327. dlg.loadMasklistFromArray = function(masklist) { //从掩码数组重置掩码列表
  1328. dlg.masklist.length = 0;
  1329. masklist.forEach(function(item, index) {
  1330. dlg.addMask(item.name, item.logic, item.content, index);
  1331. })
  1332. }
  1333. //选择一个方案,同时读取设置
  1334. dlg.selectScheme = function(index) {
  1335. if (index == undefined) index = 0;
  1336. if (dlg.downScheme.options.length < 1 || dlg.downScheme.selectedOptions.length < 1) { return; }
  1337. var scheme = dlg.schemes[index];
  1338. dlg.loadScheme(scheme);
  1339. dlg.downScheme.selectedIndex = index;
  1340. }
  1341. //选择一个掩码,同时读取设置
  1342. dlg.selectMask = function(index) {
  1343. if (dlg.downScheme.options.length < 1 || dlg.downScheme.selectedOptions.length < 1) { return; }
  1344. if (dlg.masklist.options.length < 1 || dlg.masklist.selectedOptions.length < 1) { return; }
  1345. var scheme = dlg.schemes[dlg.downScheme.selectedIndex];
  1346. var mask = scheme.masklist[index];
  1347. dlg.loadMask(mask);
  1348. dlg.masklist.selectedIndex = index;
  1349. }
  1350.  
  1351. //配置方案选择
  1352. var dt = dcE("dt");
  1353. dt.innerHTML = "默认下载方案";
  1354. dl.appendChild(dt);
  1355. var dd = dcE("dd");
  1356. var slt = new Select("pubd-downscheme");
  1357. slt.onchange = function() {
  1358. dlg.selectScheme(this.selectedIndex);
  1359. };
  1360. dlg.downScheme = slt;
  1361. dd.appendChild(slt);
  1362.  
  1363. var ipt = dcE("input");
  1364. ipt.type = "button";
  1365. ipt.className = "pubd-downscheme-new";
  1366. ipt.value = "新建"
  1367. ipt.onclick = function() {
  1368. var schemName = prompt("请输入方案名", "我的方案");
  1369. if (schemName)
  1370. {
  1371. var scheme = new DownScheme(schemName);
  1372. var length = dlg.schemes.push(scheme);
  1373. dlg.downScheme.add(scheme.name, length - 1);
  1374. dlg.downScheme.selectedIndex = length - 1;
  1375. dlg.loadScheme(scheme);
  1376. //dlg.reloadSchemes();
  1377. }
  1378. }
  1379. dd.appendChild(ipt);
  1380.  
  1381. var ipt = dcE("input");
  1382. ipt.type = "button";
  1383. ipt.className = "pubd-downscheme-remove";
  1384. ipt.value = "删除"
  1385. ipt.onclick = function() {
  1386. if (dlg.downScheme.options.length < 1) { alert("已经没有方案了"); return; }
  1387. if (dlg.downScheme.selectedOptions.length < 1) { alert("没有选中方案"); return; }
  1388. var index = dlg.downScheme.selectedIndex;
  1389. dlg.schemes.splice(index, 1);
  1390. dlg.downScheme.remove(index);
  1391. var index = dlg.downScheme.selectedIndex;
  1392. if (index < 0) dlg.reloadSchemes(); //没有选中的,重置
  1393. else dlg.loadScheme(dlg.schemes[index]);
  1394. }
  1395. dd.appendChild(ipt);
  1396. dl.appendChild(dd);
  1397.  
  1398. //配置方案详情设置
  1399. var dt = dcE("dt");
  1400. dl.appendChild(dt);
  1401. var dd = dcE("dd");
  1402. dd.className = "pubd-selectscheme-bar";
  1403.  
  1404. var frm = new Frame("当前方案设置", "pubd-selectscheme");
  1405.  
  1406. var dl_ss = dcE("dl");
  1407.  
  1408. frm.content.appendChild(dl_ss);
  1409. dd.appendChild(frm);
  1410. dl.appendChild(dd);
  1411.  
  1412. //Aria2 URL
  1413.  
  1414. var dt = dcE("dt");
  1415. dl_ss.appendChild(dt);
  1416. dt.innerHTML = "Aria2 JSON-RPC 路径";
  1417. var rpcchk = dcE("span"); //显示检查状态用
  1418. rpcchk.className = "pubd-rpcchk-info";
  1419. dlg.rpcchk = rpcchk;
  1420. dlg.rpcchk.runing = false;
  1421. dt.appendChild(rpcchk);
  1422. var dd = dcE("dd");
  1423. var rpcurl = dcE("input");
  1424. rpcurl.type = "url";
  1425. rpcurl.className = "pubd-rpcurl";
  1426. rpcurl.name = "pubd-rpcurl";
  1427. rpcurl.id = rpcurl.name;
  1428. rpcurl.placeholder = "Aria2的信息接收路径"
  1429. rpcurl.onchange = function() {
  1430. dlg.rpcchk.innerHTML = "";
  1431. dlg.rpcchk.runing = false;
  1432. if (dlg.downScheme.selectedOptions.length < 1) { return; }
  1433. var schemeIndex = dlg.downScheme.selectedIndex;
  1434. dlg.schemes[schemeIndex].rpcurl = rpcurl.value;
  1435. }
  1436. dlg.rpcurl = rpcurl;
  1437. dd.appendChild(rpcurl);
  1438.  
  1439. var ipt = dcE("input");
  1440. ipt.type = "button";
  1441. ipt.className = "pubd-rpcchk";
  1442. ipt.value = "检查路径"
  1443. ipt.onclick = function() {
  1444. if (dlg.rpcchk.runing) return;
  1445. if (dlg.rpcurl.value.length < 1) {
  1446. dlg.rpcchk.innerHTML = "路径为空";
  1447. return;
  1448. }
  1449. dlg.rpcchk.innerHTML = "正在连接...";
  1450. dlg.rpcchk.runing = true;
  1451. var aria2 = new Aria2(dlg.rpcurl.value);
  1452. aria2.getVersion(function(rejo) {
  1453. if (rejo)
  1454. dlg.rpcchk.innerHTML = "发现Aria2 ver" + rejo.result.version;
  1455. else
  1456. dlg.rpcchk.innerHTML = "Aria2连接失败";
  1457. dlg.rpcchk.runing = false;
  1458. });
  1459. }
  1460. dd.appendChild(ipt);
  1461. dl_ss.appendChild(dd);
  1462.  
  1463. //额外设置,https转http
  1464. var dt = dcE("dt");
  1465. dl_ss.appendChild(dt);
  1466. var dd = dcE("dd");
  1467. var chk_https2http = new LabelInput("图片网址https转http", "pubd-https2http", "pubd-https2http", "checkbox", "1", true, "某些Linux没有正确安装新版OpenSSL,https的图片链接会下载失败。");
  1468. dlg.https2http = chk_https2http.input;
  1469. dlg.https2http.onchange = function() {
  1470. if (dlg.downScheme.selectedOptions.length < 1) { return; }
  1471. var schemeIndex = dlg.downScheme.selectedIndex;
  1472. dlg.schemes[schemeIndex].https2http = this.checked;
  1473. }
  1474. dd.appendChild(chk_https2http);
  1475. dl_ss.appendChild(dd);
  1476.  
  1477. //下载过滤
  1478. var dt = dl_ss.appendChild(dcE("dt"));
  1479. dt.innerHTML = "下载过滤器";
  1480. var dta = dt.appendChild(dcE("a"));
  1481. dta.className = "pubd-help-link";
  1482. dta.innerHTML = "(?)";
  1483. dta.href = "https://github.com/Mapaler/PixivUserBatchDownload/wiki/%E4%B8%8B%E8%BD%BD%E8%BF%87%E6%BB%A4%E5%99%A8";
  1484. dta.target = "_blank";
  1485. var dd = dcE("dd");
  1486. var downfilter = dcE("input");
  1487. downfilter.type = "text";
  1488. downfilter.className = "pubd-downfilter";
  1489. downfilter.name = "pubd-downfilter";
  1490. downfilter.id = downfilter.name;
  1491. downfilter.placeholder = "符合条件的图片将不会被发送到Aria2"
  1492. downfilter.onchange = function() {
  1493. if (dlg.downScheme.selectedOptions.length < 1) { return; }
  1494. var schemeIndex = dlg.downScheme.selectedIndex;
  1495. dlg.schemes[schemeIndex].downfilter = downfilter.value;
  1496. }
  1497. dlg.downfilter = downfilter;
  1498. dd.appendChild(downfilter);
  1499. dl_ss.appendChild(dd);
  1500.  
  1501. //下载目录
  1502. var dt = dcE("dt");
  1503. dl_ss.appendChild(dt);
  1504. dt.innerHTML = "下载目录";
  1505. var dd = dcE("dd");
  1506. var savedir = dcE("input");
  1507. savedir.type = "text";
  1508. savedir.className = "pubd-savedir";
  1509. savedir.name = "pubd-savedir";
  1510. savedir.id = savedir.name;
  1511. savedir.placeholder = "文件下载到的目录"
  1512. savedir.onchange = function() {
  1513. if (dlg.downScheme.selectedOptions.length < 1) { return; }
  1514. var schemeIndex = dlg.downScheme.selectedIndex;
  1515. dlg.schemes[schemeIndex].savedir = savedir.value;
  1516. }
  1517. dlg.savedir = savedir;
  1518. dd.appendChild(savedir);
  1519. dl_ss.appendChild(dd);
  1520.  
  1521. //保存路径
  1522. var dt = dl_ss.appendChild(dcE("dt"));
  1523. dt.innerHTML = "保存路径";
  1524. var dta = dt.appendChild(dcE("a"));
  1525. dta.className = "pubd-help-link";
  1526. dta.innerHTML = "(?)";
  1527. dta.href = "https://github.com/Mapaler/PixivUserBatchDownload/wiki/%E6%8E%A9%E7%A0%81";
  1528. dta.target = "_blank";
  1529. var dd = dcE("dd");
  1530. var savepath = dcE("input");
  1531. savepath.type = "text";
  1532. savepath.className = "pubd-savepath";
  1533. savepath.name = "pubd-savepath";
  1534. savepath.id = savepath.name;
  1535. savepath.placeholder = "分组保存的文件夹和文件名"
  1536. savepath.onchange = function() {
  1537. if (dlg.downScheme.selectedOptions.length < 1) { return; }
  1538. var schemeIndex = dlg.downScheme.selectedIndex;
  1539. dlg.schemes[schemeIndex].savepath = savepath.value;
  1540. }
  1541. dlg.savepath = savepath;
  1542. dd.appendChild(savepath);
  1543. dl_ss.appendChild(dd);
  1544.  
  1545. //输出文本
  1546. var dt = dl_ss.appendChild(dcE("dt"));
  1547. dt.innerHTML = "文本输出模式格式";
  1548. var dta = dt.appendChild(dcE("a"));
  1549. dta.className = "pubd-help-link";
  1550. dta.innerHTML = "(?)";
  1551. dta.href = "https://github.com/Mapaler/PixivUserBatchDownload/wiki/%e9%80%89%e9%a1%b9%e7%aa%97%e5%8f%a3#%E6%96%87%E6%9C%AC%E8%BE%93%E5%87%BA%E6%A8%A1%E5%BC%8F%E6%A0%BC%E5%BC%8F";
  1552. dta.target = "_blank";
  1553. var dd = dcE("dd");
  1554. dd.className = "pubd-textout-bar";
  1555. var textout = dcE("textarea");
  1556. textout.className = "pubd-textout";
  1557. textout.name = "pubd-textout";
  1558. textout.id = textout.name;
  1559. textout.placeholder = "直接输出文本信息时的格式"
  1560. textout.wrap = "off";
  1561. textout.onchange = function() {
  1562. if (dlg.downScheme.selectedOptions.length < 1) { return; }
  1563. var schemeIndex = dlg.downScheme.selectedIndex;
  1564. dlg.schemes[schemeIndex].textout = textout.value;
  1565. }
  1566. dlg.textout = textout;
  1567. dd.appendChild(textout);
  1568. dl_ss.appendChild(dd);
  1569.  
  1570.  
  1571. //自定义掩码
  1572. var dt = dl_ss.appendChild(dcE("dt"));
  1573. dt.innerHTML = "自定义掩码";
  1574. var dta = dt.appendChild(dcE("a"));
  1575. dta.className = "pubd-help-link";
  1576. dta.innerHTML = "(?)";
  1577. dta.href = "https://github.com/Mapaler/PixivUserBatchDownload/wiki/%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A9%E7%A0%81";
  1578. dta.target = "_blank";
  1579. var dd = dcE("dd");
  1580. dl_ss.appendChild(dd);
  1581. //▼掩码名
  1582. var ipt = dcE("input");
  1583. ipt.type = "text";
  1584. ipt.className = "pubd-mask-name";
  1585. ipt.name = "pubd-mask-name";
  1586. ipt.id = ipt.name;
  1587. ipt.placeholder = "自定义掩码名";
  1588. dlg.mask_name = ipt;
  1589. dd.appendChild(ipt);
  1590. //▲掩码名
  1591. //▼执行条件
  1592. var ipt = dcE("input");
  1593. ipt.type = "text";
  1594. ipt.className = "pubd-mask-logic";
  1595. ipt.name = "pubd-mask-logic";
  1596. ipt.id = ipt.name;
  1597. ipt.placeholder = "执行条件";
  1598. dlg.mask_logic = ipt;
  1599. dd.appendChild(ipt);
  1600. //▲执行条件
  1601. var ipt = dcE("input");
  1602. ipt.type = "button";
  1603. ipt.className = "pubd-mask-add";
  1604. ipt.value = "+";
  1605. ipt.onclick = function() { //增加自定义掩码
  1606. if (dlg.downScheme.selectedOptions.length < 1) { alert("没有选中下载方案"); return; }
  1607. if (dlg.mask_name.value.length < 1) { alert("掩码名称为空"); return; }
  1608. if (dlg.mask_logic.value.length < 1) { alert("执行条件为空"); return; }
  1609. if (dlg.mask_content.value.indexOf("%{" + dlg.mask_logic.value + "}")>=0) { alert("该掩码调用自身,会形成死循环。"); return; }
  1610. var schemeIndex = dlg.downScheme.selectedIndex;
  1611. dlg.schemes[schemeIndex].mask.add(dlg.mask_name.value, dlg.mask_logic.value, dlg.mask_content.value);
  1612. dlg.addMask(dlg.mask_name.value, dlg.mask_logic.value, dlg.mask_content.value);
  1613. dlg.mask_name.value = dlg.mask_logic.value = dlg.mask_content.value = "";
  1614. }
  1615. dd.appendChild(ipt);
  1616. var mask_remove = dcE("input");
  1617. mask_remove.type = "button";
  1618. mask_remove.className = "pubd-mask-remove";
  1619. mask_remove.value = "-";
  1620. mask_remove.onclick = function() { //删除自定义掩码
  1621. if (dlg.downScheme.selectedOptions.length < 1) { alert("没有选中下载方案"); return; }
  1622. if (dlg.masklist.options.length < 1) { alert("已经没有掩码了"); return; }
  1623. if (dlg.masklist.selectedOptions.length < 1) { alert("没有选中掩码"); return; }
  1624. var schemeIndex = dlg.downScheme.selectedIndex;
  1625. var maskIndex = dlg.masklist.selectedIndex;
  1626. dlg.schemes[schemeIndex].mask.remove(maskIndex);
  1627. dlg.masklist.remove(maskIndex);
  1628. for (var mi = maskIndex; mi < dlg.masklist.options.length; mi++) {
  1629. dlg.masklist.options[mi].value = mi;
  1630. }
  1631. }
  1632. dd.appendChild(mask_remove);
  1633.  
  1634. //▼掩码内容
  1635. var ipt = dcE("input");
  1636. ipt.type = "text";
  1637. ipt.className = "pubd-mask-content";
  1638. ipt.name = "pubd-mask-content";
  1639. ipt.id = ipt.name;
  1640. ipt.placeholder = "掩码内容";
  1641. dlg.mask_content = ipt;
  1642. dd.appendChild(ipt);
  1643. //▲掩码内容
  1644. dl_ss.appendChild(dd);
  1645.  
  1646. //▼掩码列表
  1647. var dd = dcE("dd");
  1648. dd.className = "pubd-mask-list-bar";
  1649. var masklist = new Select("pubd-mask-list", "pubd-mask-list")
  1650. masklist.size = 5;
  1651. masklist.onchange = function() { //读取选中的掩码
  1652. dlg.selectMask(this.selectedIndex);
  1653. }
  1654. dlg.masklist = masklist;
  1655. dd.appendChild(masklist);
  1656. //▲掩码列表
  1657. dl_ss.appendChild(dd);
  1658.  
  1659. //保存按钮栏
  1660. var dt = dcE("dt");
  1661. dl.appendChild(dt);
  1662. var dd = dcE("dd");
  1663. dd.className = "pubd-config-savebar"
  1664. var ipt = dcE("input");
  1665. ipt.type = "button";
  1666. ipt.className = "pubd-reset";
  1667. ipt.value = "清空选项"
  1668. ipt.onclick = function() {
  1669. if (confirm("您确定要将PUBD保存的所有设置,以及方案全部删除吗?\n(⚠️不可恢复)")==true){
  1670. dlg.reset();
  1671. return true;
  1672. }else{
  1673. return false;
  1674. }
  1675. }
  1676. dd.appendChild(ipt);
  1677. var ipt = dcE("input");
  1678. ipt.type = "button";
  1679. ipt.className = "pubd-save";
  1680. ipt.value = "保存选项"
  1681. ipt.onclick = function() {
  1682. dlg.save();
  1683. }
  1684. dd.appendChild(ipt);
  1685. dl.appendChild(dd);
  1686.  
  1687. //保存设置函数
  1688. dlg.save = function() {
  1689. pubd.auth.needlogin = dlg.needlogin.checked;
  1690. pubd.auth.save();
  1691.  
  1692. //作品发送完成后,如何处理通知
  1693. var noticeType = 0;
  1694. dlg.noticeType.some(function(item){
  1695. if (item.checked) noticeType = item.value;
  1696. return item.checked;
  1697. });
  1698. //逐项发送模式
  1699. var termwiseType = 2;
  1700. dlg.termwiseType.some(function(item){
  1701. if (item.checked) termwiseType = item.value;
  1702. return item.checked;
  1703. });
  1704.  
  1705. GM_setValue("pubd-getugoiraframe", dlg.getugoiraframe.checked); //获取动图帧数
  1706. GM_setValue("pubd-autoanalyse", dlg.autoanalyse.checked); //自动分析
  1707. GM_setValue("pubd-autodownload", dlg.autodownload.checked); //自动下载
  1708. GM_setValue("pubd-noticeType", noticeType); //处理通知
  1709. GM_setValue("pubd-termwiseType", termwiseType); //逐项发送
  1710. GM_setValue("pubd-downschemes", JSON.stringify(dlg.schemes)); //下载方案
  1711. GM_setValue("pubd-defaultscheme", dlg.downScheme.selectedIndex); //默认方案
  1712. GM_setValue("pubd-configversion", pubd.configVersion); //设置版本
  1713.  
  1714. GM_notification({text:"设置已保存", title:scriptName, image:scriptIcon});
  1715. pubd.downSchemes = NewDownSchemeArrayFromJson(dlg.schemes);
  1716. pubd.dialog.downthis.reloadSchemes();
  1717. }
  1718. //重置设置函数
  1719. dlg.reset = function() {
  1720. GM_deleteValue("pubd-auth"); //登陆相关信息
  1721. GM_deleteValue("pubd-getugoiraframe"); //获取动图帧数
  1722. GM_deleteValue("pubd-autoanalyse"); //自动分析
  1723. GM_deleteValue("pubd-autodownload"); //自动下载
  1724. GM_deleteValue("pubd-noticeType"); //处理通知
  1725. GM_deleteValue("pubd-termwiseType"); //逐项发送
  1726. GM_deleteValue("pubd-downschemes"); //下载方案
  1727. GM_deleteValue("pubd-defaultscheme"); //默认方案
  1728. GM_deleteValue("pubd-configversion"); //设置版本
  1729. GM_notification({text:"已清空重置设置", title:scriptName, image:scriptIcon});
  1730. }
  1731. //窗口关闭
  1732. dlg.close = function() {
  1733. dlg.stop_token_animate();
  1734. };
  1735. //关闭窗口按钮
  1736. dlg.cptBtns.close.addEventListener("click", dlg.close);
  1737. //窗口初始化
  1738. dlg.initialise = function() {
  1739. dlg.needlogin.checked = pubd.auth.needlogin;
  1740. if (pubd.auth.needlogin) //如果要登陆,就显示Token区域,和动画
  1741. {
  1742. dlg.token_info.classList.remove("height-none");
  1743. dlg.start_token_animate();
  1744. } else {
  1745. dlg.token_info.classList.add("height-none");
  1746. }
  1747.  
  1748. dlg.getugoiraframe.checked = getValueDefault("pubd-getugoiraframe", true);
  1749. dlg.autoanalyse.checked = getValueDefault("pubd-autoanalyse", false);
  1750. dlg.autodownload.checked = getValueDefault("pubd-autodownload", false);
  1751. (dlg.noticeType[parseInt(getValueDefault("pubd-noticeType", 0))] || dlg.noticeType[0]).checked = true;
  1752. (dlg.termwiseType[parseInt(getValueDefault("pubd-termwiseType", 2))] || dlg.termwiseType[2]).checked = true;
  1753.  
  1754. //pubd.downSchemes = NewDownSchemeArrayFromJson(getValueDefault("pubd-downschemes",0)); //重新读取下载方案(可能被其他页面修改的)
  1755. dlg.schemes = NewDownSchemeArrayFromJson(pubd.downSchemes);
  1756. dlg.reloadSchemes();
  1757. dlg.selectScheme(getValueDefault("pubd-defaultscheme", 0));
  1758. //ipt_token.value = pubd.auth.response.access_token;
  1759. };
  1760. return dlg;
  1761. }
  1762.  
  1763. //重新登陆
  1764. function reLogin(onload_suceess_Cb)
  1765. {
  1766. var dlgLogin = pubd.dialog.login;
  1767. if (pubd.auth.save_account) {
  1768. dlgLogin.show((dBd.clientWidth - 370)/2, window.pageYOffset+200);
  1769. dlgLogin.error.replace("正在自动登陆");
  1770.  
  1771. pubd.auth.login(
  1772. function(jore) { //onload_suceess_Cb
  1773. dlgLogin.error.replace("登录成功");
  1774. //pubd.dialog.config.start_token_animate();
  1775. dlgLogin.cptBtns.close.click();
  1776.  
  1777. //如果设置窗口运行着的话还启动动画
  1778. if (!pubd.dialog.config.classList.contains("display-none"))
  1779. pubd.dialog.config.start_token_animate();
  1780. //调用成功后函数
  1781. onload_suceess_Cb(jore);
  1782. },
  1783. function(jore) { //onload_haserror_Cb //返回错误消息
  1784. dlgLogin.error.replace(["错误代码:" + jore.errors.system.code, jore.errors.system.message]);
  1785. },
  1786. function(re) { //onload_notjson_Cb //返回不是JSON
  1787. dlgLogin.error.replace("返回不是JSON,或程序异常");
  1788. },
  1789. function(re) { //onerror_Cb //AJAX发送失败
  1790. dlgLogin.error.replace("AJAX发送失败");
  1791. }
  1792. );
  1793. }else
  1794. {
  1795. dlgLogin.error.replace("请手动登陆后重新执行");
  1796. }
  1797. }
  1798.  
  1799. //构建登陆对话框
  1800. function buildDlgLogin(touch) {
  1801. var dlg = new Dialog("登陆账户", "pubd-login", "pubd-login");
  1802.  
  1803. var dlgc = dlg.content;
  1804. //Logo部分
  1805. var logo_box = dcE("div");
  1806. logo_box.className = "logo-box";
  1807. var logo = dcE("div");
  1808. logo.className = "logo";
  1809. logo_box.appendChild(logo);
  1810. var catchphrase = dcE("div");
  1811. catchphrase.className = "catchphrase";
  1812. catchphrase.innerHTML = "登陆获取你的账户通行证,解除年龄限制";
  1813. logo_box.appendChild(catchphrase);
  1814. dlgc.appendChild(logo_box);
  1815. //实际登陆部分
  1816. var container_login = dcE("div");
  1817. container_login.className = "container-login";
  1818.  
  1819. var input_field_group = dcE("div");
  1820. input_field_group.className = "input-field-group";
  1821. container_login.appendChild(input_field_group);
  1822. var input_field1 = dcE("div");
  1823. input_field1.className = "input-field";
  1824. var pid = dcE("input");
  1825. pid.type = "text";
  1826. pid.className = "pubd-account";
  1827. pid.name = "pubd-account";
  1828. pid.id = pid.name;
  1829. pid.placeholder = "邮箱地址/pixiv ID";
  1830. dlg.pid = pid;
  1831. input_field1.appendChild(pid);
  1832. input_field_group.appendChild(input_field1);
  1833. var input_field2 = dcE("div");
  1834. input_field2.className = "input-field";
  1835. var pass = dcE("input");
  1836. pass.type = "password";
  1837. pass.className = "pubd-password";
  1838. pass.name = "pubd-password";
  1839. pass.id = pass.name;
  1840. pass.placeholder = "密码";
  1841. dlg.pass = pass;
  1842. input_field2.appendChild(pass);
  1843. input_field_group.appendChild(input_field2);
  1844.  
  1845. var error_msg_list = dcE("ul"); //登陆错误信息
  1846. error_msg_list.className = "error-msg-list";
  1847. container_login.appendChild(error_msg_list);
  1848.  
  1849. var submit = dcE("button");
  1850. submit.className = "submit";
  1851. submit.innerHTML = "登陆";
  1852. container_login.appendChild(submit);
  1853.  
  1854. var signup_form_nav = dcE("div");
  1855. signup_form_nav.className = "signup-form-nav";
  1856. container_login.appendChild(signup_form_nav);
  1857. var checkbox = new LabelInput("记住账号密码(警告:明文保存于本地)", "pubd-remember", "pubd-remember", "checkbox", "1", true);
  1858. dlg.remember = checkbox.input;
  1859. signup_form_nav.appendChild(checkbox);
  1860. dlgc.appendChild(container_login);
  1861.  
  1862. submit.onclick = function() {
  1863. dlg.error.replace("登陆中···");
  1864.  
  1865. pubd.auth.newAccount(pid.value, pass.value, dlg.remember.checked);
  1866.  
  1867. pubd.auth.login(
  1868. function(jore) { //onload_suceess_Cb
  1869. dlg.error.replace("登陆成功");
  1870. pubd.dialog.config.start_token_animate();
  1871. },
  1872. function(jore) { //onload_haserror_Cb //返回错误消息
  1873. dlg.error.replace(["错误代码:" + jore.errors.system.code, jore.errors.system.message]);
  1874. },
  1875. function(re) { //onload_notjson_Cb //返回不是JSON
  1876. dlg.error.replace("返回不是JSON,或程序异常");
  1877. },
  1878. function(re) { //onerror_Cb //AJAX发送失败
  1879. dlg.error.replace("AJAX发送失败");
  1880. }
  1881. );
  1882. }
  1883. //添加错误功能
  1884. error_msg_list.clear = function() {
  1885. this.innerHTML = ""; //清空当前信息
  1886. }
  1887. error_msg_list.add = function(text) {
  1888. var error_msg_list_item = dcE("li");
  1889. error_msg_list_item.className = "error-msg-list-item";
  1890. error_msg_list_item.innerHTML = text;
  1891. this.appendChild(error_msg_list_item);
  1892. }
  1893. error_msg_list.adds = function(arr) {
  1894. arr.forEach(
  1895. function(item) {
  1896. error_msg_list.add(item);
  1897. }
  1898. )
  1899. }
  1900. error_msg_list.replace = function(text) {
  1901. this.clear();
  1902. if (typeof(text) == "object") //数组
  1903. this.adds(text);
  1904. else //单文本
  1905. this.add(text);
  1906. }
  1907. dlg.error = error_msg_list;
  1908. //窗口关闭
  1909. dlg.close = function() {
  1910. pubd.auth.newAccount(pid.value, pass.value, dlg.remember.checked);
  1911. pubd.auth.save();
  1912. };
  1913. //关闭窗口按钮
  1914. dlg.cptBtns.close.addEventListener("click", dlg.close);
  1915. //窗口初始化
  1916. dlg.initialise = function() {
  1917. dlg.remember.checked = pubd.auth.save_account;
  1918. pid.value = pubd.auth.username || "";
  1919. pass.value = pubd.auth.password || "";
  1920. error_msg_list.clear();
  1921. };
  1922. return dlg;
  1923. }
  1924.  
  1925.  
  1926. //构建当前画师下载对话框
  1927. function buildDlgDownThis(touch, userid) {
  1928. var dlg = new Dialog("下载当前画师", "pubd-downthis", "pubd-downthis");
  1929. dlg.user = new UserInfo();
  1930. dlg.works = null; //当前处理对象
  1931.  
  1932. var dlgc = dlg.content;
  1933.  
  1934. var dl = dcE("dl");
  1935. dlgc.appendChild(dl);
  1936.  
  1937. var dt = dcE("dt");
  1938. dl.appendChild(dt);
  1939. dt.innerHTML = ""; //用户头像等信息
  1940. var dd = dcE("dd");
  1941.  
  1942. var uinfo = new UserCard(userid ? userid : thisPageUserid); //创建当前用户信息卡
  1943.  
  1944. dlg.uinfo = uinfo;
  1945. dd.appendChild(uinfo);
  1946. dl.appendChild(dd);
  1947.  
  1948. var dt = dcE("dt");
  1949. dl.appendChild(dt);
  1950. dt.innerHTML = "";
  1951. var dd = dcE("dd");
  1952.  
  1953. var frm = new Frame("下载内容");
  1954. var radio1 = new LabelInput("他的作品", "pubd-down-content", "pubd-down-content", "radio", "0", true);
  1955. var radio2 = new LabelInput("他的收藏", "pubd-down-content", "pubd-down-content", "radio", "1", true);
  1956. dlg.dcType = [radio1.input, radio2.input];
  1957. radio1.input.onclick = function() { reAnalyse(this) };
  1958. radio2.input.onclick = function() { reAnalyse(this) };
  1959.  
  1960. function reAnalyse(radio) {
  1961. if (radio.checked == true) {
  1962. if (radio.value == 0)
  1963. dlg.user.bookmarks.break = true; //radio值为0,使收藏中断
  1964. else
  1965. dlg.user.illusts.break = true; //radio值为1,使作品中断
  1966.  
  1967. dlg.analyse(radio.value, dlg.uinfo.userid);
  1968. }
  1969. }
  1970. frm.content.appendChild(radio1);
  1971. frm.content.appendChild(radio2);
  1972.  
  1973. dd.appendChild(frm);
  1974. dl.appendChild(dd);
  1975.  
  1976. var dt = dcE("dt");
  1977. dl.appendChild(dt);
  1978. dt.innerHTML = "信息获取进度";
  1979. var dd = dcE("dd");
  1980. var progress = new Progress("pubd-downthis-progress");
  1981. dlg.progress = progress;
  1982. dd.appendChild(progress);
  1983. dl.appendChild(dd);
  1984.  
  1985. var dt = dcE("dt");
  1986. dl.appendChild(dt);
  1987. dt.innerHTML = "进程日志";
  1988.  
  1989. var btnBreak = dcE("input");
  1990. btnBreak.type = "button";
  1991. btnBreak.className = "pubd-breakdown";
  1992. btnBreak.value = "中断操作";
  1993. btnBreak.onclick = function() {
  1994. dlg.user.illusts.break = true; //使作品中断
  1995. dlg.user.bookmarks.break = true; //使收藏中断
  1996. pubd.downbreak = true; //使下载中断
  1997. }
  1998. dt.appendChild(btnBreak);
  1999. var dd = dcE("dd");
  2000. var ipt = dcE("textarea");
  2001. ipt.readOnly = true;
  2002. ipt.className = "pubd-downthis-log";
  2003. ipt.wrap = "off";
  2004. dlg.logTextarea = ipt;
  2005. dd.appendChild(ipt);
  2006. dl.appendChild(dd);
  2007.  
  2008. //下载方案
  2009. dlg.schemes = null;
  2010.  
  2011. dlg.reloadSchemes = function() { //重新读取所有下载方案
  2012. dlg.schemes = pubd.downSchemes;
  2013.  
  2014. dlg.downScheme.options.length = 0;
  2015. dlg.schemes.forEach(function(item, index) {
  2016. dlg.downScheme.add(item.name, index);
  2017. })
  2018. if (getValueDefault("pubd-defaultscheme",0) >= 0)
  2019. dlg.selectScheme(getValueDefault("pubd-defaultscheme",0));
  2020. else if (dlg.downScheme.options.length > 0)
  2021. dlg.selectScheme(0);
  2022. }
  2023.  
  2024. //选择一个方案,同时读取设置
  2025. dlg.selectScheme = function(index) {
  2026. if (index == undefined) index = 0;
  2027. if (dlg.downScheme.options.length < 1 || dlg.downScheme.selectedOptions.length < 1) { return; }
  2028. dlg.downScheme.selectedIndex = index;
  2029. }
  2030.  
  2031. var dt = dcE("dt");
  2032. dl.appendChild(dt);
  2033. dt.innerHTML = "选择下载方案";
  2034. var dd = dcE("dd");
  2035. var slt = new Select("pubd-downscheme");
  2036. dlg.downScheme = slt;
  2037. dd.appendChild(slt);
  2038. dl.appendChild(dd);
  2039.  
  2040. //下载按钮栏
  2041. var dt = dcE("dt");
  2042. dl.appendChild(dt);
  2043. var dd = dcE("dd");
  2044. dd.className = "pubd-downthis-downbar"
  2045.  
  2046. var textdown = dcE("input");
  2047. textdown.type = "button";
  2048. textdown.className = "pubd-textdown";
  2049. textdown.value = "输出\n文本";
  2050. textdown.onclick = function() {
  2051. dlg.textdownload();
  2052. }
  2053. textdown.disabled = true;
  2054. dlg.textdown = textdown;
  2055. dd.appendChild(textdown);
  2056.  
  2057. var startdown = dcE("input");
  2058. startdown.type = "button";
  2059. startdown.className = "pubd-startdown";
  2060. startdown.value = "发送到Aria2";
  2061. startdown.onclick = function() {
  2062. dlg.startdownload();
  2063. }
  2064. startdown.disabled = true;
  2065. dlg.startdown = startdown;
  2066. dd.appendChild(startdown);
  2067. dl.appendChild(dd);
  2068.  
  2069. //文本输出栏
  2070. var dt = dcE("dt");
  2071. dl.appendChild(dt);
  2072. var dd = dcE("dd");
  2073. dd.className = "pubd-downthis-textout-bar"
  2074. dl.appendChild(dd);
  2075.  
  2076. var ipt = dcE("textarea");
  2077. ipt.readOnly = true;
  2078. ipt.className = "pubd-downthis-textout display-none";
  2079. ipt.wrap = "off";
  2080. dlg.textoutTextarea = ipt;
  2081. dd.appendChild(ipt);
  2082.  
  2083. //显示日志相关
  2084. dlg.logArr = []; //用于储存一行一行的日志信息。
  2085. dlg.logClear = function() {
  2086. dlg.logArr.length = 0;
  2087. this.logTextarea.value = "";
  2088. };
  2089. dlg.log = function(text) {
  2090. dlg.logArr.push(text);
  2091. this.logTextarea.value = this.logArr.join("\n");
  2092. this.logTextarea.scrollTop = this.logTextarea.scrollHeight;
  2093. };
  2094.  
  2095. function xhrGenneral(url, onload_suceess_Cb, onload_hasError_Cb, onload_notJson_Cb, onerror_Cb) {
  2096. var headersObj = new HeadersObject();
  2097. var auth = pubd.auth;
  2098. if (auth.needlogin) {
  2099. var token_type = auth.response.token_type.substring(0, 1).toUpperCase() + auth.response.token_type.substring(1);
  2100. headersObj.Authorization = token_type + " " + auth.response.access_token;
  2101. } else {
  2102. console.info("非登录模式获取信息");
  2103. }
  2104. GM_xmlhttpRequest({
  2105. url: url,
  2106. method: "get",
  2107. responseType: "text",
  2108. headers: headersObj,
  2109. onload: function(response) {
  2110. try {
  2111. var jo = JSON.parse(response.responseText);
  2112. if (jo.error) {
  2113. console.error(
  2114. jo.error.message.indexOf("Error occurred at the OAuth process.") >= 0?
  2115. "Token过期或错误":"错误:返回错误消息",
  2116. jo, response);
  2117. //jo.error.message 是JSON字符串的错误信息,Token错误的时候返回的又是普通字符串
  2118. //jo.error.user_message 是单行文本的错误信息
  2119. onload_hasError_Cb(jo);
  2120. } else { //登陆成功
  2121. //console.info("JSON返回成功",jo);
  2122. onload_suceess_Cb(jo);
  2123. }
  2124. } catch (e) {
  2125. console.error("错误:返回可能不是JSON,或程序异常", e, response);
  2126. onload_notJson_Cb(response);
  2127. }
  2128. },
  2129. onerror: function(response) {
  2130. console.error("错误:AJAX发送失败", response);
  2131. onerror_Cb(response);
  2132. }
  2133. })
  2134. }
  2135.  
  2136. //分析
  2137. dlg.analyse = function(contentType, userid) {
  2138. if (!userid) {dlg.log("错误:没有用户ID。"); return;}
  2139. contentType = contentType == undefined ? 0 : parseInt(contentType);
  2140. var works = contentType == 0 ? dlg.user.illusts : dlg.user.bookmarks; //将需要分析的数据储存到works里
  2141. dlg.works = works;
  2142.  
  2143. if (works.runing) {
  2144. dlg.log("已经在进行分析操作了");
  2145. return;
  2146. }
  2147. works.break = false; //暂停flag为false
  2148. works.runing = true; //运行状态为true
  2149.  
  2150. dlg.textdown.disabled = true; //禁用下载按钮
  2151. dlg.startdown.disabled = true; //禁用输出文本按钮
  2152. dlg.progress.set(0); //进度条归零
  2153. dlg.logClear(); //清空日志
  2154.  
  2155. //根据用户信息是否存在,决定分析用户还是图像
  2156. if (!dlg.user.done) {
  2157. startAnalyseUser(userid, contentType);
  2158. } else {
  2159. dlg.log("ID:" + userid + " 用户信息已存在");
  2160. startAnalyseWorks(dlg.user, contentType); //开始获取第一页
  2161. }
  2162.  
  2163. function startAnalyseUser(userid, contentType) {
  2164. try { //为了避免不同网页重复获取Token,开始分析前先读取储存的Token。
  2165. pubd.auth.loadFromResponse(JSON.parse(GM_getValue("pubd-auth")));
  2166. } catch (e) {
  2167. console.error("开始分析前,重新读取登录信息失败", e);
  2168. }
  2169.  
  2170. dlg.log("开始获取ID为 " + userid + " 的用户信息");
  2171. xhrGenneral(
  2172. "https://app-api.pixiv.net/v1/user/detail?user_id=" + userid,
  2173. function(jore) { //onload_suceess_Cb
  2174. works.runing = true;
  2175. dlg.user.done = true;
  2176. dlg.user.info = Object.assign(dlg.user.info, jore);
  2177. dlg.uinfo.set({
  2178. id: userid,
  2179. head: jore.user.profile_image_urls.medium,
  2180. name: jore.user.name,
  2181. illusts: jore.profile.total_illusts + jore.profile.total_manga,
  2182. bookmarks: jore.profile.total_illust_bookmarks_public,
  2183. });
  2184. startAnalyseWorks(dlg.user, contentType); //分析完成后开始获取第一页
  2185. },
  2186. function(jore) { //onload_haserror_Cb //返回错误消息
  2187. works.runing = false;
  2188. //下面开始自动登陆
  2189. if (jore.error.message.indexOf("Error occurred at the OAuth process.") >= 0) {
  2190. dlg.log("Token过期或错误,需要重新登录");
  2191. reLogin(
  2192. function(){
  2193. dlg.log("重新登录成功。");
  2194. startAnalyseUser(userid, contentType);
  2195. }
  2196. );
  2197. }else
  2198. {
  2199. dlg.log("错误信息:" + (jore.error.message || jore.error.user_message));
  2200. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2201. dlg.startdown.disabled = false;
  2202. }
  2203. return;
  2204. },
  2205. function(re) { //onload_notjson_Cb //返回不是JSON
  2206. dlg.log("错误:返回不是JSON,或程序异常");
  2207. works.runing = false;
  2208. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2209. dlg.startdown.disabled = false;
  2210. },
  2211. function(re) { //onerror_Cb //AJAX发送失败
  2212. dlg.log("错误:AJAX发送失败");
  2213. works.runing = false;
  2214. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2215. dlg.startdown.disabled = false;
  2216. }
  2217. );
  2218. }
  2219.  
  2220. //开始分析作品的前置操作
  2221. function startAnalyseWorks(user, contentType) {
  2222. var uInfo = user.info;
  2223. var works, total, contentName, apiurl;
  2224. //获取作品,contentType == 0,获取收藏,contentType == 1
  2225. if (contentType == 0) {
  2226. works = user.illusts;
  2227. total = uInfo.profile.total_illusts + uInfo.profile.total_manga;
  2228. contentName = "作品";
  2229. apiurl = "https://app-api.pixiv.net/v1/user/illusts?user_id=" + uInfo.user.id;
  2230. } else {
  2231. works = user.bookmarks;
  2232. total = uInfo.profile.total_illust_bookmarks_public;
  2233. contentName = "收藏";
  2234. apiurl = "https://app-api.pixiv.net/v1/user/bookmarks/illust?user_id=" + uInfo.user.id + "&restrict=public";
  2235. }
  2236. if (works.item.length > 0) { //断点续传
  2237. dlg.log(contentName + " 断点续传进度 " + works.item.length + "/" + total);
  2238. dlg.progress.set(works.item.length / total); //设置当前下载进度
  2239. apiurl = works.next_url;
  2240. }
  2241. analyseWorks(user, contentType, apiurl); //开始获取第一页
  2242. }
  2243. //分析作品递归函数
  2244. function analyseWorks(user, contentType, apiurl) {
  2245. var uInfo = user.info;
  2246. var works, total, contentName;
  2247. if (contentType == 0) {
  2248. works = user.illusts;
  2249. total = uInfo.profile.total_illusts + uInfo.profile.total_manga;
  2250. contentName = "作品";
  2251. } else {
  2252. works = user.bookmarks;
  2253. total = uInfo.profile.total_illust_bookmarks_public;
  2254. contentName = "收藏";
  2255. }
  2256. if (works.done) {
  2257. //返回所有动图
  2258. var ugoiras = works.item.filter(function(item) {
  2259. return item.type == "ugoira";
  2260. })
  2261. dlg.log("共存在 " + ugoiras.length + " 件动图");
  2262. if (ugoiras.some(function(item) { //如果有没有帧数据的动图
  2263. return item.ugoira_metadata == undefined;
  2264. })) {
  2265. if (!getValueDefault("pubd-getugoiraframe",true)) {
  2266. dlg.log("由于用户设置,跳过获取动图帧数。");
  2267. } else {
  2268. analyseUgoira(works, ugoiras, function() { //开始分析动图
  2269. analyseWorks(user, contentType, apiurl) //开始获取下一页
  2270. });
  2271. return;
  2272. }
  2273. }//没有动图则继续
  2274. if (works.item.length < total)
  2275. dlg.log("可能因为权限原因,无法获取到所有 " + contentName);
  2276.  
  2277. //计算一下总页数
  2278. works.picCount = works.item.reduce(function(pV,cItem){
  2279. var page = cItem.page_count;
  2280. if (cItem.type == "ugoira" && cItem.ugoira_metadata) //动图
  2281. {
  2282. page = cItem.ugoira_metadata.frames.length;
  2283. }
  2284. return pV+=page;
  2285. },0);
  2286.  
  2287. dlg.log(contentName + " 共 " + works.item.length + " 件(约 " + works.picCount + " 张图片)已获取完毕。");
  2288. dlg.progress.set(1);
  2289. works.runing = false;
  2290. works.next_url = "";
  2291. dlg.textdown.disabled = false;
  2292. dlg.startdown.disabled = false;
  2293. if (getValueDefault("pubd-autodownload",false)) { //自动开始
  2294. dlg.log("🅰️自动开始发送");
  2295. dlg.startdownload();
  2296. }
  2297. return;
  2298. }
  2299. if (works.break) {
  2300. dlg.log("检测到 " + contentName + " 中断进程命令");
  2301. works.break = false;
  2302. works.runing = false;
  2303. dlg.textdown.disabled = false; //启用按钮,中断暂停时,可以操作目前的进度。
  2304. dlg.startdown.disabled = false;
  2305. return;
  2306. }
  2307.  
  2308. xhrGenneral(
  2309. apiurl,
  2310. function(jore) { //onload_suceess_Cb
  2311. works.runing = true;
  2312. var illusts = jore.illusts;
  2313. for (var ii = 0, ii_len = illusts.length; ii < ii_len; ii++) {
  2314. var work = illusts[ii];
  2315. var original;
  2316. if (work.page_count > 1) { /*漫画多图*/
  2317. original = work.meta_pages[0].image_urls.original;
  2318. } else { /*单张图片或动图,含漫画单图*/
  2319. original = work.meta_single_page.original_image_url;
  2320. }
  2321. var regSrc = new RegExp(illustPattern, "ig");
  2322. var regRes = regSrc.exec(original);
  2323. if (regRes) {
  2324. //然后添加扩展名等
  2325. work.url_without_page = regRes[1];
  2326. work.domain = regRes[2];
  2327. work.filename = regRes[3];
  2328. work.token = regRes[4];
  2329. work.extention = regRes[5];
  2330. } else {
  2331. var regSrcL = new RegExp(limitingPattern, "ig");
  2332. var regResL = regSrcL.exec(original);
  2333. if (regResL) {
  2334. dlg.log(contentName + " " + work.id + " 非公开,无权获取下载地址。");
  2335. //console.log(work);
  2336. work.url_without_page = regResL[1];
  2337. work.domain = regResL[2];
  2338. work.filename = regResL[3];
  2339. work.token = regResL[4];
  2340. work.extention = regResL[5];
  2341. } else {
  2342. dlg.log(contentName + " " + work.id + " 原图格式未知。");
  2343. }
  2344. }
  2345.  
  2346. works.item.push(work);
  2347. }
  2348. dlg.log(contentName + " 获取进度 " + works.item.length + "/" + total);
  2349. if (works == dlg.works) dlg.progress.set(works.item.length / total); //如果没有中断则设置当前下载进度
  2350. if (jore.next_url) { //还有下一页
  2351. works.next_url = jore.next_url;
  2352. } else { //没有下一页
  2353. works.done = true;
  2354. }
  2355. analyseWorks(user, contentType, jore.next_url); //开始获取下一页
  2356. },
  2357. function(jore) { //onload_haserror_Cb //返回错误消息
  2358. works.runing = false;
  2359. //下面开始自动登陆
  2360. if (jore.error.message.indexOf("Error occurred at the OAuth process.") >= 0) {
  2361. dlg.log("Token过期或错误,需要重新登录");
  2362. reLogin(
  2363. function(){
  2364. dlg.log("重新登录成功。");
  2365. analyseWorks(user, contentType, apiurl);
  2366. }
  2367. );
  2368. }else
  2369. {
  2370. dlg.log("错误信息:" + (jore.error.message || jore.error.user_message));
  2371. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2372. dlg.startdown.disabled = false;
  2373. }
  2374. return;
  2375. },
  2376. function(re) { //onload_notjson_Cb //返回不是JSON
  2377. dlg.log("错误:返回不是JSON,或程序异常");
  2378. works.runing = false;
  2379. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2380. dlg.startdown.disabled = false;
  2381. },
  2382. function(re) { //onerror_Cb //AJAX发送失败
  2383. dlg.log("错误:AJAX发送失败");
  2384. works.runing = false;
  2385. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2386. dlg.startdown.disabled = false;
  2387. }
  2388. )
  2389. }
  2390.  
  2391. function analyseUgoira(works, ugoirasItems, callback) {
  2392. var dealItems = ugoirasItems.filter(function(item) {
  2393. return (item.type == "ugoira" && item.ugoira_metadata == undefined);
  2394. })
  2395. if (dealItems.length < 1) {
  2396. dlg.log("动图获取完毕");
  2397. dlg.progress.set(1); //设置当前下载进度
  2398. callback();
  2399. return;
  2400. }
  2401. if (works.break) {
  2402. dlg.log("检测到中断进程命令");
  2403. works.break = false;
  2404. works.runing = false;
  2405. dlg.textdown.disabled = false; //中断暂停时,可以操作目前的进度。
  2406. dlg.startdown.disabled = false;
  2407. return;
  2408. }
  2409.  
  2410. var work = dealItems[0]; //当前处理的图
  2411.  
  2412. xhrGenneral(
  2413. "https://app-api.pixiv.net/v1/ugoira/metadata?illust_id=" + work.id,
  2414. function(jore) { //onload_suceess_Cb
  2415. works.runing = true;
  2416. //var illusts = jore.illusts;
  2417. work = Object.assign(work, jore);
  2418. dlg.log("动图信息 获取进度 " + (ugoirasItems.length - dealItems.length + 1) + "/" + ugoirasItems.length);
  2419. dlg.progress.set(1 - dealItems.length / ugoirasItems.length); //设置当前下载进度
  2420. analyseUgoira(works, ugoirasItems, callback); //开始获取下一项
  2421. },
  2422. function(jore) { //onload_haserror_Cb //返回错误消息
  2423. works.runing = false;
  2424. //下面开始自动登陆
  2425. if (jore.error.message.indexOf("Error occurred at the OAuth process.") >= 0) {
  2426. dlg.log("Token过期或错误,需要重新登录");
  2427. reLogin(
  2428. function(){
  2429. dlg.log("重新登录成功。");
  2430. analyseUgoira(works, ugoirasItems, callback);
  2431. }
  2432. );
  2433. }else if(work.restrict > 0) //非公共权限
  2434. { //添加一条空信息
  2435. work.ugoira_metadata = {
  2436. frames: [],
  2437. zip_urls: {
  2438. medium: "",
  2439. },
  2440. };
  2441. dlg.log("无访问权限,跳过本条。");
  2442. analyseUgoira(works, ugoirasItems, callback); //开始获取下一项
  2443. }else
  2444. {
  2445. dlg.log("错误信息:" + (jore.error.message || jore.error.user_message));
  2446. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2447. dlg.startdown.disabled = false;
  2448. }
  2449. return;
  2450. },
  2451. function(re) { //onload_notjson_Cb //返回不是JSON
  2452. dlg.log("错误:返回不是JSON,或程序异常");
  2453. works.runing = false;
  2454. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2455. dlg.startdown.disabled = false;
  2456. },
  2457. function(re) { //onerror_Cb //AJAX发送失败
  2458. dlg.log("错误:AJAX发送失败");
  2459. works.runing = false;
  2460. dlg.textdown.disabled = false; //错误暂停时,可以操作目前的进度。
  2461. dlg.startdown.disabled = false;
  2462. }
  2463. )
  2464. }
  2465. }
  2466. //输出文本按钮
  2467. dlg.textdownload = function() {
  2468. if (dlg.downScheme.selectedOptions.length < 1) { alert("没有选中方案"); return; }
  2469. var scheme = dlg.schemes[dlg.downScheme.selectedIndex];
  2470. var contentType = dlg.dcType[1].checked ? 1 : 0;
  2471. var userInfo = dlg.user.info;
  2472. var illustsItems = contentType == 0 ? dlg.user.illusts.item : dlg.user.bookmarks.item; //将需要分析的数据储存到works里
  2473. dlg.log("正在生成文本信息");
  2474.  
  2475. try {
  2476. var outTxtArr = illustsItems.map(function(illust) {
  2477. var page_count = illust.page_count;
  2478. if (illust.type == "ugoira" && illust.ugoira_metadata) //动图
  2479. {
  2480. page_count = illust.ugoira_metadata.frames.length;
  2481. }
  2482. var outArr = []; //输出内容
  2483. for (var pi = 0; pi < page_count; pi++) {
  2484. if (returnLogicValue(scheme.downfilter, userInfo, illust, pi) || new RegExp(limitingFilenamePattern, "ig").exec(illust.filename)) {
  2485. //跳过此次输出
  2486. continue;
  2487. }else{
  2488. outArr.push(showMask(scheme.textout, scheme.masklist, userInfo, illust, pi));
  2489. }
  2490. }
  2491. return outArr.join("");
  2492. });
  2493. var outTxt = outTxtArr.join("");
  2494. dlg.textoutTextarea.value = outTxt;
  2495. dlg.textoutTextarea.classList.remove("display-none");
  2496. dlg.log("文本信息输出成功");
  2497. } catch (error) {
  2498. console.log(error)
  2499. }
  2500. }
  2501. //开始下载按钮
  2502. dlg.startdownload = function() {
  2503. dlg.textoutTextarea.classList.add("display-none");
  2504. if (dlg.downScheme.selectedOptions.length < 1) { alert("没有选中方案"); return; }
  2505. var scheme = dlg.schemes[dlg.downScheme.selectedIndex];
  2506. var contentType = dlg.dcType[1].checked ? 1 : 0;
  2507. var userInfo = dlg.user.info;
  2508. var works = (contentType == 0 ? dlg.user.illusts : dlg.user.bookmarks);
  2509. var illustsItems = works.item.concat(); //为了不改变原数组,新建一个数组
  2510.  
  2511. var termwiseType = parseInt(getValueDefault("pubd-termwiseType", 2));
  2512. if (termwiseType == 0)
  2513. dlg.log("开始按图片逐项发送(约 "+works.picCount+" 次请求),⏳请耐心等待。");
  2514. else if (termwiseType == 1)
  2515. dlg.log("开始按作品逐项发送(约 "+illustsItems.length+" 次请求),⏳请耐心等待。");
  2516. else if (termwiseType == 2)
  2517. dlg.log("开始按作者发送,数据量较大时有较高延迟。\n⏳请耐心等待完成通知,勿多次点击。");
  2518. else
  2519. {
  2520. alert("错误:未知的逐项模式" + termwiseType);
  2521. console.error("PUBD:错误:未知的逐项模式:", termwiseType);
  2522. return;
  2523. }
  2524. var downP = { progress: dlg.progress, current: 0, max: 0 };
  2525. downP.max = works.picCount; //获取总需要下载发送的页数
  2526. var aria2 = new Aria2(scheme.rpcurl); //生成一个aria2对象
  2527. sendToAria2_illust(aria2, termwiseType, illustsItems, userInfo, scheme, downP, function() {
  2528. aria2 = null;
  2529. dlg.log("😄 " + userInfo.user.name + " 下载信息发送完毕");
  2530. var ntype = parseInt(getValueDefault("pubd-noticeType", 0)); //获取结束后如何处理通知
  2531. var bodyText = "" + userInfo.user.name + " 的相关插画已全部发送到指定的Aria2";
  2532. if (ntype == 1)
  2533. bodyText += "\n\n点击此通知 🔙返回 页面。";
  2534. else if (ntype == 2)
  2535. bodyText += "\n\n点击此通知 ❌关闭 页面。";
  2536. else if (ntype == 3)
  2537. bodyText += "\n\n通知结束时页面将 🅰️自动❌关闭。";
  2538. GM_notification(
  2539. {
  2540. text:bodyText,
  2541. title:"下载信息发送完毕",
  2542. image:userInfo.user.profile_image_urls.medium
  2543. },
  2544. function(){ //点击了通知
  2545. var ntype = parseInt(getValueDefault("pubd-noticeType", 0));
  2546. if (ntype == 1)
  2547. window.focus();
  2548. else if (ntype == 2)
  2549. window.close();
  2550. },
  2551. function(){ //关闭了通知
  2552. var ntype = parseInt(getValueDefault("pubd-noticeType", 0));
  2553. if (ntype == 3)
  2554. window.close();
  2555. },
  2556. );
  2557. });
  2558. }
  2559. //启动初始化
  2560. dlg.initialise = function() {
  2561. var dcType = 0;
  2562. if (dlg.user.bookmarks.runing) //如果有程序正在运行,则覆盖设置。
  2563. dcType = 1;
  2564. else if (dlg.user.illusts.runing)
  2565. dcType = 0;
  2566.  
  2567. dlg.dcType[dcType].checked = true;
  2568. if (getValueDefault("pubd-autoanalyse",false)) {
  2569. if (!dlg.uinfo.userid) {
  2570. dlg.uinfo.userid = parseInt(prompt("没有用户ID,请手动输入。", "ID错误"));
  2571. dlg.uinfo.set({id: dlg.uinfo.userid});
  2572. }
  2573. dlg.analyse(dcType, dlg.uinfo.userid);
  2574. }
  2575.  
  2576. //pubd.downSchemes = NewDownSchemeArrayFromJson(getValueDefault("pubd-downschemes",0)); //重新读取下载方案(可能被其他页面修改的)
  2577. dlg.reloadSchemes();
  2578. };
  2579.  
  2580. return dlg;
  2581. }
  2582. //为了区分设置窗口和保存的设置,产生一个新的下载方案数组
  2583. function NewDownSchemeArrayFromJson(jsonarr) {
  2584.  
  2585. if (typeof(jsonarr) == "string") {
  2586. try {
  2587. var jsonarr = JSON.parse(jsonarr);
  2588. } catch (e) {
  2589. console.error("PUBD:拷贝新下载方案数组时失败", e);
  2590. return false;
  2591. }
  2592. }
  2593. var sarr = new Array();
  2594. if (jsonarr instanceof Array) {
  2595. for (var si = 0; si < jsonarr.length; si++) {
  2596. var scheme = new DownScheme();
  2597. scheme.loadFromJson(jsonarr[si]);
  2598. sarr.push(scheme);
  2599. }
  2600. }
  2601. return sarr;
  2602. }
  2603. //作品循环递归输出
  2604. function sendToAria2_illust(aria2, termwiseType, illusts, userInfo, scheme, downP, callback) {
  2605. if (illusts.length < 1) //做完了
  2606. {
  2607. callback();
  2608. return;
  2609. }
  2610. if (pubd.downbreak)
  2611. {
  2612. GM_notification({text:"已中断向Aria2发送下载信息。但Aria2本身仍未停止下载已添加内容,请手动停止。", title:scriptName, image:scriptIcon});
  2613. pubd.downbreak = false;
  2614. return;
  2615. }
  2616. if (termwiseType == 0) //完全逐项
  2617. {
  2618. var illust = illusts.shift(); //读取首个作品
  2619. sendToAria2_Page(aria2, illust, 0, userInfo, scheme, downP, function() {
  2620. sendToAria2_illust(aria2, termwiseType, illusts, userInfo, scheme, downP, callback); //发送下一个作品
  2621. })
  2622. return; //不再继续执行
  2623. }else if (termwiseType == 1) //部分逐项(每作品合并)
  2624. {
  2625. var illust = illusts.shift(); //读取首个作品
  2626. var page_count = illust.page_count; //作品页数
  2627. if (illust.type == "ugoira" && illust.ugoira_metadata) //修改动图的页数
  2628. {
  2629. page_count = illust.ugoira_metadata.frames.length;
  2630. }
  2631. if (new RegExp(limitingFilenamePattern, "ig").exec(illust.filename)) //无权查看的文件
  2632. {
  2633. downP.progress.set((downP.current += page_count) / downP.max); //直接加上一个作品所有页数
  2634. sendToAria2_illust(aria2, termwiseType, illusts, userInfo, scheme, downP, callback); //调用自身
  2635. return;
  2636. }
  2637. var aria2_params = [];
  2638. for (page=0;page<page_count;page++)
  2639. {
  2640. if (returnLogicValue(scheme.downfilter, userInfo, illust, page)) {
  2641. //跳过此次下载
  2642. //console.info("符合下载过滤器定义,跳过下载:", illust);
  2643. continue;
  2644. } else {
  2645. var aria2_method = {'methodName':'aria2.addUri','params':[]};
  2646. var url = (scheme.https2http //https替换成http
  2647. ? illust.url_without_page.replace(/^https:\/\//igm, "http://")
  2648. : illust.url_without_page)
  2649. + page + "." + illust.extention;
  2650. aria2_method.params.push([url]); //添加下载链接
  2651. var options = {
  2652. "out": replacePathSafe(showMask(scheme.savepath, scheme.masklist, userInfo, illust, page), 1),
  2653. "referer": "https://app-api.pixiv.net/",
  2654. "user-agent": UA,
  2655. }
  2656. if (scheme.savedir.length > 0) {
  2657. options.dir = replacePathSafe(showMask(scheme.savedir, scheme.masklist, userInfo, illust, page), 0);
  2658. }
  2659. aria2_method.params.push(options);
  2660. aria2_params.push(aria2_method);
  2661. }
  2662. }
  2663. if (aria2_params.length>0)
  2664. {
  2665. aria2.system.multicall([aria2_params],function(res){
  2666. if (res === false) {
  2667. alert("发送到指定的Aria2失败,请检查到Aria2连接是否正常。");
  2668. return;
  2669. }
  2670. downP.progress.set((downP.current += page_count) / downP.max); //直接加上一个作品所有页数
  2671. sendToAria2_illust(aria2, termwiseType, illusts, userInfo, scheme, downP, callback); //调用自身
  2672. });
  2673. }else
  2674. { //这个作品全部跳过的时候
  2675. downP.progress.set((downP.current += page_count) / downP.max); //直接加上一个作品所有页数
  2676. sendToAria2_illust(aria2, termwiseType, illusts, userInfo, scheme, downP, callback); //调用自身
  2677. }
  2678. return;
  2679. }else if(termwiseType == 2) //不逐项,每作者合并
  2680. {
  2681. var aria2_params = [];
  2682. for (var illustIndex = 0; illustIndex < illusts.length; illustIndex++)
  2683. {
  2684. var illust = illusts[illustIndex];
  2685. if (new RegExp(limitingFilenamePattern, "ig").exec(illust.filename)) continue; //无权查看的文件,直接继续
  2686.  
  2687. var page_count = illust.page_count; //作品页数
  2688. if (illust.type == "ugoira" && illust.ugoira_metadata) //修改动图的页数
  2689. {
  2690. page_count = illust.ugoira_metadata.frames.length;
  2691. }
  2692. for (page=0;page<page_count;page++)
  2693. {
  2694. if (returnLogicValue(scheme.downfilter, userInfo, illust, page)) {
  2695. //跳过此次下载
  2696. //console.info("符合下载过滤器定义,跳过下载:", illust);
  2697. continue;
  2698. } else {
  2699. var aria2_method = {'methodName':'aria2.addUri','params':[]};
  2700. var url = (scheme.https2http //https替换成http
  2701. ? illust.url_without_page.replace(/^https:\/\//igm, "http://")
  2702. : illust.url_without_page)
  2703. + page + "." + illust.extention;
  2704. aria2_method.params.push([url]); //添加下载链接
  2705. var options = {
  2706. "out": replacePathSafe(showMask(scheme.savepath, scheme.masklist, userInfo, illust, page), 1),
  2707. "referer": "https://app-api.pixiv.net/",
  2708. "user-agent": UA,
  2709. }
  2710. if (scheme.savedir.length > 0) {
  2711. options.dir = replacePathSafe(showMask(scheme.savedir, scheme.masklist, userInfo, illust, page), 0);
  2712. }
  2713. aria2_method.params.push(options);
  2714. aria2_params.push(aria2_method);
  2715. }
  2716. }
  2717. }
  2718. if (aria2_params.length>0)
  2719. {
  2720. aria2.system.multicall([aria2_params],function(res){
  2721. if (res === false) {
  2722. alert("发送到指定的Aria2失败,请检查到Aria2连接是否正常。不排除数据过大,可考虑临时使用逐项或半逐项模式。");
  2723. var l= JSON.stringify(aria2_params).length/1024;
  2724. console.error("Aria2接受失败。数据量在未添加token的情况下有" + (
  2725. (l>1024)?
  2726. ((l/1024)+"MB"):
  2727. (l+"KB")
  2728. ),aria2_params);
  2729. return;
  2730. }
  2731. downP.progress.set((downP.current = downP.max) / downP.max); //直接加上所有页数
  2732. sendToAria2_illust(aria2, termwiseType, [], userInfo, scheme, downP, callback); //调用自身
  2733. });
  2734. }else
  2735. { //这个作品全部跳过的时候
  2736. downP.progress.set((downP.current = downP.max) / downP.max); //直接加上所有页数
  2737. sendToAria2_illust(aria2, termwiseType, [], userInfo, scheme, downP, callback); //调用自身
  2738. }
  2739. return;
  2740. }
  2741. }
  2742. //作品每页循环递归输出
  2743. function sendToAria2_Page(aria2, illust, page, userInfo, scheme, downP, callback) {
  2744. if (pubd.downbreak) {
  2745. GM_notification({text:"已中断向Aria2发送下载信息。但Aria2本身仍未停止下载已添加内容,请手动停止。", title:scriptName, image:scriptIcon});
  2746. pubd.downbreak = false;
  2747. return;
  2748. }
  2749. var page_count = illust.page_count;
  2750. if (illust.type == "ugoira" && illust.ugoira_metadata) //动图的帧数当页数
  2751. {
  2752. page_count = illust.ugoira_metadata.frames.length;
  2753. }
  2754. if (new RegExp(limitingFilenamePattern, "ig").exec(illust.filename)) //无法查看的文件,直接把page加到顶
  2755. {
  2756. page = page_count;
  2757. downP.progress.set((downP.current += page_count) / downP.max); //直接加上所有页数
  2758. }
  2759. if (page >= page_count) //本作品页数已经完毕
  2760. {
  2761. callback();
  2762. return;
  2763. }
  2764. var url = (scheme.https2http //https替换成http
  2765. ? illust.url_without_page.replace(/^https:\/\//igm, "http://")
  2766. : illust.url_without_page)
  2767. + page + "." + illust.extention;
  2768.  
  2769. if (returnLogicValue(scheme.downfilter, userInfo, illust, page)) {
  2770. //跳过此次下载
  2771. downP.progress.set(++downP.current / downP.max); //设置进度
  2772. sendToAria2_Page(aria2, illust, ++page, userInfo, scheme, downP, callback); //递归调用自身
  2773. //console.info("符合下载过滤器定义,跳过下载:", illust);
  2774. } else {
  2775. var options = {
  2776. "out": replacePathSafe(showMask(scheme.savepath, scheme.masklist, userInfo, illust, page), 1),
  2777. "referer": "https://app-api.pixiv.net/",
  2778. "user-agent": UA,
  2779. }
  2780.  
  2781. if (scheme.savedir.length > 0) {
  2782. options.dir = replacePathSafe(showMask(scheme.savedir, scheme.masklist, userInfo, illust, page), 0);
  2783. }
  2784. aria2.addUri(url, options, function(res) {
  2785. if (res === false) {
  2786. alert("发送到指定的Aria2失败,请检查到Aria2连接是否正常。");
  2787. return;
  2788. }
  2789. downP.progress.set(++downP.current / downP.max); //设置进度
  2790. sendToAria2_Page(aria2, illust, ++page, userInfo, scheme, downP, callback); //递归调用自身
  2791. });
  2792. }
  2793. }
  2794. //返回掩码值
  2795. function showMask(oldStr, maskList, user, illust, page) {
  2796. var newStr = oldStr;
  2797. //var pattern = "%{([^}]+)}"; //旧的,简单匹配
  2798. var regPattern = "%{(.*?(?:[^\\\\](?:\\\\{2})+|[^\\\\]))}"; //新的,支持转义符
  2799. var regResult = null;
  2800.  
  2801. //不断循环直到没有掩码
  2802. while ((regResult = new RegExp(regPattern).exec(newStr)) != null) {
  2803. var mskO = regResult[0], //包含括号的原始掩码
  2804. mskN = regResult[1]; //去掉掩码括号
  2805. if (mskN != undefined) {
  2806. //去掉转义符的掩码名
  2807. mskN = (mskN != undefined) ? mskN.replace(/\\{/ig, "{").replace(/\\}/ig, "}").replace(/\\\\/ig, "\\") : null;
  2808. //搜寻自定义掩码
  2809. var cusMasks = maskList.filter(function(mask) { return mask.name == mskN; });
  2810. if (cusMasks.length > 0) { //如果有对应的自定义掩码
  2811. var cusMask = cusMasks[0];
  2812. try {
  2813. if (returnLogicValue(cusMask.logic, user, illust, page)) //mask的逻辑判断
  2814. newStr = newStr.replace(mskO, cusMask.content);
  2815. else
  2816. newStr = newStr.replace(mskO, "");
  2817. } catch (e) {
  2818. console.error(mskO + " 自定义掩码出现了异常情况", e);
  2819. }
  2820. } else { //普通掩码
  2821. try {
  2822. var evTemp = eval(mskN);
  2823. if (evTemp != undefined)
  2824. newStr = newStr.replace(mskO, evTemp.toString());
  2825. else
  2826. newStr = newStr.replace(mskO, "");
  2827. } catch (e) {
  2828. newStr = newStr.replace(mskO, "");
  2829. console.error(mskO + " 掩码出现了异常情况", e);
  2830. }
  2831. }
  2832. }
  2833. }
  2834.  
  2835. return newStr;
  2836. }
  2837. //返回逻辑值
  2838. function returnLogicValue(logic, user, illust, page) {
  2839. try {
  2840. if (logic.length == 0) return false;
  2841. var evTemp = eval("(" + logic + ")");
  2842. return evTemp;
  2843. } catch (e) {
  2844. console.error("下载过滤器出现了异常情况,逻辑内容:","(" + logic + ")", e);
  2845. return false;
  2846. }
  2847. }
  2848.  
  2849. function replacePathSafe(str, type) //去除Windows下无法作为文件名的字符,目前为了支持Linux暂不替换两种斜杠吧。
  2850. { //keepTree表示是否要保留目录树的字符(\、/和:)
  2851. if (typeof(str) == "undefined")
  2852. {
  2853. return "";
  2854. }
  2855. var nstr = str; //新字符
  2856. nstr = nstr.toString();
  2857. nstr = nstr.replace(/\u0000-\u001F\u007F-\u00A0/ig, ""); //替换所有的控制字符
  2858. var patternStrs = [
  2859. "[\\*\\?\"<>\\|]", //只替换路径中完全不能出现的特殊字符
  2860. "[\\*\\?\"<>\\|\\r\\n]", //上述字符加冒号:,用于非驱动器路径
  2861. "[\\*\\?\"<>\\|\\r\\n\\\\\\/]", //完全替换所有不能出现的特殊字符,包含斜杠
  2862. ];
  2863. if (patternStrs[type] != undefined)
  2864. {
  2865. nstr = nstr.replace(new RegExp(patternStrs[type],"ig"), "_"); //只替换路径中完全不能出现的特殊字符
  2866. }
  2867. return nstr;
  2868. }
  2869.  
  2870. //开始构建UI
  2871. function findInsertPlace(touch, loggedIn) {
  2872. if (touch)
  2873. {
  2874. //alert("PUBD暂不支持手机版");
  2875. clearInterval(findInsertPlaceHook);
  2876. return;
  2877. } else {
  2878. var btnStartInsertPlace = dqS("#root>div>div>div>div>div:nth-of-type(2)>div:nth-of-type(2)>div") //2018年10月8日 新版用户资料首页
  2879. ||dqS("#root>div>div>div>aside>section") //新版作品页
  2880. //||dqS("#root>div:nth-of-type(5)>div>div>div>div>div>div>div>div") //新版FANBOOK页,但是并不支持收费的东西,所以就隐藏了吧
  2881. ||dqS("._user-profile-card") //老版用户资料页
  2882. ||dqS(".ui-layout-west aside") //老版作品页
  2883. ||dqS(".introduction") //未登录页面
  2884. ;
  2885. if (btnStartInsertPlace == undefined)
  2886. {
  2887. console.error("PUBD:未找到开始按钮插入点。");
  2888. return;
  2889. }else
  2890. {
  2891. clearInterval(findInsertPlaceHook); //停止循环
  2892. }
  2893.  
  2894. //插入警告
  2895. var showAlert = btnStartInsertPlace.appendChild(dcE("span"));
  2896. showAlert.className = "pubd-alert-" + pubd.cssVersion;
  2897. showAlert.innerHTML = '你没有正确安装用户样式,或用户样式已过期,或用户样式没过期但脚本过期,请访问<a href="https://github.com/Mapaler/PixivUserBatchDownload" target="_blank">PUBD发布页</a>更新版本。';
  2898. //插入开始操作按钮
  2899. var btnStartBox = btnStartInsertPlace.appendChild(dcE("div"));
  2900. btnStartBox.className = "pubd-btnStartInsertPlace";
  2901. pubd.start = btnStartBox.appendChild(buildbtnStart(touch));
  2902. pubd.menu = btnStartBox.appendChild(buildbtnMenu(touch));
  2903. }
  2904. }
  2905. //开始主程序
  2906. function start(touch) {
  2907. if (touch //手机版
  2908. )
  2909. { //手机版退出执行
  2910. //alert("PUBD暂不支持手机版");
  2911. clearInterval(findInsertPlaceHook);
  2912. return;
  2913. }
  2914. //载入设置
  2915. pubd.auth = new Auth();
  2916. try {
  2917. pubd.auth.loadFromResponse(JSON.parse(GM_getValue("pubd-auth")));
  2918. } catch (e) {
  2919. console.error("PUBD:脚本初始化时,读取登录信息失败。", e);
  2920. }
  2921. pubd.downSchemes = NewDownSchemeArrayFromJson(getValueDefault("pubd-downschemes",0));
  2922.  
  2923. //对下载方案的修改添加监听
  2924. GM_addValueChangeListener("pubd-downschemes", function(name, old_value, new_value, remote) {
  2925. pubd.downSchemes = NewDownSchemeArrayFromJson(new_value); //重新读取下载方案(可能被其他页面修改的)
  2926. })
  2927.  
  2928. //预先添加所有视窗,即便没有操作按钮也能通过菜单打开
  2929. var btnDlgInsertPlace = dBd;
  2930. pubd.dialog.config = btnDlgInsertPlace.appendChild(buildDlgConfig(touch));
  2931. pubd.dialog.login = btnDlgInsertPlace.appendChild(buildDlgLogin(touch));
  2932. pubd.dialog.downthis = btnDlgInsertPlace.appendChild(buildDlgDownThis(touch));
  2933. //添加Tampermonkey扩展菜单内的入口
  2934. GM_registerMenuCommand("PUBD-下载该画师", function(){pubd.dialog.downthis.show((dBd.clientWidth - 440)/2, window.pageYOffset+100)});
  2935. GM_registerMenuCommand("PUBD-选项", function(){pubd.dialog.config.show((dBd.clientWidth - 400)/2, window.pageYOffset+50);});
  2936.  
  2937. //对于新版P站的SPA结构需要循环寻找插入点,每秒循环
  2938. findInsertPlaceHook = setInterval(function(){
  2939. findInsertPlace(touch, pubd.loggedIn);
  2940. }, 1000);
  2941. }
  2942. start(pubd.touch); //开始主程序