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

一键批量下载P站画师的全部作品

目前为 2017-01-12 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name PixivUserBatchDownload
  3. // @name:zh-CN P站画师个人作品批量下载工具
  4. // @namespace http://www.mapaler.com/
  5. // @description Batch download pixiv user's images in one key.
  6. // @description:zh-CN 一键批量下载P站画师的全部作品
  7. // @include *://www.pixiv.net/*
  8. // @include *://touch.pixiv.net/*
  9. // @exclude *://www.pixiv.net/*mode=manga&illust_id*
  10. // @exclude *://www.pixiv.net/*mode=big&illust_id*
  11. // @exclude *://www.pixiv.net/*mode=manga_big*
  12. // @exclude *://www.pixiv.net/*search.php*
  13. // @version 5.0.0 Alpha1
  14. // @copyright 2017+, Mapaler <mapaler@163.com>
  15. // @icon http://www.pixiv.net/favicon.ico
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // @grant GM_deleteValue
  20. // @grant GM_listValues
  21. // ==/UserScript==
  22.  
  23. /*
  24. * 公共变量区
  25. */
  26. var pubd = { //储存设置
  27. configVersion: 0, //当前设置版本,用于提醒是否需要重置
  28. touch:false, //是触屏
  29. loggedIn:false, //登陆了
  30. start:null, //开始按钮
  31. menu:null, //菜单
  32. dialog:{ //窗口些个
  33. config:null, //设置窗口
  34. login:null, //登陆窗口
  35. downthis:null, //下载当前窗口
  36. },
  37. auth:null,
  38. downSchemes:[],
  39. };
  40.  
  41. var scriptName = typeof(GM_info)!="undefined" ? (GM_info.script.localizedName ? GM_info.script.localizedName : GM_info.script.name) : "PixivUserBatchDownload"; //本程序的名称
  42. var scriptVersion = typeof(GM_info)!="undefined" ? GM_info.script.version : "LocalDebug"; //本程序的版本
  43. var scriptIcon = ((typeof (GM_info) != "undefined") && GM_info.script.icon) ? GM_info.script.icon : "http://www.pixiv.net/favicon.ico"; //本程序的图标
  44.  
  45. //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站图片地址正则匹配式
  46. 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站图片地址正则匹配式
  47.  
  48. /*
  49. * 获取初始状态
  50. */
  51. if (typeof(unsafeWindow)!="undefined")
  52. var pixiv = unsafeWindow.pixiv;
  53. if (typeof(pixiv)=="undefined")
  54. {
  55. console.error("当前网页没有找到pixiv对象");
  56. }
  57. if (pixiv && pixiv.user.loggedIn)
  58. {
  59. pubd.loggedIn = true;
  60. }
  61. if (location.host.indexOf("touch")>=0) //typeof(pixiv.AutoView)!="undefined"
  62. {
  63. pubd.touch=true;
  64. console.info("当前访问的是P站触屏手机版");
  65. }else
  66. {
  67. console.info("当前访问的是P站桌面版");
  68. }
  69.  
  70. /*
  71. * Debug 用 仿GM函数区
  72. */
  73. //访GM_xmlhttpRequest函数v1.2
  74. if(typeof(GM_xmlhttpRequest) == "undefined")
  75. {
  76. var GM_xmlhttpRequest = function(GM_param){
  77.  
  78. var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
  79. if(GM_param.responseType) xhr.responseType = GM_param.responseType;
  80. xhr.onreadystatechange = function() //设置回调函数
  81. {
  82. if (xhr.readyState == 4 && xhr.status == 200 && GM_param.onload)
  83. GM_param.onload(xhr);
  84. if (xhr.readyState == 4 && xhr.status != 200 && GM_param.onerror)
  85. GM_param.onerror(xhr);
  86. }
  87. xhr.open(GM_param.method, GM_param.url, true);
  88.  
  89. for (var header in GM_param.headers){
  90. xhr.setRequestHeader(header, GM_param.headers[header]);
  91. }
  92.  
  93. xhr.send(GM_param.data ? GM_param.data : null);
  94. }
  95. }
  96. //仿GM_getValue函数v1.0
  97. if(typeof(GM_getValue) == "undefined")
  98. {
  99. var GM_getValue = function(name, type){
  100. var value = localStorage.getItem(name);
  101. if (value == undefined) return value;
  102. if ((/^(?:true|false)$/i.test(value) && type == undefined) || type == "boolean")
  103. {
  104. if (/^true$/i.test(value))
  105. return true;
  106. else if (/^false$/i.test(value))
  107. return false;
  108. else
  109. return Boolean(value);
  110. }
  111. else if((/^\-?[\d\.]+$/i.test(value) && type == undefined) || type == "number")
  112. return Number(value);
  113. else
  114. return value;
  115. }
  116. }
  117. //仿GM_setValue函数v1.0
  118. if(typeof(GM_setValue) == "undefined")
  119. {
  120. var GM_setValue = function(name, value){
  121. localStorage.setItem(name, value);
  122. }
  123. }
  124. //仿GM_deleteValue函数v1.0
  125. if(typeof(GM_deleteValue) == "undefined")
  126. {
  127. var GM_deleteValue = function(name){
  128. localStorage.removeItem(name);
  129. }
  130. }
  131. //仿GM_listValues函数v1.0
  132. if(typeof(GM_listValues) == "undefined")
  133. {
  134. var GM_listValues = function(){
  135. var keys = new Array();
  136. for (var ki=0, kilen=localStorage.length; ki<kilen; ki++)
  137. {
  138. keys.push(localStorage.key(ki));
  139. }
  140. return keys;
  141. }
  142. }
  143.  
  144. /*
  145. * 现成函数库
  146. */
  147. //发送网页通知
  148. function spawnNotification(theBody, theIcon, theTitle)
  149. {
  150. var options = {
  151. body: theBody,
  152. icon: theIcon
  153. }
  154. if (!("Notification" in window))
  155. {
  156. alert(theBody);
  157. }
  158. else if (Notification.permission === "granted") {
  159. Notification.requestPermission(function (permission) {
  160. // If the user is okay, let's create a notification
  161. var n = new Notification(theTitle, options);
  162. });
  163. }
  164. // Otherwise, we need to ask the user for permission
  165. else if (Notification.permission !== 'denied') {
  166. Notification.requestPermission(function (permission) {
  167. // If the user is okay, let's create a notification
  168. if (permission === "granted") {
  169. var n = new Notification(theTitle, options);
  170. }
  171. });
  172. }
  173. }
  174. /*\
  175. |*|
  176. |*| :: cookies.js ::
  177. |*|
  178. |*| A complete cookies reader/writer framework with full unicode support.
  179. |*|
  180. |*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie
  181. |*|
  182. |*| This framework is released under the GNU Public License, version 3 or later.
  183. |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
  184. |*|
  185. |*| Syntaxes:
  186. |*|
  187. |*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
  188. |*| * docCookies.getItem(name)
  189. |*| * docCookies.removeItem(name[, path], domain)
  190. |*| * docCookies.hasItem(name)
  191. |*| * docCookies.keys()
  192. |*|
  193. \*/
  194.  
  195. var docCookies = {
  196. getItem: function (sKey) {
  197. return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
  198. },
  199. setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
  200. if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
  201. var sExpires = "";
  202. if (vEnd) {
  203. switch (vEnd.constructor) {
  204. case Number:
  205. sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
  206. break;
  207. case String:
  208. sExpires = "; expires=" + vEnd;
  209. break;
  210. case Date:
  211. sExpires = "; expires=" + vEnd.toUTCString();
  212. break;
  213. }
  214. }
  215. document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
  216. return true;
  217. },
  218. removeItem: function (sKey, sPath, sDomain) {
  219. if (!sKey || !this.hasItem(sKey)) { return false; }
  220. document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
  221. return true;
  222. },
  223. hasItem: function (sKey) {
  224. return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
  225. },
  226. keys: /* optional method: you can safely remove it! */ function () {
  227. var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
  228. for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
  229. return aKeys;
  230. }
  231. };
  232.  
  233. /*
  234. * 自定义对象区
  235. */
  236. //一个用户的信息
  237. var UserInfo = function()
  238. {
  239. var obj = {
  240. done:false,
  241. info:{
  242. profile:null,
  243. user:null,
  244. profile:null,
  245. },
  246. illusts:{
  247. done:false,
  248. item:[],
  249. break:false,
  250. runing:false,
  251. next_url:"",
  252. },
  253. bookmarks:{
  254. done:false,
  255. item:[],
  256. break:false,
  257. runing:false,
  258. next_url:"",
  259. },
  260. }
  261. return obj;
  262. }
  263.  
  264. //一个Post数据
  265. var PostDataObject = (function () {
  266. return function(obj)
  267. {
  268. var postdata = new Object;
  269. if (obj)
  270. postdata.data = Object.assign({}, obj); //合并obj
  271. postdata.increase = function(obj)
  272. {
  273. postdata.data = Object.assign(postdata.data, obj); //合并obj
  274. }
  275. postdata.toPostString = function()
  276. {
  277. var arr = new Array;
  278. for (var na in postdata.data)
  279. {
  280. var item = [ na , postdata.data[na] ];
  281. arr.push(item);
  282. }
  283. var str = arr.map(
  284. function (item){
  285. return item.join("=");
  286. }
  287. ).join("&");
  288. return str;
  289. }
  290. return postdata;
  291. }
  292. })();
  293.  
  294. //一个本程序使用的headers数据
  295. var HeadersObject = function (obj) {
  296. var headers = {
  297. 'App-OS': 'android',
  298. 'App-OS-Version': '6.0',
  299. 'App-Version': '5.0.49',
  300. 'User-Agent': 'PixivAndroidApp/5.0.49 (Android 6.0; LG-H818)',
  301. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', //重要
  302. "Referer": "https://app-api.pixiv.net/",
  303. }
  304. if (obj)
  305. headers = Object.assign(headers, obj); //合并obj
  306. return headers;
  307. }
  308.  
  309. //一个认证方案
  310. var Auth = (function () {
  311.  
  312. return function(username,password,remember)
  313. {
  314. if (!username) username = "";
  315. if (!password) password = "";
  316. if (!remember) remember = false;
  317. var auth = { //原始结构
  318. response:{
  319. access_token:"",
  320. expires_in:0,
  321. token_type:"",
  322. scope:"",
  323. refresh_token:"",
  324. user:{
  325. profile_image_urls:{
  326. px_16x16:"",
  327. px_50x50:"",
  328. px_170x170:"",
  329. },
  330. id:"",
  331. name:"",
  332. account:"",
  333. mail_address:"",
  334. is_premium:false,
  335. x_restrict:0,
  336. is_mail_authorized:true,
  337. },
  338. device_token:"",
  339. },
  340. needlogin:false,
  341. username:username,
  342. password:password,
  343. save_account:remember,
  344. login_date:null,
  345. }
  346. auth.newAccount = function(username,password,remember)
  347. {
  348. if(typeof(remember)=="boolean") auth.save_account = remember;
  349. auth.username = username;
  350. auth.password = password;
  351. }
  352. auth.loadFromResponse = function(response)
  353. {
  354. auth = Object.assign(auth, response);
  355. }
  356. auth.save = function()
  357. {
  358. var saveObj = JSON.parse(JSON.stringify(auth)); //深度拷贝
  359. if(!saveObj.save_account)
  360. {
  361. saveObj.username = "";
  362. saveObj.password = "";
  363. }
  364. GM_setValue("pubd-auth",JSON.stringify(saveObj));
  365. }
  366.  
  367. auth.login = function(onload_suceess_Cb,onload_hasError_Cb,onload_notJson_Cb,onerror_Cb)
  368. {
  369. var postObj = new PostDataObject({ //Post时发送的数据
  370. client_id:"BVO2E8vAAikgUBW8FYpi6amXOjQj",
  371. client_secret:"LI1WsFUDrrquaINOdarrJclCrkTtc3eojCOswlog",
  372. grant_type:"password",
  373. username:auth.username,
  374. password:auth.password,
  375. //device_token:"6e50367b155c2ba9faeaf2152ee4607c",
  376. get_secure_url:"true",
  377. })
  378. var device_token = docCookies.getItem("device_token");
  379. if (device_token) postObj.increase({"device_token": device_token});
  380.  
  381. //登陆是老的API
  382. GM_xmlhttpRequest({
  383. url:"https://oauth.secure.pixiv.net/auth/token",
  384. method:"post",
  385. responseType:"text",
  386. headers: new HeadersObject(),
  387. data: postObj.toPostString(),
  388. onload: function(response) {
  389. try
  390. {
  391. var jo = JSON.parse(response.responseText);
  392. if (jo.has_error || jo.errors)
  393. {
  394. console.error("登录失败,返回错误消息",jo);
  395. onload_hasError_Cb(jo);
  396. }else
  397. {//登陆成功
  398. auth.loadFromResponse(jo);
  399. auth.login_date = new Date();
  400. console.info("登陆成功",jo);
  401. onload_suceess_Cb(jo);
  402. }
  403. }catch(e)
  404. {
  405. console.error("登录失败,返回可能不是JSON,或程序异常",e,response);
  406. onload_notJson_Cb(response);
  407. }
  408. },
  409. onerror: function(response) {
  410. console.error("登录失败,AJAX发送失败",response);
  411. onerror_Cb(response);
  412. }
  413. })
  414. }
  415. return auth;
  416. };
  417. })();
  418.  
  419. //一个下载方案
  420. var DownScheme = (function () {
  421. //一个自定义掩码
  422. return function(name)
  423. {
  424. var obj = {
  425. name:name?name:"默认方案",
  426. rpcurl:"http://localhost:6800/jsonrpc",
  427. savedir:"D:/PivixDownload/",
  428. savepath:"%{illust.user.id}/%{illust.filename}%{page}.%{illust.extention}",
  429. masklist:[],
  430. mask:{
  431. add:function(name,logic,content){
  432. var mask = {
  433. name:name,
  434. logic:logic,
  435. content:content,
  436. };
  437. obj.masklist.push(mask);
  438. return mask;
  439. },
  440. remove:function(index){
  441. obj.masklist.splice(index, 1);
  442. },
  443. },
  444. loadFromJson:function(json)
  445. {
  446. if (typeof(json) == "string")
  447. {
  448. try
  449. {
  450. var json = JSON.parse(json);
  451. }catch(e)
  452. {
  453. console.error(e);
  454. return false;
  455. }
  456. }
  457. if (json.name) this.name = json.name;
  458. if (json.rpcurl) this.rpcurl = json.rpcurl;
  459. if (json.savedir) this.savedir = json.savedir;
  460. if (json.savepath) this.savepath = json.savepath;
  461. if (json.masklist) this.masklist = JSON.parse(JSON.stringify(json.masklist));
  462. return true;
  463. },
  464. }
  465. return obj;
  466. };
  467. })();
  468.  
  469. //创建菜单类
  470. var pubdMenu = (function () {
  471. //生成菜单项
  472. function buildMenuItem(title,classname,callback,submenu)
  473. {
  474. var item = document.createElement("li");
  475. item.subitem = null; //子菜单
  476. if (title == 0) //只添加一条线
  477. {
  478. item.className = "pubd-menu-line" + (classname?" "+classname:"");
  479. return item;
  480. }
  481. item.className = "pubd-menu-item" + (classname?" "+classname:"");
  482. //添加链接
  483. var a = document.createElement("a");
  484. a.className = "pubd-menu-item-a"
  485. //添加图标
  486. var icon = document.createElement("i");
  487. icon.className = "pubd-icon";
  488. a.appendChild(icon);
  489. //添加文字
  490. var span = document.createElement("span");
  491. span.className = "text";
  492. span.innerHTML = title;
  493. a.appendChild(span);
  494.  
  495. if (typeof(callback) == "string")
  496. {
  497. a.target = "_blank";
  498. a.href = callback;
  499. }
  500. else if (typeof(callback) == "function")
  501. {
  502. item.addEventListener("click",callback);
  503. //a.onclick = callback;
  504. }
  505. if (typeof(submenu) == "object")
  506. {
  507. item.classList.add("pubd-menu-includesub"); //表明该菜单项有子菜单
  508. submenu.classList.add("pubd-menu-submenu"); //表明该菜单是子菜单
  509. //a.addEventListener("mouseenter",function(){callback.show()});
  510. //a.addEventListener("mouseleave",function(){callback.hide()});
  511. item.appendChild(submenu);
  512. item.subitem = submenu;
  513. }
  514.  
  515. item.appendChild(a);
  516. return item;
  517. }
  518.  
  519. return function(touch,classname) {
  520. var menu = document.createElement("ul");
  521. menu.className = "pubd-menu display-none" + (classname?" "+classname:"");
  522. menu.item = new Array();
  523. //显示该菜单
  524. menu.show = function()
  525. {
  526. menu.classList.remove("display-none");
  527. }
  528. menu.hide = function()
  529. {
  530. menu.classList.add("display-none");
  531. }
  532. //添加菜单项
  533. menu.add = function(title,classname,callback,submenu)
  534. {
  535. var itm = buildMenuItem(title,classname,callback,submenu);
  536. this.appendChild(itm);
  537. this.item.push(itm)
  538. return itm;
  539. }
  540. //鼠标移出菜单时消失
  541. menu.addEventListener("mouseleave",function(e){
  542. this.hide();
  543. });
  544. return menu;
  545. };
  546. })();
  547.  
  548. //创建通用对话框类
  549. var Dialog = (function () {
  550. //构建标题栏按钮
  551. function buildDlgCptBtn(text,classname,callback)
  552. {
  553. if (!callback)classname="";
  554. var btn = document.createElement("a");
  555. btn.className = "dlg-cpt-btn" + (classname?" "+classname:"");
  556. if (typeof(callback) == "string")
  557. {
  558. btn.target = "_blank";
  559. btn.href = callback;
  560. }
  561. else
  562. {
  563. if (callback)
  564. btn.addEventListener("click",callback);
  565. }
  566. var btnTxt = document.createElement("div");
  567. btnTxt.className = "dlg-cpt-btn-text";
  568. btnTxt.innerHTML = text;
  569. btn.appendChild(btnTxt);
  570.  
  571. return btn;
  572. }
  573.  
  574. return function(caption,id,classname) {
  575. var dlg = document.createElement("div");
  576. dlg.className = "pubd-dialog display-none" + (classname?" "+classname:"");
  577.  
  578. //添加图标与标题
  579. var cpt = document.createElement("div");
  580. cpt.className = "caption";
  581. var icon = document.createElement("i");
  582. icon.className = "pubd-icon";
  583. cpt.appendChild(icon);
  584. var span = document.createElement("span");
  585. span.innerHTML = caption;
  586. cpt.appendChild(span);
  587. dlg.appendChild(cpt);
  588. dlg.caption = span;
  589. dlg.icon = icon;
  590.  
  591. //添加标题栏按钮
  592. var cptBtns = document.createElement("div");
  593. cptBtns.className = "dlg-cpt-btns";
  594. //添加关闭按钮
  595. cptBtns.add = function(text,classname,callback){
  596. var btn = buildDlgCptBtn(text,classname,callback);
  597. this.insertBefore(btn,this.firstChild);
  598. return btn;
  599. }
  600. cptBtns.close = cptBtns.add("X","dlg-btn-close",(function()
  601. {
  602. dlg.classList.add("display-none");
  603. }));
  604. dlg.appendChild(cptBtns);
  605. dlg.cptBtns = cptBtns; //captionButtons
  606.  
  607. //添加内容
  608. var content = document.createElement("div");
  609. content.className = "dlg-content";
  610. dlg.appendChild(content);
  611. dlg.content = content;
  612.  
  613. //窗口激活
  614. dlg.active = function()
  615. {
  616. if (!this.classList.contains("pubd-dlg-active"))
  617. {//如果没有激活的话才执行
  618. var dlgs = document.getElementsByClassName("pubd-dialog");
  619. for (var dlgi=0;dlgi<dlgs.length;dlgi++)
  620. {
  621. dlgs[dlgi].classList.remove("pubd-dlg-active");//取消激活
  622. dlgs[dlgi].style.zIndex = parseInt(window.getComputedStyle(dlgs[dlgi],null).getPropertyValue("z-index")) - 1;
  623. }
  624. this.style.zIndex = "";
  625. this.classList.add("pubd-dlg-active");//添加激活
  626. }
  627. }
  628. //窗口初始化
  629. dlg.initialise = function()
  630. {
  631. return;
  632. }
  633. //窗口显示
  634. dlg.show = function()
  635. {
  636. this.initialise();
  637. this.classList.remove("display-none");
  638. this.active();
  639. }
  640. //窗口隐藏
  641. dlg.hide = function()
  642. {
  643. this.cptBtns.close.click;
  644. }
  645. //添加鼠标拖拽移动
  646. dlg.drag = {disX: 0,disY: 0};
  647. //startDrag(cpt, dlg);
  648. cpt.addEventListener("mousedown",function(e){
  649. dlg.drag.disX = e.pageX - dlg.offsetLeft;
  650. dlg.drag.disY = e.pageY - dlg.offsetTop;
  651. var handler_mousemove = function (e) {
  652. dlg.style.left = (e.pageX - dlg.drag.disX) + 'px';
  653. dlg.style.top = (e.pageY - dlg.drag.disY) + 'px';
  654. };
  655. var handler_mouseup = function (e) {
  656. document.removeEventListener("mousemove",handler_mousemove);
  657. };
  658. document.addEventListener("mousemove",handler_mousemove);
  659. document.addEventListener("mouseup",handler_mouseup,{once:true});
  660. });
  661. //点击窗口激活窗口
  662. dlg.addEventListener("mousedown",function(e){
  663. dlg.active();
  664. });
  665. return dlg;
  666. };
  667. })();
  668.  
  669. //创建选项卡类
  670. var Tab = (function () {
  671.  
  672. return function(title) {
  673. var obj = {
  674. title:document.createElement("li"),
  675. content:document.createElement("li"),
  676. }
  677. obj.title = document.createElement("li");
  678. obj.title.className = "pubd-tab-title";
  679. obj.title.innerHTML = title;
  680. obj.name = function()
  681. {
  682. return this.title.textContent;
  683. }
  684. obj.rename = function(newName)
  685. {
  686. if (typeof(newName)=="string" && newName.length>0)
  687. {
  688. this.title.innerHTML = newName;
  689. return true;
  690. }else
  691. return false;
  692. }
  693.  
  694. obj.content.className = "pubd-tab-content";
  695. obj.content.innerHTML = "设置内容";
  696.  
  697. return obj;
  698. };
  699. })();
  700.  
  701. //创建复数选项卡类
  702. var Tabs = (function () {
  703.  
  704. return function() {
  705. var tabs = document.createElement("div");
  706. tabs.className = "pubd-tabs";
  707. tabs.item = new Array(); //储存卡
  708. //添加卡名区域
  709. var ult = document.createElement("ul");
  710. ult.className = "tab-title";
  711. tabs.appendChild(ult);
  712. //添加卡内容区域
  713. var ulc = document.createElement("ul");
  714. ulc.className = "tab-content";
  715. tabs.appendChild(ulc);
  716. tabs.add = function(name)
  717. {
  718. var tab = new Tab(name);
  719. tabs.item.push(tab);
  720. ult.appendChild(tab.title);
  721. ulc.appendChild(tab.content);
  722. }
  723. return tabs;
  724. };
  725. })();
  726.  
  727. //创建框架类
  728. var Frame = (function () {
  729.  
  730. return function(title,classname) {
  731. var frame = document.createElement("div");
  732. frame.className = "pubd-frame" + (classname?" "+classname:"");
  733. var caption = document.createElement("div");
  734. caption.className = "pubd-frame-caption";
  735. caption.innerHTML = title;
  736. frame.caption = caption;
  737. frame.appendChild(caption);
  738. var content = document.createElement("div");
  739. content.className = "pubd-frame-content";
  740. frame.content = content;
  741. frame.appendChild(content);
  742.  
  743. frame.name = function()
  744. {
  745. return this.caption.textContent;
  746. }
  747. frame.rename = function(newName)
  748. {
  749. if (typeof(newName)=="string" && newName.length>0)
  750. {
  751. this.caption.innerHTML = newName;
  752. return true;
  753. }else
  754. return false;
  755. }
  756.  
  757. return frame;
  758. };
  759. })();
  760.  
  761. //创建带Label的Input类
  762. var LabelInput = (function () {
  763.  
  764. return function(text,classname,name,type,value,beforeText) {
  765. var label = document.createElement("label");
  766. label.innerHTML = text;
  767. label.className = classname;
  768.  
  769. var ipt = document.createElement("input");
  770. ipt.name = name;
  771. ipt.id = ipt.name;
  772. ipt.type = type;
  773. ipt.value = value;
  774.  
  775. label.input = ipt;
  776. if (beforeText)
  777. label.insertBefore(ipt,label.firstChild);
  778. else
  779. label.appendChild(ipt);
  780. return label;
  781. };
  782. })();
  783.  
  784. //创建进度条类
  785. var Progress = (function () {
  786. //强制保留pos位小数,如:2,会在2后面补上00.即2.00
  787. function toDecimal2(num,pos) {
  788. var f = parseFloat(num);
  789. if (isNaN(f)) {
  790. return false;
  791. }
  792. var f = Math.round(num*Math.pow(10,pos))/Math.pow(10,pos);
  793. var s = f.toString();
  794. var rs = s.indexOf('.');
  795. if (pos > 0 && rs < 0) {
  796. rs = s.length;
  797. s += '.';
  798. }
  799. while (s.length <= rs + pos) {
  800. s += '0';
  801. }
  802. return s;
  803. }
  804.  
  805. return function(classname,align_right) {
  806. var progress = document.createElement("div");
  807. progress.className = "pubd-progress" + (classname?" "+classname:"");
  808. if (align_right) progress.classList.add("pubd-progress-right");
  809.  
  810. progress.scaleNum = 0;
  811.  
  812. var bar = document.createElement("div");
  813. bar.className = "pubd-progress-bar";
  814. progress.appendChild(bar);
  815.  
  816. var txt = document.createElement("span");
  817. txt.className = "pubd-progress-text";
  818. progress.appendChild(txt);
  819.  
  820. progress.set = function(scale,pos,str)
  821. {
  822. if (!pos) pos = 2;
  823. var percentStr = toDecimal2((scale * 100),pos) + "%";
  824. scale = scale>1?1:(scale<0?0:scale);
  825. this.scaleNum = scale;
  826. bar.style.width = percentStr;
  827. if (str)
  828. txt.innerHTML = str;
  829. else
  830. txt.innerHTML = percentStr;
  831. }
  832. progress.scale = function()
  833. {
  834. return this.scaleNum;
  835. }
  836.  
  837. return progress;
  838. };
  839. })();
  840.  
  841. //创建用户卡片类
  842. var UserCard = (function () {
  843.  
  844. return function(userid) {
  845. var uinfo = document.createElement("div");
  846. uinfo.userid = userid;
  847. uinfo.className = "pubd-user-info";
  848. var uhead = document.createElement("div");
  849. uhead.className = "pubd-user-info-head";
  850. uinfo.appendChild(uhead);
  851. var uhead_img = document.createElement("img");
  852. uinfo.uhead = uhead_img;
  853. uhead.appendChild(uhead_img);
  854. uinfo.uhead = uhead_img;
  855.  
  856. var infos = document.createElement("dl");
  857. infos.className = "pubd-user-info-dl";
  858. //ID
  859. var dt=document.createElement("dt");
  860. dt.className = "pubd-user-info-id-dt";
  861. dt.innerHTML = "ID"
  862. infos.appendChild(dt);
  863. var dd=document.createElement("dd");
  864. dd.className = "pubd-user-info-id-dd";
  865. dd.innerHTML = uinfo.userid;
  866. uinfo.uid = dd;
  867. infos.appendChild(dd);
  868. //作品数
  869. var dt=document.createElement("dt");
  870. dt.className = "pubd-user-info-illusts-dt";
  871. dt.innerHTML = "作品投稿数"
  872. infos.appendChild(dt);
  873. var dd=document.createElement("dd");
  874. dd.className = "pubd-user-info-illusts-dd";
  875. uinfo.uillusts = dd;
  876. infos.appendChild(dd);
  877. //昵称
  878. var dt=document.createElement("dt");
  879. dt.className = "pubd-user-info-name-dt";
  880. dt.innerHTML = "昵称"
  881. infos.appendChild(dt);
  882. var dd=document.createElement("dd");
  883. dd.className = "pubd-user-info-name-dd";
  884. uinfo.uname = dd;
  885. infos.appendChild(dd);
  886. //收藏数
  887. var dt=document.createElement("dt");
  888. dt.className = "pubd-user-info-bookmarks-dt";
  889. dt.innerHTML = "插画收藏数"
  890. infos.appendChild(dt);
  891. var dd=document.createElement("dd");
  892. dd.className = "pubd-user-info-bookmarks-dd";
  893. uinfo.ubookmarks = dd;
  894. infos.appendChild(dd);
  895.  
  896. uinfo.infos = infos;
  897. uinfo.appendChild(infos);
  898.  
  899. uinfo.set = function(obj)
  900. {
  901. if (obj.id)
  902. {
  903. uinfo.userid = obj.id;
  904. uinfo.uid.innerHTML = obj.id;
  905. }
  906. if (obj.head) uinfo.uhead.src = obj.head;
  907. if (obj.name) uinfo.uname.innerHTML = obj.name;
  908. if (obj.illusts) uinfo.uillusts.innerHTML = obj.illusts;
  909. if (obj.bookmarks) uinfo.ubookmarks.innerHTML = obj.bookmarks;
  910. }
  911. return uinfo;
  912. };
  913. })();
  914.  
  915. //创建下拉框类
  916. var Select = (function () {
  917. return function(classname,name) {
  918. var select = document.createElement("select");
  919. select.className = "pubd-select" + (classname?" "+classname:"");
  920. select.name = name;
  921. select.id = select.name;
  922.  
  923. select.add = function(text,value)
  924. {
  925. var opt = new Option(text, value);
  926. this.options.add(opt);
  927. }
  928. select.remove = function(index)
  929. {
  930. this.options.remove(index);
  931. }
  932.  
  933. return select;
  934. };
  935. })();
  936.  
  937. //创建Aria2类
  938. var Aria2 = (function () {
  939. var jsonrpc_version = '2.0';
  940.  
  941. function get_auth(url) {
  942. return url.match(/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(?:\/\/)?(?:([^:@]*(?::[^:@]*)?)?@)?/)[1];
  943. };
  944.  
  945. function request(jsonrpc_path, method, params, callback, priority) {
  946. if (callback==undefined) callback = function(){return;}
  947. var auth = get_auth(jsonrpc_path);
  948. jsonrpc_path = jsonrpc_path.replace(/^((?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(\/\/)?(?:(?:[^:@]*(?::[^:@]*)?)?@)?(.*)/, '$1$2$3'); // auth string not allowed in url for firefox
  949.  
  950. var request_obj = {
  951. jsonrpc: jsonrpc_version,
  952. method: method,
  953. id: priority ? "1" : (new Date()).getTime().toString(),
  954. };
  955. if (params) request_obj['params'] = params;
  956. if (auth && auth.indexOf('token:') == 0) params.unshift(auth);
  957.  
  958. var headers = {"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",}
  959. if (auth && auth.indexOf('token:') != 0) {
  960. headers.Authorization = "Basic " + btoa(auth);
  961. }
  962. GM_xmlhttpRequest({
  963. url: jsonrpc_path + "?tm=" + (new Date()).getTime().toString(),
  964. method:"POST",
  965. responseType:"text",
  966. data:JSON.stringify(request_obj),
  967. headers: headers,
  968. onload: function(response) {
  969. try
  970. {
  971. var JSONreq = JSON.parse(response.response);
  972. callback(JSONreq);
  973. }catch(e)
  974. {
  975. console.error("Aria2发送信息错误",e,response);
  976. callback(false);
  977. }
  978. },
  979. onerror: function(response) {
  980. console.error(response);
  981. callback(false);
  982. }
  983. })
  984. };
  985.  
  986. return function (jsonrpc_path) {
  987. this.jsonrpc_path = jsonrpc_path;
  988. this.addUri = function (uri, options, callback) {
  989. request(this.jsonrpc_path, 'aria2.addUri', [[uri, ], options], callback);
  990. };
  991. this.addTorrent = function (base64txt, options, callback)
  992. {
  993. request(this.jsonrpc_path, 'aria2.addTorrent', [base64txt, [], options], callback);
  994. };
  995. this.getVersion = function (callback) {
  996. request(this.jsonrpc_path, 'aria2.getVersion', [], callback, true);
  997. };
  998. this.getGlobalOption = function (callback) {
  999. request(this.jsonrpc_path, 'aria2.getGlobalOption', [], callback, true);
  1000. };
  1001. return this;
  1002. }
  1003. })();
  1004.  
  1005. /*
  1006. * 自定义函数区
  1007. */
  1008. //构建开始按钮
  1009. function buildbtnStart(touch)
  1010. {
  1011. if (touch) //手机版
  1012. {
  1013.  
  1014. }else
  1015. {
  1016. var btnStart = document.createElement("a");
  1017. btnStart.id = "pubd-start";
  1018. btnStart.className = "pubd-start";
  1019. //添加图标
  1020. var icon = document.createElement("i");
  1021. icon.className = "pubd-icon";
  1022. btnStart.appendChild(icon);
  1023. //添加文字
  1024. var span = document.createElement("span");
  1025. span.className = "text";
  1026. span.innerHTML = "使用PUBD扒图";
  1027. btnStart.appendChild(span);
  1028.  
  1029. //鼠标移入和按下都起作用
  1030. //btnStart.addEventListener("mouseenter",function(){pubd.menu.show()});
  1031. btnStart.addEventListener("click",function(){pubd.menu.classList.toggle("display-none")});
  1032. }
  1033. return btnStart;
  1034. }
  1035.  
  1036. //构建菜单
  1037. function buildbtnMenu(touch)
  1038. {
  1039. if (touch) //手机版
  1040. {
  1041.  
  1042. }else
  1043. {
  1044. var menu2 = new pubdMenu(touch);
  1045. menu2.add("子菜单1","",function(){alert("子菜单1")});
  1046. menu2.add("子菜单2","",function(){alert("子菜单2")});
  1047. var menu1 = new pubdMenu(touch);
  1048. menu1.add("子菜单1","",function(){alert("子菜单1")});
  1049. menu1.add("子菜单2","",null,menu2);
  1050. var menu3 = new pubdMenu(touch);
  1051. menu3.add("子菜单1","",function(){alert("子菜单1")});
  1052. menu3.add("子菜单2","",function(){alert("子菜单2")});
  1053. menu3.add("子菜单2","",function(){alert("子菜单3")});
  1054. menu3.add("子菜单2","",function(){alert("子菜单4")});
  1055. var menu4 = new pubdMenu(touch);
  1056. menu4.add("子菜单1","",null,menu3);
  1057. menu4.add("子菜单2","",function(){alert("子菜单2")});
  1058. menu4.add("子菜单2","",function(){alert("子菜单5")});
  1059. menu4.add("子菜单2","",function(){alert("子菜单6")});
  1060.  
  1061. var menu = new pubdMenu(touch,"pubd-menu-main");
  1062. menu.id = "pubd-menu";
  1063. menu.add("下载该画师","",function()
  1064. {
  1065. pubd.dialog.downthis.show();
  1066. menu.hide();
  1067. }
  1068. );
  1069. menu.add("占位用","",null,menu1);
  1070. menu.add("没功能","",null,menu4);
  1071. menu.add("多个画师下载",null,function()
  1072. {//做成“声音”的设备样子
  1073. alert("这个功能也没有开发")
  1074. }
  1075. );
  1076. menu.add(0);
  1077. menu.add("选项","pubd-menu-setting",function()
  1078. {
  1079. pubd.dialog.config.show();
  1080. menu.hide();
  1081. }
  1082. );
  1083. }
  1084. return menu;
  1085. }
  1086.  
  1087. //构建设置对话框
  1088. function buildDlgConfig(touch)
  1089. {
  1090. var dlg = new Dialog("PUBD选项 v" + scriptVersion,"pubd-config","pubd-config");
  1091. dlg.cptBtns.add("反馈","dlg-btn-debug","https://github.com/Mapaler/PixivUserBatchDownload/issues");
  1092. dlg.cptBtns.add("?","dlg-btn-help","https://github.com/Mapaler/PixivUserBatchDownload/tree/develop_v5");
  1093. dlg.token_ani = null; //储存Token进度条动画句柄
  1094. var dlgc = dlg.content;
  1095.  
  1096. var dl=document.createElement("dl");
  1097. dlgc.appendChild(dl);
  1098. var dt=document.createElement("dt");
  1099. dl.appendChild(dt);
  1100. dt.innerHTML = "Pixiv访问权限,默认仅能访问公开作品";
  1101. var dd=document.createElement("dd");
  1102. var checkbox = new LabelInput("开启登陆功能,解除浏览限制","pubd-needlogin","pubd-needlogin","checkbox","1",true);
  1103. dlg.needlogin = checkbox.input;
  1104. dlg.needlogin.onclick = function()
  1105. {
  1106. if (dlg.needlogin.checked)
  1107. {
  1108. dlg.token_info.classList.remove("height-none");
  1109. dlg.start_token_animate();
  1110. }else
  1111. {
  1112. dlg.token_info.classList.add("height-none");
  1113. dlg.stop_token_animate();
  1114. }
  1115. pubd.dialog.login.cptBtns.close.click();
  1116. }
  1117. dd.appendChild(checkbox);
  1118.  
  1119. var a_setting = document.createElement("a");
  1120. a_setting.className = "pubd-browsing-restriction";
  1121. a_setting.href = "http://www.pixiv.net/setting_user.php#over-18";
  1122. a_setting.target = "_blank";
  1123. a_setting.innerHTML = "设置我的账户浏览限制";
  1124. dd.appendChild(a_setting);
  1125. dl.appendChild(dd);
  1126. var dd=document.createElement("dd");
  1127. dd.className = "pubd-token-info height-none";
  1128. dlg.token_info = dd;
  1129. var progress = new Progress("pubd-token-expires",true);
  1130. dlg.token_expires = progress;
  1131. dd.appendChild(progress);
  1132. //开始动画
  1133. dlg.start_token_animate = function()
  1134. {
  1135. //if (!dlg.classList.contains("display-none"))
  1136. //{
  1137. dlg.stop_token_animate();
  1138. requestAnimationFrame(token_animate);
  1139. dlg.token_ani = setInterval(function () {requestAnimationFrame(token_animate)}, 1000);
  1140. //}
  1141. }
  1142. //停止动画
  1143. dlg.stop_token_animate = function()
  1144. {
  1145. clearInterval(dlg.token_ani);
  1146. }
  1147. //动画具体实现
  1148. function token_animate()
  1149. {
  1150. var nowdate = new Date();
  1151. var olddate = new Date(pubd.auth.login_date);
  1152. var expires_in = parseInt(pubd.auth.response.expires_in);
  1153. var differ = expires_in - (nowdate - olddate)/1000;
  1154. var scale = differ / expires_in;
  1155. if (differ>0)
  1156. {
  1157. progress.set(scale,2,"Token有效剩余" + parseInt(differ) + "秒");
  1158. }else
  1159. {
  1160. progress.set(0,2,"Token已失效,请重新登录");
  1161. clearInterval(dlg.token_ani);
  1162. }
  1163. //console.log("Token有效剩余" + differ + "秒"); //检测动画后台是否停止
  1164. }
  1165.  
  1166. var ipt = document.createElement("input");
  1167. ipt.type = "button";
  1168. ipt.className = "pubd-tologin";
  1169. ipt.value = "账户登陆"
  1170. ipt.onclick = function()
  1171. {
  1172. pubd.dialog.login.show();
  1173. }
  1174. dd.appendChild(ipt);
  1175. dl.appendChild(dd);
  1176.  
  1177. //“下载该画师”窗口选项
  1178. var dt=document.createElement("dt");
  1179. dl.appendChild(dt);
  1180. var dd=document.createElement("dd");
  1181.  
  1182. var frm = new Frame("“下载该画师”窗口","pubd-frmdownthis");
  1183. var chk_autoanalyse = new LabelInput("打开窗口时自动获取","pubd-autoanalyse","pubd-autoanalyse","checkbox","1",true);
  1184. dlg.autoanalyse = chk_autoanalyse.input;
  1185. var chk_autodownload = new LabelInput("获取完成后自动下载","pubd-autodownload","pubd-autodownload","checkbox","1",true);
  1186. dlg.autodownload = chk_autodownload.input;
  1187.  
  1188. frm.content.appendChild(chk_autoanalyse);
  1189. frm.content.appendChild(chk_autodownload);
  1190. dd.appendChild(frm);
  1191. dl.appendChild(dd);
  1192.  
  1193. /*
  1194. //选项卡栏
  1195. var dt=document.createElement("dt");
  1196. dl.appendChild(dt);
  1197. var dd=document.createElement("dd");
  1198. dd.className = "pubd-config-tab"
  1199. var tabs = new Tabs();
  1200. tabs.add("第一选项卡");
  1201. tabs.add("第二选项卡");
  1202. dd.appendChild(tabs);
  1203. dl.appendChild(dd);
  1204. */
  1205. //配置方案储存
  1206. dlg.schemes = null;
  1207. dlg.reloadSchemes = function()
  1208. {//重新读取所有下载方案
  1209. dlg.downScheme.options.length = 0;
  1210. dlg.schemes.forEach(function(item,index){
  1211. dlg.downScheme.add(item.name,index);
  1212. })
  1213. if (dlg.downScheme.options.length > 0)
  1214. dlg.selectScheme(0);
  1215. }
  1216. dlg.loadScheme = function(scheme)
  1217. {//读取一个下载方案
  1218. if (scheme == undefined)
  1219. {
  1220. dlg.rpcurl.value = "";
  1221. dlg.savedir.value = "";
  1222. dlg.savepath.value = "";
  1223. dlg.loadMasklistFromArray([]);
  1224. }else
  1225. {
  1226. dlg.rpcurl.value = scheme.rpcurl;
  1227. dlg.savedir.value = scheme.savedir;
  1228. dlg.savepath.value = scheme.savepath;
  1229. dlg.loadMasklistFromArray(scheme.masklist);
  1230. }
  1231. }
  1232. dlg.addMask = function(name,logic,content,value)
  1233. {//向掩码列表添加一个新的掩码
  1234. if (value == undefined)
  1235. value = dlg.masklist.options.length;
  1236. var text = name + " : " + logic + " : " + content;
  1237. var opt = new Option(text, value);
  1238. dlg.masklist.options.add(opt);
  1239. }
  1240. dlg.loadMask = function(mask)
  1241. {//读取一个掩码到三个文本框,只是用来查看
  1242. dlg.mask_name.value = mask.name;
  1243. dlg.mask_logic.value = mask.logic;
  1244. dlg.mask_content.value = mask.content;
  1245. }
  1246. dlg.loadMasklistFromArray = function(masklist)
  1247. {//从掩码数组重置掩码列表
  1248. dlg.masklist.length = 0;
  1249. masklist.forEach(function(item,index){
  1250. dlg.addMask(item.name,item.logic,item.content,index);
  1251. })
  1252. }
  1253. //选择一个方案,同时读取设置
  1254. dlg.selectScheme = function(index)
  1255. {
  1256. if (index == undefined) index=0;
  1257. if (dlg.downScheme.options.length<1 || dlg.downScheme.selectedOptions.length<1){return;}
  1258. var scheme = dlg.schemes[index];
  1259. dlg.loadScheme(scheme);
  1260. dlg.downScheme.selectedIndex = index;
  1261. }
  1262. //选择一个掩码,同时读取设置
  1263. dlg.selectMask = function(index)
  1264. {
  1265. if (dlg.downScheme.options.length<1 || dlg.downScheme.selectedOptions.length<1){return;}
  1266. if (dlg.masklist.options.length<1 || dlg.masklist.selectedOptions.length<1){return;}
  1267. var scheme = dlg.schemes[dlg.downScheme.selectedIndex];
  1268. var mask = scheme.masklist[index];
  1269. dlg.loadMask(mask);
  1270. dlg.masklist.selectedIndex = index;
  1271. }
  1272. //配置方案选择
  1273. var dt=document.createElement("dt");
  1274. dt.innerHTML = "选择下载方案";
  1275. dl.appendChild(dt);
  1276. var dd=document.createElement("dd");
  1277. var slt = new Select("pubd-downscheme");
  1278. slt.onchange = function()
  1279. {
  1280. dlg.selectScheme(this.selectedIndex);
  1281. };
  1282. dlg.downScheme = slt;
  1283. dd.appendChild(slt);
  1284. var ipt = document.createElement("input");
  1285. ipt.type = "button";
  1286. ipt.className = "pubd-downscheme-new";
  1287. ipt.value = "新建"
  1288. ipt.onclick = function()
  1289. {
  1290. var schemName = prompt("请输入方案名","我的方案");
  1291. var scheme = new DownScheme(schemName);
  1292. var length = dlg.schemes.push(scheme);
  1293. dlg.downScheme.add(scheme.name,length-1);
  1294. dlg.downScheme.selectedIndex = length-1;
  1295. dlg.loadScheme(scheme);
  1296. console.log(scheme);
  1297. //dlg.reloadSchemes();
  1298. }
  1299. dd.appendChild(ipt);
  1300.  
  1301. var ipt = document.createElement("input");
  1302. ipt.type = "button";
  1303. ipt.className = "pubd-downscheme-remove";
  1304. ipt.value = "删除"
  1305. ipt.onclick = function()
  1306. {
  1307. if (dlg.downScheme.options.length < 1){alert("已经没有方案了");return;}
  1308. if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中方案");return;}
  1309. var index = dlg.downScheme.selectedIndex;
  1310. dlg.schemes.splice(index, 1);
  1311. dlg.downScheme.remove(index);
  1312. var index = dlg.downScheme.selectedIndex;
  1313. if (index<0) dlg.reloadSchemes();//没有选中的,重置
  1314. else dlg.loadScheme(dlg.schemes[index]);
  1315. }
  1316. dd.appendChild(ipt);
  1317. dl.appendChild(dd);
  1318.  
  1319. //Aria2 URL
  1320.  
  1321. var dt=document.createElement("dt");
  1322. dl.appendChild(dt);
  1323. dt.innerHTML = "Aria2 JSON-RPC 路径"
  1324. var rpcchk = document.createElement("span"); //显示检查状态用
  1325. rpcchk.className = "pubd-rpcchk-info";
  1326. dlg.rpcchk = rpcchk;
  1327. dlg.rpcchk.runing = false;
  1328. dt.appendChild(rpcchk);
  1329. var dd=document.createElement("dd");
  1330. var rpcurl = document.createElement("input");
  1331. rpcurl.type = "url";
  1332. rpcurl.className = "pubd-rpcurl";
  1333. rpcurl.name = "pubd-rpcurl";
  1334. rpcurl.id = rpcurl.name;
  1335. rpcurl.placeholder = "Aria2的信息接收路径"
  1336. rpcurl.onchange = function()
  1337. {
  1338. dlg.rpcchk.innerHTML = "";
  1339. dlg.rpcchk.runing = false;
  1340. if (dlg.downScheme.selectedOptions.length < 1){return;}
  1341. var schemeIndex = dlg.downScheme.selectedIndex;
  1342. dlg.schemes[schemeIndex].rpcurl = rpcurl.value;
  1343. }
  1344. dlg.rpcurl = rpcurl;
  1345. dd.appendChild(rpcurl);
  1346.  
  1347. var ipt = document.createElement("input");
  1348. ipt.type = "button";
  1349. ipt.className = "pubd-rpcchk";
  1350. ipt.value = "检查路径"
  1351. ipt.onclick = function()
  1352. {
  1353. if (dlg.rpcchk.runing) return;
  1354. if (dlg.rpcurl.value.length < 1)
  1355. {
  1356. dlg.rpcchk.innerHTML = "路径为空";
  1357. return;
  1358. }
  1359. dlg.rpcchk.innerHTML = "正在连接...";
  1360. dlg.rpcchk.runing = true;
  1361. var aria2 = new Aria2(dlg.rpcurl.value);
  1362. aria2.getVersion(function (rejo){
  1363. if (rejo)
  1364. dlg.rpcchk.innerHTML="发现Aria2 ver" + rejo.result.version;
  1365. else
  1366. dlg.rpcchk.innerHTML="Aria2连接失败";
  1367. dlg.rpcchk.runing = false;
  1368. });
  1369. }
  1370. dd.appendChild(ipt);
  1371. dl.appendChild(dd);
  1372.  
  1373. //下载目录
  1374. var dt=document.createElement("dt");
  1375. dl.appendChild(dt);
  1376. dt.innerHTML = "下载目录"
  1377. var dd=document.createElement("dd");
  1378. var savedir = document.createElement("input");
  1379. savedir.type = "url";
  1380. savedir.className = "pubd-savedir";
  1381. savedir.name = "pubd-savedir";
  1382. savedir.id = savedir.name;
  1383. savedir.placeholder = "文件下载到的目录"
  1384. savedir.onchange = function()
  1385. {
  1386. if (dlg.downScheme.selectedOptions.length < 1){return;}
  1387. var schemeIndex = dlg.downScheme.selectedIndex;
  1388. dlg.schemes[schemeIndex].savedir = savedir.value;
  1389. }
  1390. dlg.savedir = savedir;
  1391. dd.appendChild(savedir);
  1392. dl.appendChild(dd);
  1393.  
  1394. //保存路径
  1395. var dt=document.createElement("dt");
  1396. dl.appendChild(dt);
  1397. dt.innerHTML = "保存路径"
  1398. var dd=document.createElement("dd");
  1399. var savepath = document.createElement("input");
  1400. savepath.type = "text";
  1401. savepath.className = "pubd-savepath";
  1402. savepath.name = "pubd-savedir";
  1403. savepath.id = savepath.name;
  1404. savepath.placeholder = "分组保存的文件夹和文件名"
  1405. savepath.onchange = function()
  1406. {
  1407. if (dlg.downScheme.selectedOptions.length < 1){return;}
  1408. var schemeIndex = dlg.downScheme.selectedIndex;
  1409. dlg.schemes[schemeIndex].savepath = savepath.value;
  1410. }
  1411. dlg.savepath = savepath;
  1412. dd.appendChild(savepath);
  1413. dl.appendChild(dd);
  1414.  
  1415. //自定义掩码
  1416. var dt=document.createElement("dt");
  1417. dl.appendChild(dt);
  1418. dt.innerHTML = "自定义掩码"
  1419. var dd=document.createElement("dd");
  1420. dl.appendChild(dd);
  1421. //▼掩码名
  1422. var ipt = document.createElement("input");
  1423. ipt.type = "text";
  1424. ipt.className = "pubd-mask-name";
  1425. ipt.name = "pubd-mask-name";
  1426. ipt.id = ipt.name;
  1427. ipt.placeholder = "自定义掩码名";
  1428. dlg.mask_name = ipt;
  1429. dd.appendChild(ipt);
  1430. //▲掩码名
  1431. //▼执行条件
  1432. var ipt = document.createElement("input");
  1433. ipt.type = "text";
  1434. ipt.className = "pubd-mask-logic";
  1435. ipt.name = "pubd-mask-logic";
  1436. ipt.id = ipt.name;
  1437. ipt.placeholder = "执行条件";
  1438. dlg.mask_logic = ipt;
  1439. dd.appendChild(ipt);
  1440. //▲执行条件
  1441. var ipt = document.createElement("input");
  1442. ipt.type = "button";
  1443. ipt.className = "pubd-mask-add";
  1444. ipt.value = "+";
  1445. ipt.onclick = function()
  1446. {//增加自定义掩码
  1447. if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中下载方案");return;}
  1448. if (dlg.mask_name.value.length < 1){alert("掩码名称为空");return;}
  1449. if (dlg.mask_logic.value.length < 1){alert("执行条件为空");return;}
  1450. var schemeIndex = dlg.downScheme.selectedIndex;
  1451. dlg.schemes[schemeIndex].mask.add(dlg.mask_name.value,dlg.mask_logic.value,dlg.mask_content.value);
  1452. dlg.addMask(dlg.mask_name.value,dlg.mask_logic.value,dlg.mask_content.value);
  1453. dlg.mask_name.value = dlg.mask_logic.value = dlg.mask_content.value = "";
  1454. }
  1455. dd.appendChild(ipt);
  1456. var mask_remove = document.createElement("input");
  1457. mask_remove.type = "button";
  1458. mask_remove.className = "pubd-mask-remove";
  1459. mask_remove.value = "-";
  1460. mask_remove.onclick = function()
  1461. {//删除自定义掩码
  1462. if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中下载方案");return;}
  1463. if (dlg.masklist.options.length < 1){alert("已经没有掩码了");return;}
  1464. if (dlg.masklist.selectedOptions.length < 1){alert("没有选中掩码");return;}
  1465. var schemeIndex = dlg.downScheme.selectedIndex;
  1466. var maskIndex = dlg.masklist.selectedIndex;
  1467. dlg.schemes[schemeIndex].mask.remove(maskIndex);
  1468. dlg.masklist.remove(maskIndex);
  1469. for (var mi=maskIndex;mi<dlg.masklist.options.length;mi++)
  1470. {
  1471. dlg.masklist.options[mi].value = mi;
  1472. }
  1473. }
  1474. dd.appendChild(mask_remove);
  1475.  
  1476. //▼掩码内容
  1477. var ipt = document.createElement("input");
  1478. ipt.type = "text";
  1479. ipt.className = "pubd-mask-content";
  1480. ipt.name = "pubd-mask-content";
  1481. ipt.id = ipt.name;
  1482. ipt.placeholder = "掩码内容";
  1483. dlg.mask_content = ipt;
  1484. dd.appendChild(ipt);
  1485. //▲掩码内容
  1486. dl.appendChild(dd);
  1487. //▼掩码列表
  1488. var dd=document.createElement("dd");
  1489. var masklist = new Select("pubd-mask-list")
  1490. masklist.size = 5;
  1491. masklist.onchange = function()
  1492. {//读取选中的掩码
  1493. dlg.selectMask(this.selectedIndex);
  1494. }
  1495. dlg.masklist = masklist;
  1496. dd.appendChild(masklist);
  1497. //▲掩码列表
  1498. dl.appendChild(dd);
  1499.  
  1500. //保存按钮栏
  1501. var dt=document.createElement("dt");
  1502. dl.appendChild(dt);
  1503. var dd=document.createElement("dd");
  1504. dd.className = "pubd-config-savebar"
  1505. var ipt = document.createElement("input");
  1506. ipt.type = "button";
  1507. ipt.className = "pubd-reset";
  1508. ipt.value = "重置"
  1509. ipt.onclick = function()
  1510. {
  1511. dlg.reset();
  1512. }
  1513. dd.appendChild(ipt);
  1514. var ipt = document.createElement("input");
  1515. ipt.type = "button";
  1516. ipt.className = "pubd-save";
  1517. ipt.value = "保存设置"
  1518. ipt.onclick = function()
  1519. {
  1520. dlg.save();
  1521. }
  1522. dd.appendChild(ipt);
  1523. dl.appendChild(dd);
  1524.  
  1525. //保存设置函数
  1526. dlg.save = function()
  1527. {
  1528. spawnNotification("设置已保存", scriptIcon, scriptName);
  1529. pubd.auth.needlogin = dlg.needlogin.checked;
  1530. pubd.auth.save();
  1531. GM_setValue("pubd-autoanalyse",dlg.autoanalyse.checked); //自动分析
  1532. GM_setValue("pubd-autodownload",dlg.autodownload.checked); //自动下载
  1533. var schemesStr = JSON.stringify(dlg.schemes);
  1534. GM_setValue("pubd-downschemes",schemesStr); //下载方案
  1535. GM_setValue("pubd-defaultscheme",dlg.downScheme.selectedIndex); //默认方案
  1536. pubd.downSchemes = NewDownSchemeArrayFromJson(dlg.schemes);
  1537. }
  1538. //重置设置函数
  1539. dlg.reset = function()
  1540. {
  1541. spawnNotification("设置已重置", scriptIcon, scriptName);
  1542. GM_deleteValue("pubd-auth"); //登陆相关信息
  1543. GM_deleteValue("pubd-autoanalyse"); //自动分析
  1544. GM_deleteValue("pubd-autodownload"); //自动下载
  1545. GM_deleteValue("pubd-downschemes"); //下载方案
  1546. GM_deleteValue("pubd-defaultscheme");//默认方案
  1547. }
  1548. //窗口关闭
  1549. dlg.close = function(){
  1550. dlg.stop_token_animate();
  1551. };
  1552. //关闭窗口按钮
  1553. dlg.cptBtns.close.addEventListener("click",dlg.close);
  1554. //窗口初始化
  1555. dlg.initialise = function(){
  1556. dlg.needlogin.checked = pubd.auth.needlogin;
  1557. if (pubd.auth.needlogin) //如果要登陆,就显示Token区域,和动画
  1558. {
  1559. dlg.token_info.classList.remove("height-none");
  1560. dlg.start_token_animate();
  1561. }
  1562. else
  1563. {
  1564. dlg.token_info.classList.add("height-none");
  1565. }
  1566. dlg.autoanalyse.checked = GM_getValue("pubd-autoanalyse");
  1567. dlg.autodownload.checked = GM_getValue("pubd-autodownload");
  1568.  
  1569. dlg.schemes = NewDownSchemeArrayFromJson(pubd.downSchemes);
  1570. dlg.reloadSchemes();
  1571. dlg.selectScheme(GM_getValue("pubd-defaultscheme"));
  1572. //ipt_token.value = pubd.auth.response.access_token;
  1573. };
  1574. return dlg;
  1575. }
  1576.  
  1577. //构建登陆对话框
  1578. function buildDlgLogin(touch)
  1579. {
  1580. var dlg = new Dialog("登陆账户","pubd-login","pubd-login");
  1581.  
  1582. var dlgc = dlg.content;
  1583. //Logo部分
  1584. var logo_box = document.createElement("div");
  1585. logo_box.className = "logo-box";
  1586. var logo = document.createElement("div");
  1587. logo.className = "logo";
  1588. logo_box.appendChild(logo);
  1589. var catchphrase = document.createElement("div");
  1590. catchphrase.className = "catchphrase";
  1591. catchphrase.innerHTML = "登陆获取你的账户通行证,解除年龄限制"
  1592. logo_box.appendChild(catchphrase);
  1593. dlgc.appendChild(logo_box);
  1594. //实际登陆部分
  1595. var container_login = document.createElement("div");
  1596. container_login.className = "container-login";
  1597.  
  1598. var input_field_group = document.createElement("div");
  1599. input_field_group.className = "input-field-group";
  1600. container_login.appendChild(input_field_group);
  1601. var input_field1 = document.createElement("div");
  1602. input_field1.className = "input-field";
  1603. var pid = document.createElement("input");
  1604. pid.type = "text";
  1605. pid.className = "pubd-account";
  1606. pid.name = "pubd-account";
  1607. pid.id = pid.name;
  1608. pid.placeholder="邮箱地址/pixiv ID";
  1609. dlg.pid = pid;
  1610. input_field1.appendChild(pid);
  1611. input_field_group.appendChild(input_field1);
  1612. var input_field2 = document.createElement("div");
  1613. input_field2.className = "input-field";
  1614. var pass = document.createElement("input");
  1615. pass.type = "password";
  1616. pass.className = "pubd-password";
  1617. pass.name = "pubd-password";
  1618. pass.id =pass.name;
  1619. pass.placeholder="密码";
  1620. dlg.pass = pass;
  1621. input_field2.appendChild(pass);
  1622. input_field_group.appendChild(input_field2);
  1623.  
  1624. var error_msg_list = document.createElement("ul"); //登陆错误信息
  1625. error_msg_list.className = "error-msg-list";
  1626. container_login.appendChild(error_msg_list);
  1627.  
  1628. var submit = document.createElement("button");
  1629. submit.className = "submit";
  1630. submit.innerHTML = "登陆"
  1631. container_login.appendChild(submit);
  1632.  
  1633. var signup_form_nav = document.createElement("div");
  1634. signup_form_nav.className = "signup-form-nav";
  1635. container_login.appendChild(signup_form_nav);
  1636. var checkbox = new LabelInput("记住账号密码(警告:明文保存于本地)","pubd-remember","pubd-remember","checkbox","1",true);
  1637. dlg.remember = checkbox.input;
  1638. signup_form_nav.appendChild(checkbox);
  1639. dlgc.appendChild(container_login);
  1640.  
  1641. submit.onclick = function()
  1642. {
  1643. dlg.error.replace("登陆中···");
  1644.  
  1645. pubd.auth.newAccount(pid.value,pass.value,dlg.remember.checked);
  1646.  
  1647. pubd.auth.login(
  1648. function(jore){//onload_suceess_Cb
  1649. dlg.error.replace("登陆成功");
  1650. pubd.dialog.config.start_token_animate();
  1651. },
  1652. function(jore){//onload_haserror_Cb //返回错误消息
  1653. dlg.error.replace(["错误代码:" + jore.errors.system.code,jore.errors.system.message]);
  1654. },
  1655. function(re){//onload_notjson_Cb //返回不是JSON
  1656. dlg.error.replace("返回不是JSON,或程序异常");
  1657. },
  1658. function(re){//onerror_Cb //AJAX发送失败
  1659. dlg.error.replace("AJAX发送失败");
  1660. }
  1661. );
  1662. }
  1663. //添加错误功能
  1664. error_msg_list.clear = function()
  1665. {
  1666. this.innerHTML = ""; //清空当前信息
  1667. }
  1668. error_msg_list.add = function(text)
  1669. {
  1670. var error_msg_list_item = document.createElement("li");
  1671. error_msg_list_item.className = "error-msg-list-item";
  1672. error_msg_list_item.innerHTML = text;
  1673. this.appendChild(error_msg_list_item);
  1674. }
  1675. error_msg_list.adds = function(arr)
  1676. {
  1677. arr.forEach(
  1678. function (item){
  1679. error_msg_list.add(item);
  1680. }
  1681. )
  1682. }
  1683. error_msg_list.replace = function(text)
  1684. {
  1685. this.clear();
  1686. if (typeof(text) == "object") //数组
  1687. this.adds(text);
  1688. else //单文本
  1689. this.add(text);
  1690. }
  1691. dlg.error = error_msg_list;
  1692. //窗口关闭
  1693. dlg.close = function(){
  1694. pubd.auth.newAccount(pid.value,pass.value,dlg.remember.checked);
  1695. pubd.auth.save();
  1696. };
  1697. //关闭窗口按钮
  1698. dlg.cptBtns.close.addEventListener("click",dlg.close);
  1699. //窗口初始化
  1700. dlg.initialise = function(){
  1701. dlg.remember.checked = pubd.auth.save_account;
  1702. pid.value = pubd.auth.username||"";
  1703. pass.value = pubd.auth.password||"";
  1704. error_msg_list.clear();
  1705. };
  1706. return dlg;
  1707. }
  1708.  
  1709.  
  1710. //构建当前画师下载对话框
  1711. function buildDlgDownThis(touch,userid)
  1712. {
  1713. var dlg = new Dialog("下载当前画师","pubd-downthis","pubd-downthis");
  1714. dlg.user = new UserInfo();
  1715.  
  1716. var dlgc = dlg.content;
  1717.  
  1718. var dl=document.createElement("dl");
  1719. dlgc.appendChild(dl);
  1720.  
  1721. var dt=document.createElement("dt");
  1722. dl.appendChild(dt);
  1723. dt.innerHTML = "" //用户头像等信息
  1724. var dd=document.createElement("dd");
  1725.  
  1726. var uinfo = new UserCard(userid?userid:pixiv.context.userId); //创建当前用户信息卡
  1727. dlg.uinfo = uinfo;
  1728. dd.appendChild(uinfo);
  1729. dl.appendChild(dd);
  1730.  
  1731. var dt=document.createElement("dt");
  1732. dl.appendChild(dt);
  1733. dt.innerHTML = ""
  1734. var dd=document.createElement("dd");
  1735.  
  1736. var frm = new Frame("下载内容");
  1737. var radio1 = new LabelInput("他的作品","pubd-down-content","pubd-down-content","radio","0",true);
  1738. var radio2 = new LabelInput("他的收藏","pubd-down-content","pubd-down-content","radio","1",true);
  1739. dlg.dcType = [radio1.input,radio2.input];
  1740. radio1.input.onclick = function(){reAnalyse(this)};
  1741. radio2.input.onclick = function(){reAnalyse(this)};
  1742. function reAnalyse(radio)
  1743. {
  1744. if (radio.checked == true)
  1745. {
  1746. if (radio.value == 0)
  1747. dlg.user.bookmarks.break = true; //radio值为0,使收藏中断
  1748. else
  1749. dlg.user.illusts.break = true; //radio值为1,使作品中断
  1750.  
  1751. dlg.analyse(radio.value,dlg.uinfo.userid);
  1752. }
  1753. }
  1754. frm.content.appendChild(radio1);
  1755. frm.content.appendChild(radio2);
  1756.  
  1757. dd.appendChild(frm);
  1758. dl.appendChild(dd);
  1759.  
  1760. var dt=document.createElement("dt");
  1761. dl.appendChild(dt);
  1762. dt.innerHTML = "信息获取进度"
  1763. var dd=document.createElement("dd");
  1764. var progress = new Progress("pubd-downthis-progress");
  1765. dlg.progress = progress;
  1766. dd.appendChild(progress);
  1767. dl.appendChild(dd);
  1768.  
  1769. var dt=document.createElement("dt");
  1770. dl.appendChild(dt);
  1771. dt.innerHTML = "进程日志"
  1772. var btnBreak = document.createElement("input");
  1773. btnBreak.type = "button";
  1774. btnBreak.className = "pubd-breakdown";
  1775. btnBreak.value = "中断操作";
  1776. btnBreak.onclick = function()
  1777. {
  1778. dlg.user.illusts.break = true; //使作品中断
  1779. dlg.user.bookmarks.break = true; //使收藏中断
  1780. }
  1781. dt.appendChild(btnBreak);
  1782. var dd=document.createElement("dd");
  1783. var ipt = document.createElement("textarea");
  1784. ipt.readOnly = true;
  1785. ipt.className = "pubd-downthis-log";
  1786. ipt.wrap = "off";
  1787. dlg.logTextarea = ipt;
  1788. dd.appendChild(ipt);
  1789. dl.appendChild(dd);
  1790.  
  1791. //下载方案
  1792. dlg.schemes = null;
  1793. dlg.reloadSchemes = function()
  1794. {//重新读取所有下载方案
  1795. dlg.downScheme.options.length = 0;
  1796. dlg.schemes.forEach(function(item,index){
  1797. dlg.downScheme.add(item.name,index);
  1798. })
  1799. if (dlg.downScheme.options.length > 0)
  1800. dlg.selectScheme(0);
  1801. }
  1802. //选择一个方案,同时读取设置
  1803. dlg.selectScheme = function(index)
  1804. {
  1805. if (index == undefined) index=0;
  1806. if (dlg.downScheme.options.length<1 || dlg.downScheme.selectedOptions.length<1){return;}
  1807. dlg.downScheme.selectedIndex = index;
  1808. }
  1809.  
  1810. var dt=document.createElement("dt");
  1811. dl.appendChild(dt);
  1812. dt.innerHTML = "选择下载方案"
  1813. var dd=document.createElement("dd");
  1814. var slt = new Select("pubd-downscheme");
  1815. dlg.downScheme = slt;
  1816. dd.appendChild(slt);
  1817. dl.appendChild(dd);
  1818.  
  1819. //下载按钮栏
  1820. var dt=document.createElement("dt");
  1821. dl.appendChild(dt);
  1822. var dd=document.createElement("dd");
  1823. dd.className = "pubd-downthis-downbar"
  1824.  
  1825. var startdown = document.createElement("input");
  1826. startdown.type = "button";
  1827. startdown.className = "pubd-startdown";
  1828. startdown.value = "开始下载";
  1829. startdown.onclick = function()
  1830. {
  1831. dlg.startdownload();
  1832. }
  1833. startdown.disabled = true;
  1834. dlg.startdown = startdown;
  1835. dd.appendChild(startdown);
  1836. dl.appendChild(dd);
  1837.  
  1838. //显示日志相关
  1839. dlg.logArr = []; //用于储存一行一行的日志信息。
  1840. dlg.logClear = function(){
  1841. dlg.logArr.length = 0;
  1842. this.logTextarea.value = "";
  1843. };
  1844. dlg.log = function(text){
  1845. dlg.logArr.push(text);
  1846. this.logTextarea.value = this.logArr.join("\n");
  1847. this.logTextarea.scrollTop = this.logTextarea.scrollHeight;
  1848. };
  1849.  
  1850. function xhrGenneral(url,onload_suceess_Cb,onload_hasError_Cb,onload_notJson_Cb,onerror_Cb)
  1851. {
  1852. var headersObj = new HeadersObject();
  1853. var auth = pubd.auth;
  1854. if (auth.needlogin)
  1855. {
  1856. var token_type = auth.response.token_type.substring(0,1).toUpperCase() + auth.response.token_type.substring(1);
  1857. headersObj.Authorization = token_type + " " + auth.response.access_token;
  1858. }else
  1859. {
  1860. console.info("非登录模式获取信息");
  1861. }
  1862. GM_xmlhttpRequest({
  1863. url:url,
  1864. method:"get",
  1865. responseType:"text",
  1866. headers: headersObj,
  1867. onload: function(response) {
  1868. try
  1869. {
  1870. var jo = JSON.parse(response.responseText);
  1871. if (jo.error)
  1872. {
  1873. console.error("错误:返回错误消息",jo,response);
  1874. //jo.error.message 是JSON字符串的错误信息,Token错误的时候返回的又是普通字符串
  1875. //jo.error.user_message 是单行文本的错误信息
  1876. onload_hasError_Cb(jo);
  1877. //下面开始自动登陆
  1878. if (jo.error.message.indexOf("Error occurred at the OAuth process.")>=0)
  1879. {
  1880. dlg.log("Token过期或错误,需要重新登录");
  1881. if (pubd.auth.save_account)
  1882. {
  1883. dlg.log("检测到已保存账户密码,开始自动登陆");
  1884. var dlgLogin = pubd.dialog.login;
  1885. dlgLogin.show();
  1886. pubd.auth.login(
  1887. function(jore){//onload_suceess_Cb
  1888. dlgLogin.error.replace("登陆成功");
  1889. //pubd.dialog.config.start_token_animate();
  1890. dlgLogin.cptBtns.close.click();
  1891. dlg.log("登陆成功");
  1892. //回调自身
  1893. xhrGenneral(url,onload_suceess_Cb,onload_hasError_Cb,onload_notJson_Cb,onerror_Cb);
  1894. },
  1895. function(jore){//onload_haserror_Cb //返回错误消息
  1896. dlgLogin.error.replace(["错误代码:" + jore.errors.system.code,jore.errors.system.message]);
  1897. },
  1898. function(re){//onload_notjson_Cb //返回不是JSON
  1899. dlgLogin.error.replace("返回不是JSON,或程序异常");
  1900. },
  1901. function(re){//onerror_Cb //AJAX发送失败
  1902. dlgLogin.error.replace("AJAX发送失败");
  1903. }
  1904. );
  1905. }
  1906. }
  1907. }else
  1908. {//登陆成功
  1909. //console.info("JSON返回成功",jo);
  1910. onload_suceess_Cb(jo);
  1911. }
  1912. }catch(e)
  1913. {
  1914. console.error("错误:返回可能不是JSON,或程序异常",e,response);
  1915. onload_notJson_Cb(response);
  1916. }
  1917. },
  1918. onerror: function(response) {
  1919. console.error("错误:AJAX发送失败",response);
  1920. onerror_Cb(response);
  1921. }
  1922. })
  1923. }
  1924.  
  1925. //分析
  1926. dlg.analyse = function(contentType,userid)
  1927. {
  1928. if(!userid){dlg.log("错误:没有用户ID");return;}
  1929. contentType = contentType==undefined?0:parseInt(contentType);
  1930. var works = contentType==0?dlg.user.illusts:dlg.user.bookmarks; //将需要分析的数据储存到works里
  1931.  
  1932. if(works.runing)
  1933. {
  1934. dlg.log("已经在进行分析操作了");
  1935. return;
  1936. }
  1937. works.break = false;
  1938. works.runing = true;
  1939.  
  1940. dlg.startdown.disabled = true;
  1941. dlg.progress.set(0);
  1942. dlg.logClear();
  1943.  
  1944. function startAnalyseUser(userid,contentType)
  1945. {
  1946. dlg.log("开始获取ID为 " + userid + " 的用户信息");
  1947. xhrGenneral(
  1948. "https://app-api.pixiv.net/v1/user/detail?user_id=" + userid,
  1949. function(jore){//onload_suceess_Cb
  1950. works.runing = true;
  1951. dlg.user.done = true;
  1952. dlg.user.info = Object.assign(dlg.user.info, jore);
  1953. dlg.uinfo.set({
  1954. head:jore.user.profile_image_urls.medium,
  1955. name:jore.user.name,
  1956. illusts:jore.profile.total_illusts + jore.profile.total_manga,
  1957. bookmarks:jore.profile.total_illust_bookmarks_public,
  1958. });
  1959. startAnalyseWorks(dlg.user,contentType); //开始获取第一页
  1960. },
  1961. function(jore){//onload_haserror_Cb //返回错误消息
  1962. dlg.log("错误信息:" + (jore.error.message || jore.error.user_message));
  1963. works.runing = false;
  1964. },
  1965. function(re){//onload_notjson_Cb //返回不是JSON
  1966. dlg.log("错误:返回不是JSON,或程序异常");
  1967. works.runing = false;
  1968. },
  1969. function(re){//onerror_Cb //AJAX发送失败
  1970. dlg.log("错误:AJAX发送失败");
  1971. works.runing = false;
  1972. }
  1973. )
  1974. }
  1975.  
  1976. //根据用户信息是否存在,决定分析用户还是图像
  1977. if (!dlg.user.done)
  1978. {
  1979. startAnalyseUser(userid,contentType);
  1980. }else
  1981. {
  1982. dlg.log("ID:" + userid + " 用户信息已存在");
  1983. startAnalyseWorks(dlg.user,contentType); //开始获取第一页
  1984. }
  1985.  
  1986. //开始分析作品的前置操作
  1987. function startAnalyseWorks(user,contentType)
  1988. {
  1989. var uInfo = user.info;
  1990. var works,total,contentName,apiurl;
  1991. //获取作品,contentType == 0,获取收藏,contentType == 1
  1992. if (contentType==0)
  1993. {
  1994. works = user.illusts;
  1995. total = uInfo.profile.total_illusts + uInfo.profile.total_manga;
  1996. contentName = "作品";
  1997. apiurl = "https://app-api.pixiv.net/v1/user/illusts?user_id=" + uInfo.user.id;
  1998. }else
  1999. {
  2000. works = user.bookmarks;
  2001. total = uInfo.profile.total_illust_bookmarks_public;
  2002. contentName = "收藏";
  2003. apiurl = "https://app-api.pixiv.net/v1/user/bookmarks/illust?user_id=" + uInfo.user.id + "&restrict=public";
  2004. }
  2005. if (works.item.length>0)
  2006. {//断点续传
  2007. dlg.log(contentName + " 断点续传进度 " + works.item.length + "/" + total);
  2008. dlg.progress.set(works.item.length/total); //设置当前下载进度
  2009. apiurl = works.next_url;
  2010. }
  2011. analyseWorks(user,contentType,apiurl); //开始获取第一页
  2012. }
  2013. //分析作品递归函数
  2014. function analyseWorks(user,contentType,apiurl)
  2015. {
  2016. var uInfo = user.info;
  2017. var works,total,contentName;
  2018. if (contentType==0)
  2019. {
  2020. works = user.illusts;
  2021. total = uInfo.profile.total_illusts + uInfo.profile.total_manga;
  2022. contentName = "作品";
  2023. }else
  2024. {
  2025. works = user.bookmarks;
  2026. total = uInfo.profile.total_illust_bookmarks_public;
  2027. contentName = "收藏";
  2028. }
  2029. if (works.done)
  2030. {
  2031. //返回所有动图
  2032. var ugoiras = works.item.filter(function(item){
  2033. return item.type == "ugoira";
  2034. })
  2035. if (ugoiras.some(function(item){
  2036. return item.ugoira_metadata == undefined;
  2037. })>0)
  2038. {
  2039. dlg.log("共存在 " + ugoiras.length + " 件动图");
  2040. analyseUgoira(works,ugoiras,function(){ //开始分析动图
  2041. analyseWorks(user,contentType,apiurl) //开始获取下一页
  2042. });
  2043. return;
  2044. }
  2045. //没有动图则继续
  2046. if (works.item.length<total)
  2047. dlg.log("可能因为权限原因,无法获取到所有 " + contentName);
  2048. dlg.log(contentName + " 共 " + works.item.length + " 件已获取完毕");
  2049. dlg.progress.set(1);
  2050. works.runing = false;
  2051. works.next_url = "";
  2052. dlg.startdown.disabled = false;
  2053. if (GM_getValue("pubd-autodownload"))
  2054. {//自动开始
  2055. dlg.log("自动开始下载");
  2056. dlg.startdownload();
  2057. }
  2058. return;
  2059. }
  2060. if (works.break)
  2061. {
  2062. dlg.log("检测到 " + contentName + " 中断进程命令");
  2063. works.break = false;
  2064. works.runing = false;
  2065. return;
  2066. }
  2067.  
  2068. xhrGenneral(
  2069. apiurl,
  2070. function(jore){//onload_suceess_Cb
  2071. works.runing = true;
  2072. var illusts = jore.illusts;
  2073. for (var ii=0,ii_len=illusts.length;ii<ii_len;ii++)
  2074. {
  2075. var work = illusts[ii];
  2076. var original;
  2077. if (work.page_count>1)
  2078. {/*漫画多图*/
  2079. original = work.meta_pages[0].image_urls.original;
  2080. }else
  2081. {/*单张图片或动图,含漫画单图*/
  2082. original = work.meta_single_page.original_image_url;
  2083. }
  2084. var regSrc = new RegExp(illustPattern, "ig");
  2085. var regRes = regSrc.exec(original);
  2086. if (regRes)
  2087. {
  2088. work.url_without_page = regRes[1];
  2089. work.domain = regRes[2];
  2090. work.filename = regRes[3];
  2091. work.token = regRes[4];
  2092. work.extention = regRes[5];
  2093. }
  2094.  
  2095. //然后添加扩展名等
  2096. if (work.restrict>0)//非公共权限
  2097. dlg.log(contentName + " " + work.id + " 非公共权限,可能无法正常下载");
  2098.  
  2099. works.item.push(work);
  2100. }
  2101. dlg.log(contentName + " 获取进度 " + works.item.length + "/" + total);
  2102. dlg.progress.set(works.item.length/total); //设置当前下载进度
  2103. if (jore.next_url)
  2104. {//还有下一页
  2105. works.next_url = jore.next_url;
  2106. }else
  2107. {//没有下一页
  2108. works.done = true;
  2109. }
  2110. analyseWorks(user,contentType,jore.next_url); //开始获取下一页
  2111. },
  2112. function(jore){//onload_haserror_Cb //返回错误消息
  2113. dlg.log("错误信息:" + (jore.error.message || jore.error.user_message));
  2114. works.runing = false;
  2115. },
  2116. function(re){//onload_notjson_Cb //返回不是JSON
  2117. dlg.log("错误:返回不是JSON,或程序异常");
  2118. works.runing = false;
  2119. },
  2120. function(re){//onerror_Cb //AJAX发送失败
  2121. dlg.log("错误:AJAX发送失败");
  2122. works.runing = false;
  2123. }
  2124. )
  2125. }
  2126.  
  2127. function analyseUgoira(works,ugoirasItems,callback)
  2128. {
  2129. var dealItems = ugoirasItems.filter(function(item){
  2130. return (item.ugoira_metadata == undefined && item.type == "ugoira");
  2131. })
  2132. if (dealItems.length<1)
  2133. {
  2134. dlg.log("动图获取完毕");
  2135. dlg.progress.set(1); //设置当前下载进度
  2136. callback();
  2137. return;
  2138. }
  2139. if (works.break)
  2140. {
  2141. dlg.log("检测到中断进程命令");
  2142. works.break = false;
  2143. works.runing = false;
  2144. return;
  2145. }
  2146.  
  2147. var work = dealItems[0]; //当前处理的图
  2148.  
  2149. xhrGenneral(
  2150. "https://app-api.pixiv.net/v1/ugoira/metadata?illust_id=" + work.id,
  2151. function(jore){//onload_suceess_Cb
  2152. works.runing = true;
  2153. var illusts = jore.illusts;
  2154. work = Object.assign(work,jore);
  2155. dlg.log("动图信息 获取进度 " + (ugoirasItems.length - dealItems.length + 1) + "/" + ugoirasItems.length);
  2156. dlg.progress.set(1-dealItems.length/ugoirasItems.length); //设置当前下载进度
  2157. analyseUgoira(works,ugoirasItems,callback); //开始获取下一项
  2158. },
  2159. function(jore){//onload_haserror_Cb //返回错误消息
  2160. dlg.log("错误信息:" + (jore.error.message || jore.error.user_message));
  2161. if (work.restrict>0)//非公共权限
  2162. {//添加一条空信息
  2163. work.ugoira_metadata = {
  2164. frames:[
  2165.  
  2166. ],
  2167. zip_urls:{
  2168. medium:"",
  2169. },
  2170. };
  2171. dlg.log("跳过本条,获取下一条");
  2172. analyseUgoira(works,ugoirasItems,callback); //开始获取下一项
  2173. }
  2174. works.runing = false;
  2175. },
  2176. function(re){//onload_notjson_Cb //返回不是JSON
  2177. dlg.log("错误:返回不是JSON,或程序异常");
  2178. works.runing = false;
  2179. },
  2180. function(re){//onerror_Cb //AJAX发送失败
  2181. dlg.log("错误:AJAX发送失败");
  2182. works.runing = false;
  2183. }
  2184. )
  2185. }
  2186. }
  2187. //开始下载按钮
  2188. dlg.startdownload = function()
  2189. {
  2190. if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中方案");return;}
  2191. var scheme = dlg.schemes[dlg.downScheme.selectedIndex];
  2192. var contentType = dlg.dcType[1].checked?1:0;
  2193. var userInfo = dlg.user.info;
  2194. var illustsItems = contentType==0?dlg.user.illusts.item:dlg.user.bookmarks.item; //将需要分析的数据储存到works里
  2195. downloadWork(scheme,userInfo,illustsItems);//调用公用下载窗口
  2196. }
  2197. //启动初始化
  2198. dlg.initialise = function(){
  2199. //var dcType = (GM_getValue("pubd-down-content") == 1)?1:0;
  2200. var dcType = 0;
  2201. if (dlg.user.bookmarks.runing) //如果有程序正在运行,则覆盖设置。
  2202. dcType = 1;
  2203. else if (dlg.user.illusts.runing)
  2204. dcType = 0;
  2205. dlg.dcType[dcType].checked = true;
  2206. if (GM_getValue("pubd-autoanalyse"))
  2207. {
  2208. dlg.analyse(dcType,dlg.uinfo.userid);
  2209. }
  2210. dlg.schemes = pubd.downSchemes;
  2211. dlg.reloadSchemes();
  2212. dlg.selectScheme(GM_getValue("pubd-defaultscheme"));
  2213. };
  2214.  
  2215. return dlg;
  2216. }
  2217. //为了区分设置窗口和保存的设置,产生一个新的下载方案数组
  2218. function NewDownSchemeArrayFromJson(jsonarr)
  2219. {
  2220. if (typeof(jsonarr) == "string")
  2221. {
  2222. try
  2223. {
  2224. var jsonarr = JSON.parse(jsonarr);
  2225. }catch(e)
  2226. {
  2227. console.error("拷贝新下载方案数组时失败",e);
  2228. return false;
  2229. }
  2230. }
  2231. var sarr = new Array();
  2232. if (jsonarr instanceof Array)
  2233. {
  2234. for (var si = 0;si<jsonarr.length;si++)
  2235. {
  2236. var scheme = new DownScheme();
  2237. //var scheme = Object.create(new DownScheme());
  2238. //console.log("拷贝下载方案前",scheme);
  2239. scheme.loadFromJson(jsonarr[si]);
  2240. sarr.push(scheme);
  2241. //console.log("拷贝下载方案后",scheme);
  2242. }
  2243. }
  2244. return sarr;
  2245. }
  2246. //下载具体内容
  2247. function downloadWork(scheme,userInfo,illustsItems)
  2248. {
  2249. try
  2250. {
  2251.  
  2252. var masklist = scheme.masklist;
  2253. var works_len = illustsItems.length;
  2254. var aria2 = new Aria2(scheme.rpcurl);
  2255.  
  2256. spawnNotification("正在将 " + userInfo.user.name + " 的相关插画发送到指定的Aria2。如果图片数量较多,在此过程中可能会发生浏览器的卡顿或者暂时停止响应,这是正常情况请耐心等待。", userInfo.user.profile_image_urls.medium, "正在发送 " + userInfo.user.name + " 的相关插画");
  2257. illustsItems.reduce(function (previous, current, index, array)
  2258. {
  2259. var page_count = current.page_count;
  2260. if (current.type == "ugoira") //动图
  2261. page_count = current.ugoira_metadata.frames.length;
  2262. for (var pi = 0; pi < page_count; pi++)
  2263. {
  2264. var url = current.url_without_page + pi + "." + current.extention;
  2265. var srtObj = {
  2266. "out": replacePathSafe(showMask(scheme.savepath, scheme.masklist, userInfo, current, pi), true),
  2267. "referer": "https://app-api.pixiv.net/",
  2268. "user-agent": "PixivAndroidApp/5.0.49 (Android 6.0; LG-H818)",
  2269. }
  2270. if(scheme.savedir.length>0)
  2271. {
  2272. srtObj.dir = replacePathSafe(showMask(scheme.savedir, scheme.masklist, userInfo, current, pi), true);
  2273. }
  2274. //console.log(url,srtObj);
  2275. aria2.addUri(url, srtObj);
  2276. }
  2277. },false)
  2278.  
  2279. }catch(e)
  2280. {
  2281. console.error(e);
  2282. }
  2283. }
  2284. function showMask(str,masklist,user,illust,page)
  2285. {
  2286. var newTxt = str;
  2287. var pattern = "%{([^}]+)}";
  2288. var rs = null;
  2289. // console.log(rs = regMask.exec(newTxt),rs = regMask.exec(newTxt),rs = regMask.exec(newTxt),rs = regMask.exec(newTxt))
  2290.  
  2291. while (( rs = new RegExp(pattern).exec(newTxt) ) != null) {
  2292. var mymask = masklist.filter(function(mask)
  2293. {
  2294. return mask.name == rs[1];
  2295. });
  2296. if (mymask.length > 0)
  2297. {
  2298. var mask = mymask[0];
  2299. try
  2300. {
  2301. var evTemp = eval("(" + mask.logic + ")"); //mask的逻辑判断
  2302. if (evTemp)
  2303. newTxt = newTxt.replace(rs[0], mask.content);
  2304. else
  2305. newTxt = newTxt.replace(rs[0], "");
  2306. }catch(e)
  2307. {
  2308. console.error(rs[0] + " 自定义掩码出现了异常情况",e);
  2309. }
  2310. }
  2311.  
  2312. else if (rs[1] != undefined)
  2313. {
  2314. try
  2315. {
  2316. var evTemp = eval(rs[1]);
  2317. if (evTemp!=undefined)
  2318. newTxt = newTxt.replace(rs[0], evTemp.toString());
  2319. }catch(e)
  2320. {
  2321. console.error(rs[0] + " 掩码出现了异常情况",e);
  2322. }
  2323. }
  2324. }
  2325.  
  2326. return newTxt;
  2327. }
  2328. function replacePathSafe(str, keepTree) //去除Windows下无法作为文件名的字符,目前为了支持Linux暂不替换两种斜杠吧。
  2329. {//keepTree表示是否要保留目录树的字符(\、/和:)
  2330. var nstr = "";
  2331. if (typeof(str) == "undefined") return nstr;
  2332. str = str.toString();
  2333. if (keepTree)
  2334. nstr = str.replace(/[\*\?"<>\|]/ig, "_");
  2335. else
  2336. nstr = str.replace(/[\\\/:\*\?"<>\|\r\n]/ig, "_");
  2337. return nstr;
  2338. }
  2339. //开始构建UI
  2340. function startBuild(touch,loggedIn)
  2341. {
  2342. if (touch) //手机版
  2343. {
  2344. alert("PUBD暂不支持手机版");
  2345. }else
  2346. {
  2347. pubd.auth = new Auth();
  2348. try{
  2349. pubd.auth.loadFromResponse(JSON.parse(GM_getValue("pubd-auth")));
  2350. //pubd.auth.response.access_token = "";
  2351. }catch(e){
  2352. console.error("脚本初始化时,读取登录信息失败",e);
  2353. }
  2354. pubd.downSchemes = NewDownSchemeArrayFromJson(GM_getValue("pubd-downschemes"));
  2355.  
  2356. var btnStartInsertPlace = document.getElementsByClassName("user-relation")[0];
  2357. if (!btnStartInsertPlace) btnStartInsertPlace = document.getElementsByClassName("badges")[0]; //自己的页面
  2358. var btnStartBox = document.createElement("li");
  2359. if (!loggedIn)
  2360. {
  2361. var btnStartInsertPlace = document.getElementsByClassName("introduction")[0];
  2362. var btnStartBox = document.createElement("div");
  2363. }
  2364. pubd.start = buildbtnStart(touch);
  2365. pubd.menu = buildbtnMenu(touch);
  2366. btnStartBox.appendChild(pubd.start);
  2367. btnStartBox.appendChild(pubd.menu);
  2368. btnStartInsertPlace.appendChild(btnStartBox);
  2369.  
  2370. //var btnDlgInsertPlace = document.getElementsByClassName("layout-wrapper")[0] || document.body;
  2371. var btnDlgInsertPlace = document.body;
  2372. pubd.dialog.config = buildDlgConfig(touch);
  2373. btnDlgInsertPlace.appendChild(pubd.dialog.config);
  2374. pubd.dialog.login = buildDlgLogin(touch);
  2375. btnDlgInsertPlace.appendChild(pubd.dialog.login);
  2376. pubd.dialog.downthis = buildDlgDownThis(touch);
  2377. btnDlgInsertPlace.appendChild(pubd.dialog.downthis);
  2378.  
  2379. }
  2380. }
  2381.  
  2382. startBuild(pubd.touch,pubd.loggedIn); //开始主程序