您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
一键批量下载P站画师的全部作品
当前为
// ==UserScript== // @name PixivUserBatchDownload // @name:zh-CN P站画师个人作品批量下载工具 // @namespace http://www.mapaler.com/ // @description Batch download pixiv user's images in one key. // @description:zh-CN 一键批量下载P站画师的全部作品 // @include *://www.pixiv.net/* // @include *://touch.pixiv.net/* // @exclude *://www.pixiv.net/*mode=manga&illust_id* // @exclude *://www.pixiv.net/*mode=big&illust_id* // @exclude *://www.pixiv.net/*mode=manga_big* // @exclude *://www.pixiv.net/*search.php* // @version 5.0 开发版 // @copyright 2017+, Mapaler <[email protected]> // @icon http://www.pixiv.net/favicon.ico // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_listValues // ==/UserScript== /* * 公共变量区 */ var pubd = { //储存设置 configVersion: 0, //当前设置版本,用于提醒是否需要重置 touch:false, //是触屏 loggedIn:false, //登陆了 start:null, //开始按钮 menu:null, //菜单 dialog:{ //窗口些个 config:null, //设置窗口 login:null, //登陆窗口 downthis:null, //下载当前窗口 }, auth:null, downSchemes:[], }; var scriptName = typeof(GM_info)!="undefined" ? (GM_info.script.localizedName ? GM_info.script.localizedName : GM_info.script.name) : "PixivUserBatchDownload"; //本程序的名称 var scriptVersion = typeof(GM_info)!="undefined" ? GM_info.script.version : "LocalDebug"; //本程序的版本 var scriptIcon = ((typeof (GM_info) != "undefined") && GM_info.script.icon) ? GM_info.script.icon : "http://www.pixiv.net/favicon.ico"; //本程序的图标 //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站图片地址正则匹配式 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站图片地址正则匹配式 /* * 获取初始状态 */ if (typeof(unsafeWindow)!="undefined") var pixiv = unsafeWindow.pixiv; if (typeof(pixiv)=="undefined") { console.error("当前网页没有找到pixiv对象"); } if (pixiv && pixiv.user.loggedIn) { pubd.loggedIn = true; } if (location.host.indexOf("touch")>=0) //typeof(pixiv.AutoView)!="undefined" { pubd.touch=true; console.info("当前访问的是P站触屏手机版"); }else { console.info("当前访问的是P站桌面版"); } /* * Debug 用 仿GM函数区 */ //访GM_xmlhttpRequest函数v1.2 if(typeof(GM_xmlhttpRequest) == "undefined") { var GM_xmlhttpRequest = function(GM_param){ var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象 if(GM_param.responseType) xhr.responseType = GM_param.responseType; xhr.onreadystatechange = function() //设置回调函数 { if (xhr.readyState == 4 && xhr.status == 200 && GM_param.onload) GM_param.onload(xhr); if (xhr.readyState == 4 && xhr.status != 200 && GM_param.onerror) GM_param.onerror(xhr); } xhr.open(GM_param.method, GM_param.url, true); for (var header in GM_param.headers){ xhr.setRequestHeader(header, GM_param.headers[header]); } xhr.send(GM_param.data ? GM_param.data : null); } } //仿GM_getValue函数v1.0 if(typeof(GM_getValue) == "undefined") { var GM_getValue = function(name, type){ var value = localStorage.getItem(name); if (value == undefined) return value; if ((/^(?:true|false)$/i.test(value) && type == undefined) || type == "boolean") { if (/^true$/i.test(value)) return true; else if (/^false$/i.test(value)) return false; else return Boolean(value); } else if((/^\-?[\d\.]+$/i.test(value) && type == undefined) || type == "number") return Number(value); else return value; } } //仿GM_setValue函数v1.0 if(typeof(GM_setValue) == "undefined") { var GM_setValue = function(name, value){ localStorage.setItem(name, value); } } //仿GM_deleteValue函数v1.0 if(typeof(GM_deleteValue) == "undefined") { var GM_deleteValue = function(name){ localStorage.removeItem(name); } } //仿GM_listValues函数v1.0 if(typeof(GM_listValues) == "undefined") { var GM_listValues = function(){ var keys = new Array(); for (var ki=0, kilen=localStorage.length; ki<kilen; ki++) { keys.push(localStorage.key(ki)); } return keys; } } /* * 现成函数库 */ //发送网页通知 function spawnNotification(theBody, theIcon, theTitle) { var options = { body: theBody, icon: theIcon } if (!("Notification" in window)) { alert(theBody); } else if (Notification.permission === "granted") { Notification.requestPermission(function (permission) { // If the user is okay, let's create a notification var n = new Notification(theTitle, options); }); } // Otherwise, we need to ask the user for permission else if (Notification.permission !== 'denied') { Notification.requestPermission(function (permission) { // If the user is okay, let's create a notification if (permission === "granted") { var n = new Notification(theTitle, options); } }); } } /*\ |*| |*| :: cookies.js :: |*| |*| A complete cookies reader/writer framework with full unicode support. |*| |*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie |*| |*| This framework is released under the GNU Public License, version 3 or later. |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html |*| |*| Syntaxes: |*| |*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]]) |*| * docCookies.getItem(name) |*| * docCookies.removeItem(name[, path], domain) |*| * docCookies.hasItem(name) |*| * docCookies.keys() |*| \*/ var docCookies = { getItem: function (sKey) { return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } var sExpires = ""; if (vEnd) { switch (vEnd.constructor) { case Number: sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; break; case String: sExpires = "; expires=" + vEnd; break; case Date: sExpires = "; expires=" + vEnd.toUTCString(); break; } } document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); return true; }, removeItem: function (sKey, sPath, sDomain) { if (!sKey || !this.hasItem(sKey)) { return false; } document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : ""); return true; }, hasItem: function (sKey) { return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); }, keys: /* optional method: you can safely remove it! */ function () { var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } return aKeys; } }; /* * 自定义对象区 */ //一个用户的信息 var UserInfo = function() { var obj = { done:false, info:{ profile:null, user:null, profile:null, }, illusts:{ done:false, item:[], break:false, runing:false, next_url:"", }, bookmarks:{ done:false, item:[], break:false, runing:false, next_url:"", }, } return obj; } //一个Post数据 var PostDataObject = (function () { return function(obj) { var postdata = new Object; if (obj) postdata.data = Object.assign({}, obj); //合并obj postdata.increase = function(obj) { postdata.data = Object.assign(postdata.data, obj); //合并obj } postdata.toPostString = function() { var arr = new Array; for (var na in postdata.data) { var item = [ na , postdata.data[na] ]; arr.push(item); } var str = arr.map( function (item){ return item.join("="); } ).join("&"); return str; } return postdata; } })(); //一个本程序使用的headers数据 var HeadersObject = function (obj) { var headers = { 'App-OS': 'android', 'App-OS-Version': '6.0', 'App-Version': '5.0.49', 'User-Agent': 'PixivAndroidApp/5.0.49 (Android 6.0; LG-H818)', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', //重要 "Referer": "https://app-api.pixiv.net/", } if (obj) headers = Object.assign(headers, obj); //合并obj return headers; } //一个认证方案 var Auth = (function () { return function(username,password,remember) { if (!username) username = ""; if (!password) password = ""; if (!remember) remember = false; var auth = { //原始结构 response:{ access_token:"", expires_in:0, token_type:"", scope:"", refresh_token:"", user:{ profile_image_urls:{ px_16x16:"", px_50x50:"", px_170x170:"", }, id:"", name:"", account:"", mail_address:"", is_premium:false, x_restrict:0, is_mail_authorized:true, }, device_token:"", }, needlogin:false, username:username, password:password, save_account:remember, login_date:null, } auth.newAccount = function(username,password,remember) { if(typeof(remember)=="boolean") auth.save_account = remember; auth.username = username; auth.password = password; } auth.loadFromResponse = function(response) { auth = Object.assign(auth, response); } auth.save = function() { var saveObj = JSON.parse(JSON.stringify(auth)); //深度拷贝 if(!saveObj.save_account) { saveObj.username = ""; saveObj.password = ""; } GM_setValue("pubd-auth",JSON.stringify(saveObj)); } auth.login = function(onload_suceess_Cb,onload_hasError_Cb,onload_notJson_Cb,onerror_Cb) { var postObj = new PostDataObject({ //Post时发送的数据 client_id:"BVO2E8vAAikgUBW8FYpi6amXOjQj", client_secret:"LI1WsFUDrrquaINOdarrJclCrkTtc3eojCOswlog", grant_type:"password", username:auth.username, password:auth.password, //device_token:"6e50367b155c2ba9faeaf2152ee4607c", get_secure_url:"true", }) var device_token = docCookies.getItem("device_token"); if (device_token) postObj.increase({"device_token": device_token}); //登陆是老的API GM_xmlhttpRequest({ url:"https://oauth.secure.pixiv.net/auth/token", method:"post", responseType:"text", headers: new HeadersObject(), data: postObj.toPostString(), onload: function(response) { try { var jo = JSON.parse(response.responseText); if (jo.has_error || jo.errors) { console.error("登录失败,返回错误消息",jo); onload_hasError_Cb(jo); }else {//登陆成功 auth.loadFromResponse(jo); auth.login_date = new Date(); console.info("登陆成功",jo); onload_suceess_Cb(jo); } }catch(e) { console.error("登录失败,返回可能不是JSON,或程序异常",e,response); onload_notJson_Cb(response); } }, onerror: function(response) { console.error("登录失败,AJAX发送失败",response); onerror_Cb(response); } }) } return auth; }; })(); //一个下载方案 var DownScheme = (function () { //一个自定义掩码 return function(name) { var obj = { name:name?name:"默认方案", rpcurl:"http://localhost:6800/jsonrpc", savedir:"D:/PivixDownload/", savepath:"%{illust.user.id}/%{illust.filename}%{page}.%{illust.extention}", masklist:[], mask:{ add:function(name,logic,content){ var mask = { name:name, logic:logic, content:content, }; obj.masklist.push(mask); return mask; }, remove:function(index){ obj.masklist.splice(index, 1); }, }, loadFromJson:function(json) { if (typeof(json) == "string") { try { var json = JSON.parse(json); }catch(e) { console.error(e); return false; } } if (json.name) this.name = json.name; if (json.rpcurl) this.rpcurl = json.rpcurl; if (json.savedir) this.savedir = json.savedir; if (json.savepath) this.savepath = json.savepath; if (json.masklist) this.masklist = JSON.parse(JSON.stringify(json.masklist)); return true; }, } return obj; }; })(); //创建菜单类 var pubdMenu = (function () { //生成菜单项 function buildMenuItem(title,classname,callback,submenu) { var item = document.createElement("li"); item.subitem = null; //子菜单 if (title == 0) //只添加一条线 { item.className = "pubd-menu-line" + (classname?" "+classname:""); return item; } item.className = "pubd-menu-item" + (classname?" "+classname:""); //添加链接 var a = document.createElement("a"); a.className = "pubd-menu-item-a" //添加图标 var icon = document.createElement("i"); icon.className = "pubd-icon"; a.appendChild(icon); //添加文字 var span = document.createElement("span"); span.className = "text"; span.innerHTML = title; a.appendChild(span); if (typeof(callback) == "string") { a.target = "_blank"; a.href = callback; } else if (typeof(callback) == "function") { item.addEventListener("click",callback); //a.onclick = callback; } if (typeof(submenu) == "object") { item.classList.add("pubd-menu-includesub"); //表明该菜单项有子菜单 submenu.classList.add("pubd-menu-submenu"); //表明该菜单是子菜单 //a.addEventListener("mouseenter",function(){callback.show()}); //a.addEventListener("mouseleave",function(){callback.hide()}); item.appendChild(submenu); item.subitem = submenu; } item.appendChild(a); return item; } return function(touch,classname) { var menu = document.createElement("ul"); menu.className = "pubd-menu display-none" + (classname?" "+classname:""); menu.item = new Array(); //显示该菜单 menu.show = function() { menu.classList.remove("display-none"); } menu.hide = function() { menu.classList.add("display-none"); } //添加菜单项 menu.add = function(title,classname,callback,submenu) { var itm = buildMenuItem(title,classname,callback,submenu); this.appendChild(itm); this.item.push(itm) return itm; } //鼠标移出菜单时消失 menu.addEventListener("mouseleave",function(e){ this.hide(); }); return menu; }; })(); //创建通用对话框类 var Dialog = (function () { //构建标题栏按钮 function buildDlgCptBtn(text,classname,callback) { if (!callback)classname=""; var btn = document.createElement("a"); btn.className = "dlg-cpt-btn" + (classname?" "+classname:""); if (typeof(callback) == "string") { btn.target = "_blank"; btn.href = callback; } else { if (callback) btn.addEventListener("click",callback); } var btnTxt = document.createElement("div"); btnTxt.className = "dlg-cpt-btn-text"; btnTxt.innerHTML = text; btn.appendChild(btnTxt); return btn; } return function(caption,id,classname) { var dlg = document.createElement("div"); dlg.className = "pubd-dialog display-none" + (classname?" "+classname:""); //添加图标与标题 var cpt = document.createElement("div"); cpt.className = "caption"; var icon = document.createElement("i"); icon.className = "pubd-icon"; cpt.appendChild(icon); var span = document.createElement("span"); span.innerHTML = caption; cpt.appendChild(span); dlg.appendChild(cpt); dlg.caption = span; dlg.icon = icon; //添加标题栏按钮 var cptBtns = document.createElement("div"); cptBtns.className = "dlg-cpt-btns"; //添加关闭按钮 cptBtns.add = function(text,classname,callback){ var btn = buildDlgCptBtn(text,classname,callback); this.insertBefore(btn,this.firstChild); return btn; } cptBtns.close = cptBtns.add("X","dlg-btn-close",(function() { dlg.classList.add("display-none"); })); dlg.appendChild(cptBtns); dlg.cptBtns = cptBtns; //captionButtons //添加内容 var content = document.createElement("div"); content.className = "dlg-content"; dlg.appendChild(content); dlg.content = content; //窗口激活 dlg.active = function() { if (!this.classList.contains("pubd-dlg-active")) {//如果没有激活的话才执行 var dlgs = document.getElementsByClassName("pubd-dialog"); for (var dlgi=0;dlgi<dlgs.length;dlgi++) { dlgs[dlgi].classList.remove("pubd-dlg-active");//取消激活 dlgs[dlgi].style.zIndex = parseInt(window.getComputedStyle(dlgs[dlgi],null).getPropertyValue("z-index")) - 1; } this.style.zIndex = ""; this.classList.add("pubd-dlg-active");//添加激活 } } //窗口初始化 dlg.initialise = function() { return; } //窗口显示 dlg.show = function() { this.initialise(); this.classList.remove("display-none"); this.active(); } //窗口隐藏 dlg.hide = function() { this.cptBtns.close.click; } //添加鼠标拖拽移动 dlg.drag = {disX: 0,disY: 0}; //startDrag(cpt, dlg); cpt.addEventListener("mousedown",function(e){ dlg.drag.disX = e.pageX - dlg.offsetLeft; dlg.drag.disY = e.pageY - dlg.offsetTop; var handler_mousemove = function (e) { dlg.style.left = (e.pageX - dlg.drag.disX) + 'px'; dlg.style.top = (e.pageY - dlg.drag.disY) + 'px'; }; var handler_mouseup = function (e) { document.removeEventListener("mousemove",handler_mousemove); }; document.addEventListener("mousemove",handler_mousemove); document.addEventListener("mouseup",handler_mouseup,{once:true}); }); //点击窗口激活窗口 dlg.addEventListener("mousedown",function(e){ dlg.active(); }); return dlg; }; })(); //创建选项卡类 var Tab = (function () { return function(title) { var obj = { title:document.createElement("li"), content:document.createElement("li"), } obj.title = document.createElement("li"); obj.title.className = "pubd-tab-title"; obj.title.innerHTML = title; obj.name = function() { return this.title.textContent; } obj.rename = function(newName) { if (typeof(newName)=="string" && newName.length>0) { this.title.innerHTML = newName; return true; }else return false; } obj.content.className = "pubd-tab-content"; obj.content.innerHTML = "设置内容"; return obj; }; })(); //创建复数选项卡类 var Tabs = (function () { return function() { var tabs = document.createElement("div"); tabs.className = "pubd-tabs"; tabs.item = new Array(); //储存卡 //添加卡名区域 var ult = document.createElement("ul"); ult.className = "tab-title"; tabs.appendChild(ult); //添加卡内容区域 var ulc = document.createElement("ul"); ulc.className = "tab-content"; tabs.appendChild(ulc); tabs.add = function(name) { var tab = new Tab(name); tabs.item.push(tab); ult.appendChild(tab.title); ulc.appendChild(tab.content); } return tabs; }; })(); //创建框架类 var Frame = (function () { return function(title,classname) { var frame = document.createElement("div"); frame.className = "pubd-frame" + (classname?" "+classname:""); var caption = document.createElement("div"); caption.className = "pubd-frame-caption"; caption.innerHTML = title; frame.caption = caption; frame.appendChild(caption); var content = document.createElement("div"); content.className = "pubd-frame-content"; frame.content = content; frame.appendChild(content); frame.name = function() { return this.caption.textContent; } frame.rename = function(newName) { if (typeof(newName)=="string" && newName.length>0) { this.caption.innerHTML = newName; return true; }else return false; } return frame; }; })(); //创建带Label的Input类 var LabelInput = (function () { return function(text,classname,name,type,value,beforeText) { var label = document.createElement("label"); label.innerHTML = text; label.className = classname; var ipt = document.createElement("input"); ipt.name = name; ipt.id = ipt.name; ipt.type = type; ipt.value = value; label.input = ipt; if (beforeText) label.insertBefore(ipt,label.firstChild); else label.appendChild(ipt); return label; }; })(); //创建进度条类 var Progress = (function () { //强制保留pos位小数,如:2,会在2后面补上00.即2.00 function toDecimal2(num,pos) { var f = parseFloat(num); if (isNaN(f)) { return false; } var f = Math.round(num*Math.pow(10,pos))/Math.pow(10,pos); var s = f.toString(); var rs = s.indexOf('.'); if (pos > 0 && rs < 0) { rs = s.length; s += '.'; } while (s.length <= rs + pos) { s += '0'; } return s; } return function(classname,align_right) { var progress = document.createElement("div"); progress.className = "pubd-progress" + (classname?" "+classname:""); if (align_right) progress.classList.add("pubd-progress-right"); progress.scaleNum = 0; var bar = document.createElement("div"); bar.className = "pubd-progress-bar"; progress.appendChild(bar); var txt = document.createElement("span"); txt.className = "pubd-progress-text"; progress.appendChild(txt); progress.set = function(scale,pos,str) { if (!pos) pos = 2; var percentStr = toDecimal2((scale * 100),pos) + "%"; scale = scale>1?1:(scale<0?0:scale); this.scaleNum = scale; bar.style.width = percentStr; if (str) txt.innerHTML = str; else txt.innerHTML = percentStr; } progress.scale = function() { return this.scaleNum; } return progress; }; })(); //创建用户卡片类 var UserCard = (function () { return function(userid) { var uinfo = document.createElement("div"); uinfo.userid = userid; uinfo.className = "pubd-user-info"; var uhead = document.createElement("div"); uhead.className = "pubd-user-info-head"; uinfo.appendChild(uhead); var uhead_img = document.createElement("img"); uinfo.uhead = uhead_img; uhead.appendChild(uhead_img); uinfo.uhead = uhead_img; var infos = document.createElement("dl"); infos.className = "pubd-user-info-dl"; //ID var dt=document.createElement("dt"); dt.className = "pubd-user-info-id-dt"; dt.innerHTML = "ID" infos.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-user-info-id-dd"; dd.innerHTML = uinfo.userid; uinfo.uid = dd; infos.appendChild(dd); //作品数 var dt=document.createElement("dt"); dt.className = "pubd-user-info-illusts-dt"; dt.innerHTML = "作品投稿数" infos.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-user-info-illusts-dd"; uinfo.uillusts = dd; infos.appendChild(dd); //昵称 var dt=document.createElement("dt"); dt.className = "pubd-user-info-name-dt"; dt.innerHTML = "昵称" infos.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-user-info-name-dd"; uinfo.uname = dd; infos.appendChild(dd); //收藏数 var dt=document.createElement("dt"); dt.className = "pubd-user-info-bookmarks-dt"; dt.innerHTML = "插画收藏数" infos.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-user-info-bookmarks-dd"; uinfo.ubookmarks = dd; infos.appendChild(dd); uinfo.infos = infos; uinfo.appendChild(infos); uinfo.set = function(obj) { if (obj.id) { uinfo.userid = obj.id; uinfo.uid.innerHTML = obj.id; } if (obj.head) uinfo.uhead.src = obj.head; if (obj.name) uinfo.uname.innerHTML = obj.name; if (obj.illusts) uinfo.uillusts.innerHTML = obj.illusts; if (obj.bookmarks) uinfo.ubookmarks.innerHTML = obj.bookmarks; } return uinfo; }; })(); //创建下拉框类 var Select = (function () { return function(classname,name) { var select = document.createElement("select"); select.className = "pubd-select" + (classname?" "+classname:""); select.name = name; select.id = select.name; select.add = function(text,value) { var opt = new Option(text, value); this.options.add(opt); } select.remove = function(index) { this.options.remove(index); } return select; }; })(); //创建Aria2类 var Aria2 = (function () { var jsonrpc_version = '2.0'; function get_auth(url) { return url.match(/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(?:\/\/)?(?:([^:@]*(?::[^:@]*)?)?@)?/)[1]; }; function request(jsonrpc_path, method, params, callback, priority) { if (callback==undefined) callback = function(){return;} var auth = get_auth(jsonrpc_path); jsonrpc_path = jsonrpc_path.replace(/^((?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(\/\/)?(?:(?:[^:@]*(?::[^:@]*)?)?@)?(.*)/, '$1$2$3'); // auth string not allowed in url for firefox var request_obj = { jsonrpc: jsonrpc_version, method: method, id: priority ? "1" : (new Date()).getTime().toString(), }; if (params) request_obj['params'] = params; if (auth && auth.indexOf('token:') == 0) params.unshift(auth); var headers = {"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",} if (auth && auth.indexOf('token:') != 0) { headers.Authorization = "Basic " + btoa(auth); } GM_xmlhttpRequest({ url: jsonrpc_path + "?tm=" + (new Date()).getTime().toString(), method:"POST", responseType:"text", data:JSON.stringify(request_obj), headers: headers, onload: function(response) { try { var JSONreq = JSON.parse(response.response); callback(JSONreq); }catch(e) { console.error("Aria2发送信息错误",e,response); callback(false); } }, onerror: function(response) { console.error(response); callback(false); } }) }; return function (jsonrpc_path) { this.jsonrpc_path = jsonrpc_path; this.addUri = function (uri, options, callback) { request(this.jsonrpc_path, 'aria2.addUri', [[uri, ], options], callback); }; this.addTorrent = function (base64txt, options, callback) { request(this.jsonrpc_path, 'aria2.addTorrent', [base64txt, [], options], callback); }; this.getVersion = function (callback) { request(this.jsonrpc_path, 'aria2.getVersion', [], callback, true); }; this.getGlobalOption = function (callback) { request(this.jsonrpc_path, 'aria2.getGlobalOption', [], callback, true); }; return this; } })(); /* * 自定义函数区 */ //构建开始按钮 function buildbtnStart(touch) { if (touch) //手机版 { }else { var btnStart = document.createElement("a"); btnStart.id = "pubd-start"; btnStart.className = "pubd-start"; //添加图标 var icon = document.createElement("i"); icon.className = "pubd-icon"; btnStart.appendChild(icon); //添加文字 var span = document.createElement("span"); span.className = "text"; span.innerHTML = "使用PUBD扒图"; btnStart.appendChild(span); //鼠标移入和按下都起作用 //btnStart.addEventListener("mouseenter",function(){pubd.menu.show()}); btnStart.addEventListener("click",function(){pubd.menu.classList.toggle("display-none")}); } return btnStart; } //构建菜单 function buildbtnMenu(touch) { if (touch) //手机版 { }else { var menu2 = new pubdMenu(touch); menu2.add("子菜单1","",function(){alert("子菜单1")}); menu2.add("子菜单2","",function(){alert("子菜单2")}); var menu1 = new pubdMenu(touch); menu1.add("子菜单1","",function(){alert("子菜单1")}); menu1.add("子菜单2","",null,menu2); var menu3 = new pubdMenu(touch); menu3.add("子菜单1","",function(){alert("子菜单1")}); menu3.add("子菜单2","",function(){alert("子菜单2")}); menu3.add("子菜单2","",function(){alert("子菜单3")}); menu3.add("子菜单2","",function(){alert("子菜单4")}); var menu4 = new pubdMenu(touch); menu4.add("子菜单1","",null,menu3); menu4.add("子菜单2","",function(){alert("子菜单2")}); menu4.add("子菜单2","",function(){alert("子菜单5")}); menu4.add("子菜单2","",function(){alert("子菜单6")}); var menu = new pubdMenu(touch,"pubd-menu-main"); menu.id = "pubd-menu"; menu.add("下载该画师","",function() { pubd.dialog.downthis.show(); menu.hide(); } ); menu.add("占位用","",null,menu1); menu.add("没功能","",null,menu4); menu.add("多个画师下载",null,function() {//做成“声音”的设备样子 alert("这个功能也没有开发") } ); menu.add(0); menu.add("选项","pubd-menu-setting",function() { pubd.dialog.config.show(); menu.hide(); } ); } return menu; } //构建设置对话框 function buildDlgConfig(touch) { var dlg = new Dialog("PUBD选项 v" + scriptVersion,"pubd-config","pubd-config"); dlg.cptBtns.add("反馈","dlg-btn-debug","https://github.com/Mapaler/PixivUserBatchDownload/issues"); dlg.cptBtns.add("?","dlg-btn-help","https://github.com/Mapaler/PixivUserBatchDownload/tree/develop_v5"); dlg.token_ani = null; //储存Token进度条动画句柄 var dlgc = dlg.content; var dl=document.createElement("dl"); dlgc.appendChild(dl); var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "Pixiv访问权限,默认仅能访问公开作品"; var dd=document.createElement("dd"); var checkbox = new LabelInput("开启登陆功能,解除浏览限制","pubd-needlogin","pubd-needlogin","checkbox","1",true); dlg.needlogin = checkbox.input; dlg.needlogin.onclick = function() { if (dlg.needlogin.checked) { dlg.token_info.classList.remove("height-none"); dlg.start_token_animate(); }else { dlg.token_info.classList.add("height-none"); dlg.stop_token_animate(); } pubd.dialog.login.cptBtns.close.click(); } dd.appendChild(checkbox); var a_setting = document.createElement("a"); a_setting.className = "pubd-browsing-restriction"; a_setting.href = "http://www.pixiv.net/setting_user.php#over-18"; a_setting.target = "_blank"; a_setting.innerHTML = "设置我的账户浏览限制"; dd.appendChild(a_setting); dl.appendChild(dd); var dd=document.createElement("dd"); dd.className = "pubd-token-info height-none"; dlg.token_info = dd; var progress = new Progress("pubd-token-expires",true); dlg.token_expires = progress; dd.appendChild(progress); //开始动画 dlg.start_token_animate = function() { //if (!dlg.classList.contains("display-none")) //{ dlg.stop_token_animate(); requestAnimationFrame(token_animate); dlg.token_ani = setInterval(function () {requestAnimationFrame(token_animate)}, 1000); //} } //停止动画 dlg.stop_token_animate = function() { clearInterval(dlg.token_ani); } //动画具体实现 function token_animate() { var nowdate = new Date(); var olddate = new Date(pubd.auth.login_date); var expires_in = parseInt(pubd.auth.response.expires_in); var differ = expires_in - (nowdate - olddate)/1000; var scale = differ / expires_in; if (differ>0) { progress.set(scale,2,"Token有效剩余" + parseInt(differ) + "秒"); }else { progress.set(0,2,"Token已失效,请重新登录"); clearInterval(dlg.token_ani); } //console.log("Token有效剩余" + differ + "秒"); //检测动画后台是否停止 } var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-tologin"; ipt.value = "账户登陆" ipt.onclick = function() { pubd.dialog.login.show(); } dd.appendChild(ipt); dl.appendChild(dd); //“下载该画师”窗口选项 var dt=document.createElement("dt"); dl.appendChild(dt); var dd=document.createElement("dd"); var frm = new Frame("“下载该画师”窗口","pubd-frmdownthis"); var chk_autoanalyse = new LabelInput("打开窗口时自动获取","pubd-autoanalyse","pubd-autoanalyse","checkbox","1",true); dlg.autoanalyse = chk_autoanalyse.input; var chk_autodownload = new LabelInput("获取完成后自动下载","pubd-autodownload","pubd-autodownload","checkbox","1",true); dlg.autodownload = chk_autodownload.input; frm.content.appendChild(chk_autoanalyse); frm.content.appendChild(chk_autodownload); dd.appendChild(frm); dl.appendChild(dd); /* //选项卡栏 var dt=document.createElement("dt"); dl.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-config-tab" var tabs = new Tabs(); tabs.add("第一选项卡"); tabs.add("第二选项卡"); dd.appendChild(tabs); dl.appendChild(dd); */ //配置方案储存 dlg.schemes = null; dlg.reloadSchemes = function() {//重新读取所有下载方案 dlg.downScheme.options.length = 0; dlg.schemes.forEach(function(item,index){ dlg.downScheme.add(item.name,index); }) if (dlg.downScheme.options.length > 0) dlg.selectScheme(0); } dlg.loadScheme = function(scheme) {//读取一个下载方案 if (scheme == undefined) { dlg.rpcurl.value = ""; dlg.savedir.value = ""; dlg.savepath.value = ""; dlg.loadMasklistFromArray([]); }else { dlg.rpcurl.value = scheme.rpcurl; dlg.savedir.value = scheme.savedir; dlg.savepath.value = scheme.savepath; dlg.loadMasklistFromArray(scheme.masklist); } } dlg.addMask = function(name,logic,content,value) {//向掩码列表添加一个新的掩码 if (value == undefined) value = dlg.masklist.options.length; var text = name + " : " + logic + " : " + content; var opt = new Option(text, value); dlg.masklist.options.add(opt); } dlg.loadMask = function(mask) {//读取一个掩码到三个文本框,只是用来查看 dlg.mask_name.value = mask.name; dlg.mask_logic.value = mask.logic; dlg.mask_content.value = mask.content; } dlg.loadMasklistFromArray = function(masklist) {//从掩码数组重置掩码列表 dlg.masklist.length = 0; masklist.forEach(function(item,index){ dlg.addMask(item.name,item.logic,item.content,index); }) } //选择一个方案,同时读取设置 dlg.selectScheme = function(index) { if (index == undefined) index=0; if (dlg.downScheme.options.length<1 || dlg.downScheme.selectedOptions.length<1){return;} var scheme = dlg.schemes[index]; dlg.loadScheme(scheme); dlg.downScheme.selectedIndex = index; } //选择一个掩码,同时读取设置 dlg.selectMask = function(index) { if (dlg.downScheme.options.length<1 || dlg.downScheme.selectedOptions.length<1){return;} if (dlg.masklist.options.length<1 || dlg.masklist.selectedOptions.length<1){return;} var scheme = dlg.schemes[dlg.downScheme.selectedIndex]; var mask = scheme.masklist[index]; dlg.loadMask(mask); dlg.masklist.selectedIndex = index; } //配置方案选择 var dt=document.createElement("dt"); dt.innerHTML = "选择下载方案"; dl.appendChild(dt); var dd=document.createElement("dd"); var slt = new Select("pubd-downscheme"); slt.onchange = function() { dlg.selectScheme(this.selectedIndex); }; dlg.downScheme = slt; dd.appendChild(slt); var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-downscheme-new"; ipt.value = "新建" ipt.onclick = function() { var schemName = prompt("请输入方案名","我的方案"); var scheme = new DownScheme(schemName); var length = dlg.schemes.push(scheme); dlg.downScheme.add(scheme.name,length-1); dlg.downScheme.selectedIndex = length-1; dlg.loadScheme(scheme); console.log(scheme); //dlg.reloadSchemes(); } dd.appendChild(ipt); var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-downscheme-remove"; ipt.value = "删除" ipt.onclick = function() { if (dlg.downScheme.options.length < 1){alert("已经没有方案了");return;} if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中方案");return;} var index = dlg.downScheme.selectedIndex; dlg.schemes.splice(index, 1); dlg.downScheme.remove(index); var index = dlg.downScheme.selectedIndex; if (index<0) dlg.reloadSchemes();//没有选中的,重置 else dlg.loadScheme(dlg.schemes[index]); } dd.appendChild(ipt); dl.appendChild(dd); //Aria2 URL var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "Aria2 JSON-RPC 路径" var rpcchk = document.createElement("span"); //显示检查状态用 rpcchk.className = "pubd-rpcchk-info"; dlg.rpcchk = rpcchk; dlg.rpcchk.runing = false; dt.appendChild(rpcchk); var dd=document.createElement("dd"); var rpcurl = document.createElement("input"); rpcurl.type = "url"; rpcurl.className = "pubd-rpcurl"; rpcurl.name = "pubd-rpcurl"; rpcurl.id = rpcurl.name; rpcurl.placeholder = "Aria2的信息接收路径" rpcurl.onchange = function() { dlg.rpcchk.innerHTML = ""; dlg.rpcchk.runing = false; if (dlg.downScheme.selectedOptions.length < 1){return;} var schemeIndex = dlg.downScheme.selectedIndex; dlg.schemes[schemeIndex].rpcurl = rpcurl.value; } dlg.rpcurl = rpcurl; dd.appendChild(rpcurl); var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-rpcchk"; ipt.value = "检查路径" ipt.onclick = function() { if (dlg.rpcchk.runing) return; if (dlg.rpcurl.value.length < 1) { dlg.rpcchk.innerHTML = "路径为空"; return; } dlg.rpcchk.innerHTML = "正在连接..."; dlg.rpcchk.runing = true; var aria2 = new Aria2(dlg.rpcurl.value); aria2.getVersion(function (rejo){ if (rejo) dlg.rpcchk.innerHTML="发现Aria2 ver" + rejo.result.version; else dlg.rpcchk.innerHTML="Aria2连接失败"; dlg.rpcchk.runing = false; }); } dd.appendChild(ipt); dl.appendChild(dd); //下载目录 var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "下载目录" var dd=document.createElement("dd"); var savedir = document.createElement("input"); savedir.type = "url"; savedir.className = "pubd-savedir"; savedir.name = "pubd-savedir"; savedir.id = savedir.name; savedir.placeholder = "文件下载到的目录" savedir.onchange = function() { if (dlg.downScheme.selectedOptions.length < 1){return;} var schemeIndex = dlg.downScheme.selectedIndex; dlg.schemes[schemeIndex].savedir = savedir.value; } dlg.savedir = savedir; dd.appendChild(savedir); dl.appendChild(dd); //保存路径 var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "保存路径" var dd=document.createElement("dd"); var savepath = document.createElement("input"); savepath.type = "text"; savepath.className = "pubd-savepath"; savepath.name = "pubd-savedir"; savepath.id = savepath.name; savepath.placeholder = "分组保存的文件夹和文件名" savepath.onchange = function() { if (dlg.downScheme.selectedOptions.length < 1){return;} var schemeIndex = dlg.downScheme.selectedIndex; dlg.schemes[schemeIndex].savepath = savepath.value; } dlg.savepath = savepath; dd.appendChild(savepath); dl.appendChild(dd); //自定义掩码 var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "自定义掩码" var dd=document.createElement("dd"); dl.appendChild(dd); //▼掩码名 var ipt = document.createElement("input"); ipt.type = "text"; ipt.className = "pubd-mask-name"; ipt.name = "pubd-mask-name"; ipt.id = ipt.name; ipt.placeholder = "自定义掩码名"; dlg.mask_name = ipt; dd.appendChild(ipt); //▲掩码名 //▼执行条件 var ipt = document.createElement("input"); ipt.type = "text"; ipt.className = "pubd-mask-logic"; ipt.name = "pubd-mask-logic"; ipt.id = ipt.name; ipt.placeholder = "执行条件"; dlg.mask_logic = ipt; dd.appendChild(ipt); //▲执行条件 var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-mask-add"; ipt.value = "+"; ipt.onclick = function() {//增加自定义掩码 if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中下载方案");return;} var schemeIndex = dlg.downScheme.selectedIndex; dlg.schemes[schemeIndex].mask.add(dlg.mask_name.value,dlg.mask_logic.value,dlg.mask_content.value); dlg.addMask(dlg.mask_name.value,dlg.mask_logic.value,dlg.mask_content.value); dlg.mask_name.value = dlg.mask_logic.value = dlg.mask_content.value = ""; } dd.appendChild(ipt); var mask_remove = document.createElement("input"); mask_remove.type = "button"; mask_remove.className = "pubd-mask-remove"; mask_remove.value = "-"; mask_remove.onclick = function() {//删除自定义掩码 if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中下载方案");return;} if (dlg.masklist.options.length < 1){alert("已经没有掩码了");return;} if (dlg.masklist.selectedOptions.length < 1){alert("没有选中掩码");return;} var schemeIndex = dlg.downScheme.selectedIndex; var maskIndex = dlg.masklist.selectedIndex; dlg.schemes[schemeIndex].mask.remove(maskIndex); dlg.masklist.remove(maskIndex); for (var mi=maskIndex;mi<dlg.masklist.options.length;mi++) { dlg.masklist.options[mi].value = mi; } } dd.appendChild(mask_remove); //▼掩码内容 var ipt = document.createElement("input"); ipt.type = "text"; ipt.className = "pubd-mask-content"; ipt.name = "pubd-mask-content"; ipt.id = ipt.name; ipt.placeholder = "掩码内容"; dlg.mask_content = ipt; dd.appendChild(ipt); //▲掩码内容 dl.appendChild(dd); //▼掩码列表 var dd=document.createElement("dd"); var masklist = new Select("pubd-mask-list") masklist.size = 5; masklist.onchange = function() {//读取选中的掩码 dlg.selectMask(this.selectedIndex); } dlg.masklist = masklist; dd.appendChild(masklist); //▲掩码列表 dl.appendChild(dd); //保存按钮栏 var dt=document.createElement("dt"); dl.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-config-savebar" var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-reset"; ipt.value = "重置" ipt.onclick = function() { dlg.reset(); } dd.appendChild(ipt); var ipt = document.createElement("input"); ipt.type = "button"; ipt.className = "pubd-save"; ipt.value = "保存设置" ipt.onclick = function() { dlg.save(); } dd.appendChild(ipt); dl.appendChild(dd); //保存设置函数 dlg.save = function() { spawnNotification("设置已保存", scriptIcon, scriptName); pubd.auth.needlogin = dlg.needlogin.checked; pubd.auth.save(); GM_setValue("pubd-autoanalyse",dlg.autoanalyse.checked); //自动分析 GM_setValue("pubd-autodownload",dlg.autodownload.checked); //自动下载 var schemesStr = JSON.stringify(dlg.schemes); GM_setValue("pubd-downschemes",schemesStr); //下载方案 GM_setValue("pubd-defaultscheme",dlg.downScheme.selectedIndex); //默认方案 pubd.downSchemes = NewDownSchemeArrayFromJson(dlg.schemes); } //重置设置函数 dlg.reset = function() { spawnNotification("设置已重置", scriptIcon, scriptName); GM_deleteValue("pubd-auth"); //登陆相关信息 GM_deleteValue("pubd-autoanalyse"); //自动分析 GM_deleteValue("pubd-autodownload"); //自动下载 GM_deleteValue("pubd-downschemes"); //下载方案 GM_deleteValue("pubd-defaultscheme");//默认方案 } //窗口关闭 dlg.close = function(){ dlg.stop_token_animate(); }; //关闭窗口按钮 dlg.cptBtns.close.addEventListener("click",dlg.close); //窗口初始化 dlg.initialise = function(){ dlg.needlogin.checked = pubd.auth.needlogin; if (pubd.auth.needlogin) //如果要登陆,就显示Token区域,和动画 { dlg.token_info.classList.remove("height-none"); dlg.start_token_animate(); } else { dlg.token_info.classList.add("height-none"); } dlg.autoanalyse.checked = GM_getValue("pubd-autoanalyse"); dlg.autodownload.checked = GM_getValue("pubd-autodownload"); dlg.schemes = NewDownSchemeArrayFromJson(pubd.downSchemes); dlg.reloadSchemes(); dlg.selectScheme(GM_getValue("pubd-defaultscheme")); //ipt_token.value = pubd.auth.response.access_token; }; return dlg; } //构建登陆对话框 function buildDlgLogin(touch) { var dlg = new Dialog("登陆账户","pubd-login","pubd-login"); var dlgc = dlg.content; //Logo部分 var logo_box = document.createElement("div"); logo_box.className = "logo-box"; var logo = document.createElement("div"); logo.className = "logo"; logo_box.appendChild(logo); var catchphrase = document.createElement("div"); catchphrase.className = "catchphrase"; catchphrase.innerHTML = "登陆获取你的账户通行证,解除年龄限制" logo_box.appendChild(catchphrase); dlgc.appendChild(logo_box); //实际登陆部分 var container_login = document.createElement("div"); container_login.className = "container-login"; var input_field_group = document.createElement("div"); input_field_group.className = "input-field-group"; container_login.appendChild(input_field_group); var input_field1 = document.createElement("div"); input_field1.className = "input-field"; var pid = document.createElement("input"); pid.type = "text"; pid.className = "pubd-account"; pid.name = "pubd-account"; pid.id = pid.name; pid.placeholder="邮箱地址/pixiv ID"; dlg.pid = pid; input_field1.appendChild(pid); input_field_group.appendChild(input_field1); var input_field2 = document.createElement("div"); input_field2.className = "input-field"; var pass = document.createElement("input"); pass.type = "password"; pass.className = "pubd-password"; pass.name = "pubd-password"; pass.id =pass.name; pass.placeholder="密码"; dlg.pass = pass; input_field2.appendChild(pass); input_field_group.appendChild(input_field2); var error_msg_list = document.createElement("ul"); //登陆错误信息 error_msg_list.className = "error-msg-list"; container_login.appendChild(error_msg_list); var submit = document.createElement("button"); submit.className = "submit"; submit.innerHTML = "登陆" container_login.appendChild(submit); var signup_form_nav = document.createElement("div"); signup_form_nav.className = "signup-form-nav"; container_login.appendChild(signup_form_nav); var checkbox = new LabelInput("记住账号密码(警告:明文保存于本地)","pubd-remember","pubd-remember","checkbox","1",true); dlg.remember = checkbox.input; signup_form_nav.appendChild(checkbox); dlgc.appendChild(container_login); submit.onclick = function() { dlg.error.replace("登陆中···"); pubd.auth.newAccount(pid.value,pass.value,dlg.remember.checked); pubd.auth.login( function(jore){//onload_suceess_Cb dlg.error.replace("登陆成功"); pubd.dialog.config.start_token_animate(); }, function(jore){//onload_haserror_Cb //返回错误消息 dlg.error.replace(["错误代码:" + jore.errors.system.code,jore.errors.system.message]); }, function(re){//onload_notjson_Cb //返回不是JSON dlg.error.replace("返回不是JSON,或程序异常"); }, function(re){//onerror_Cb //AJAX发送失败 dlg.error.replace("AJAX发送失败"); } ); } //添加错误功能 error_msg_list.clear = function() { this.innerHTML = ""; //清空当前信息 } error_msg_list.add = function(text) { var error_msg_list_item = document.createElement("li"); error_msg_list_item.className = "error-msg-list-item"; error_msg_list_item.innerHTML = text; this.appendChild(error_msg_list_item); } error_msg_list.adds = function(arr) { arr.forEach( function (item){ error_msg_list.add(item); } ) } error_msg_list.replace = function(text) { this.clear(); if (typeof(text) == "object") //数组 this.adds(text); else //单文本 this.add(text); } dlg.error = error_msg_list; //窗口关闭 dlg.close = function(){ pubd.auth.newAccount(pid.value,pass.value,dlg.remember.checked); pubd.auth.save(); }; //关闭窗口按钮 dlg.cptBtns.close.addEventListener("click",dlg.close); //窗口初始化 dlg.initialise = function(){ dlg.remember.checked = pubd.auth.save_account; pid.value = pubd.auth.username||""; pass.value = pubd.auth.password||""; error_msg_list.clear(); }; return dlg; } //构建当前画师下载对话框 function buildDlgDownThis(touch,userid) { var dlg = new Dialog("下载当前画师","pubd-downthis","pubd-downthis"); dlg.user = new UserInfo(); var dlgc = dlg.content; var dl=document.createElement("dl"); dlgc.appendChild(dl); var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "" //用户头像等信息 var dd=document.createElement("dd"); var uinfo = new UserCard(userid?userid:pixiv.context.userId); //创建当前用户信息卡 dlg.uinfo = uinfo; dd.appendChild(uinfo); dl.appendChild(dd); var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "" var dd=document.createElement("dd"); var frm = new Frame("下载内容"); var radio1 = new LabelInput("他的作品","pubd-down-content","pubd-down-content","radio","0",true); var radio2 = new LabelInput("他的收藏","pubd-down-content","pubd-down-content","radio","1",true); dlg.dcType = [radio1.input,radio2.input]; radio1.input.onclick = function(){reAnalyse(this)}; radio2.input.onclick = function(){reAnalyse(this)}; function reAnalyse(radio) { if (radio.checked == true) { if (radio.value == 0) dlg.user.bookmarks.break = true; //radio值为0,使收藏中断 else dlg.user.illusts.break = true; //radio值为1,使作品中断 dlg.analyse(radio.value,dlg.uinfo.userid); } } frm.content.appendChild(radio1); frm.content.appendChild(radio2); dd.appendChild(frm); dl.appendChild(dd); var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "信息获取进度" var dd=document.createElement("dd"); var progress = new Progress("pubd-downthis-progress"); dlg.progress = progress; dd.appendChild(progress); dl.appendChild(dd); var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "进程日志" var btnBreak = document.createElement("input"); btnBreak.type = "button"; btnBreak.className = "pubd-breakdown"; btnBreak.value = "中断操作"; btnBreak.onclick = function() { dlg.user.illusts.break = true; //使作品中断 dlg.user.bookmarks.break = true; //使收藏中断 } dt.appendChild(btnBreak); var dd=document.createElement("dd"); var ipt = document.createElement("textarea"); ipt.readOnly = true; ipt.className = "pubd-downthis-log"; ipt.wrap = "off"; dlg.logTextarea = ipt; dd.appendChild(ipt); dl.appendChild(dd); //下载方案 dlg.schemes = null; dlg.reloadSchemes = function() {//重新读取所有下载方案 dlg.downScheme.options.length = 0; dlg.schemes.forEach(function(item,index){ dlg.downScheme.add(item.name,index); }) if (dlg.downScheme.options.length > 0) dlg.selectScheme(0); } //选择一个方案,同时读取设置 dlg.selectScheme = function(index) { if (index == undefined) index=0; if (dlg.downScheme.options.length<1 || dlg.downScheme.selectedOptions.length<1){return;} dlg.downScheme.selectedIndex = index; } var dt=document.createElement("dt"); dl.appendChild(dt); dt.innerHTML = "选择下载方案" var dd=document.createElement("dd"); var slt = new Select("pubd-downscheme"); dlg.downScheme = slt; dd.appendChild(slt); dl.appendChild(dd); //下载按钮栏 var dt=document.createElement("dt"); dl.appendChild(dt); var dd=document.createElement("dd"); dd.className = "pubd-downthis-downbar" var startdown = document.createElement("input"); startdown.type = "button"; startdown.className = "pubd-startdown"; startdown.value = "开始下载"; startdown.onclick = function() { dlg.startdownload(); } startdown.disabled = true; dlg.startdown = startdown; dd.appendChild(startdown); dl.appendChild(dd); //显示日志相关 dlg.logArr = []; //用于储存一行一行的日志信息。 dlg.logClear = function(){ dlg.logArr.length = 0; this.logTextarea.value = ""; }; dlg.log = function(text){ dlg.logArr.push(text); this.logTextarea.value = this.logArr.join("\n"); this.logTextarea.scrollTop = this.logTextarea.scrollHeight; }; function xhrGenneral(url,onload_suceess_Cb,onload_hasError_Cb,onload_notJson_Cb,onerror_Cb) { var headersObj = new HeadersObject(); var auth = pubd.auth; if (auth.needlogin) { var token_type = auth.response.token_type.substring(0,1).toUpperCase() + auth.response.token_type.substring(1); headersObj.Authorization = token_type + " " + auth.response.access_token; }else { console.info("非登录模式获取信息"); } GM_xmlhttpRequest({ url:url, method:"get", responseType:"text", headers: headersObj, onload: function(response) { try { var jo = JSON.parse(response.responseText); if (jo.error) { console.error("错误:返回错误消息",jo,response); //jo.error.message 是JSON字符串的错误信息,Token错误的时候返回的又是普通字符串 //jo.error.user_message 是单行文本的错误信息 onload_hasError_Cb(jo); //下面开始自动登陆 if (jo.error.message.indexOf("Error occurred at the OAuth process.")>=0) { dlg.log("Token过期或错误,需要重新登录"); if (pubd.auth.save_account) { dlg.log("检测到已保存账户密码,开始自动登陆"); var dlgLogin = pubd.dialog.login; dlgLogin.show(); pubd.auth.login( function(jore){//onload_suceess_Cb dlgLogin.error.replace("登陆成功"); //pubd.dialog.config.start_token_animate(); dlgLogin.cptBtns.close.click(); dlg.log("登陆成功"); //回调自身 xhrGenneral(url,onload_suceess_Cb,onload_hasError_Cb,onload_notJson_Cb,onerror_Cb); }, function(jore){//onload_haserror_Cb //返回错误消息 dlgLogin.error.replace(["错误代码:" + jore.errors.system.code,jore.errors.system.message]); }, function(re){//onload_notjson_Cb //返回不是JSON dlgLogin.error.replace("返回不是JSON,或程序异常"); }, function(re){//onerror_Cb //AJAX发送失败 dlgLogin.error.replace("AJAX发送失败"); } ); } } }else {//登陆成功 //console.info("JSON返回成功",jo); onload_suceess_Cb(jo); } }catch(e) { console.error("错误:返回可能不是JSON,或程序异常",e,response); onload_notJson_Cb(response); } }, onerror: function(response) { console.error("错误:AJAX发送失败",response); onerror_Cb(response); } }) } //分析 dlg.analyse = function(contentType,userid) { if(!userid){dlg.log("错误:没有用户ID");return;} contentType = contentType==undefined?0:parseInt(contentType); var works = contentType==0?dlg.user.illusts:dlg.user.bookmarks; //将需要分析的数据储存到works里 if(works.runing) { dlg.log("已经在进行分析操作了"); return; } works.break = false; works.runing = true; dlg.startdown.disabled = true; dlg.progress.set(0); dlg.logClear(); function startAnalyseUser(userid,contentType) { dlg.log("开始获取ID为 " + userid + " 的用户信息"); xhrGenneral( "https://app-api.pixiv.net/v1/user/detail?user_id=" + userid, function(jore){//onload_suceess_Cb works.runing = true; dlg.user.done = true; dlg.user.info = Object.assign(dlg.user.info, jore); dlg.uinfo.set({ head:jore.user.profile_image_urls.medium, name:jore.user.name, illusts:jore.profile.total_illusts + jore.profile.total_manga, bookmarks:jore.profile.total_illust_bookmarks_public, }); startAnalyseWorks(dlg.user,contentType); //开始获取第一页 }, function(jore){//onload_haserror_Cb //返回错误消息 dlg.log("错误信息:" + (jore.error.message || jore.error.user_message)); works.runing = false; }, function(re){//onload_notjson_Cb //返回不是JSON dlg.log("错误:返回不是JSON,或程序异常"); works.runing = false; }, function(re){//onerror_Cb //AJAX发送失败 dlg.log("错误:AJAX发送失败"); works.runing = false; } ) } //根据用户信息是否存在,决定分析用户还是图像 if (!dlg.user.done) { startAnalyseUser(userid,contentType); }else { dlg.log("ID:" + userid + " 用户信息已存在"); startAnalyseWorks(dlg.user,contentType); //开始获取第一页 } //开始分析作品的前置操作 function startAnalyseWorks(user,contentType) { var uInfo = user.info; var works,total,contentName,apiurl; //获取作品,contentType == 0,获取收藏,contentType == 1 if (contentType==0) { works = user.illusts; total = uInfo.profile.total_illusts + uInfo.profile.total_manga; contentName = "作品"; apiurl = "https://app-api.pixiv.net/v1/user/illusts?user_id=" + uInfo.user.id; }else { works = user.bookmarks; total = uInfo.profile.total_illust_bookmarks_public; contentName = "收藏"; apiurl = "https://app-api.pixiv.net/v1/user/bookmarks/illust?user_id=" + uInfo.user.id + "&restrict=public"; } if (works.item.length>0) {//断点续传 dlg.log(contentName + " 断点续传进度 " + works.item.length + "/" + total); dlg.progress.set(works.item.length/total); //设置当前下载进度 apiurl = works.next_url; } analyseWorks(user,contentType,apiurl); //开始获取第一页 } //分析作品递归函数 function analyseWorks(user,contentType,apiurl) { var uInfo = user.info; var works,total,contentName; if (contentType==0) { works = user.illusts; total = uInfo.profile.total_illusts + uInfo.profile.total_manga; contentName = "作品"; }else { works = user.bookmarks; total = uInfo.profile.total_illust_bookmarks_public; contentName = "收藏"; } if (works.done) { //返回所有动图 var ugoiras = works.item.filter(function(item){ return item.type == "ugoira"; }) if (ugoiras.some(function(item){ return item.ugoira_metadata == undefined; })>0) { dlg.log("共存在 " + ugoiras.length + " 件动图"); analyseUgoira(works,ugoiras,function(){ //开始分析动图 analyseWorks(user,contentType,apiurl) //开始获取下一页 }); return; } //没有动图则继续 if (works.item.length<total) dlg.log("可能因为权限原因,无法获取到所有 " + contentName); dlg.log(contentName + " 共 " + works.item.length + " 件已获取完毕"); dlg.progress.set(1); works.runing = false; works.next_url = ""; dlg.startdown.disabled = false; if (GM_getValue("pubd-autodownload")) {//自动开始 dlg.log("自动开始下载"); dlg.startdownload(); } return; } if (works.break) { dlg.log("检测到 " + contentName + " 中断进程命令"); works.break = false; works.runing = false; return; } xhrGenneral( apiurl, function(jore){//onload_suceess_Cb works.runing = true; var illusts = jore.illusts; for (var ii=0,ii_len=illusts.length;ii<ii_len;ii++) { var work = illusts[ii]; var original; if (work.page_count>1) {/*漫画多图*/ original = work.meta_pages[0].image_urls.original; }else {/*单张图片或动图,含漫画单图*/ original = work.meta_single_page.original_image_url; } var regSrc = new RegExp(illustPattern, "ig"); var regRes = regSrc.exec(original); if (regRes) { work.url_without_page = regRes[1]; work.domain = regRes[2]; work.filename = regRes[3]; work.token = regRes[4]; work.extention = regRes[5]; } //然后添加扩展名等 if (work.restrict>0)//非公共权限 dlg.log(contentName + " " + work.id + " 非公共权限,可能无法正常下载"); works.item.push(work); } dlg.log(contentName + " 获取进度 " + works.item.length + "/" + total); dlg.progress.set(works.item.length/total); //设置当前下载进度 if (jore.next_url) {//还有下一页 works.next_url = jore.next_url; }else {//没有下一页 works.done = true; } analyseWorks(user,contentType,jore.next_url); //开始获取下一页 }, function(jore){//onload_haserror_Cb //返回错误消息 dlg.log("错误信息:" + (jore.error.message || jore.error.user_message)); works.runing = false; }, function(re){//onload_notjson_Cb //返回不是JSON dlg.log("错误:返回不是JSON,或程序异常"); works.runing = false; }, function(re){//onerror_Cb //AJAX发送失败 dlg.log("错误:AJAX发送失败"); works.runing = false; } ) } function analyseUgoira(works,ugoirasItems,callback) { var dealItems = ugoirasItems.filter(function(item){ return (item.ugoira_metadata == undefined && item.type == "ugoira"); }) if (dealItems.length<1) { dlg.log("动图获取完毕"); dlg.progress.set(1); //设置当前下载进度 callback(); return; } if (works.break) { dlg.log("检测到中断进程命令"); works.break = false; works.runing = false; return; } var work = dealItems[0]; //当前处理的图 xhrGenneral( "https://app-api.pixiv.net/v1/ugoira/metadata?illust_id=" + work.id, function(jore){//onload_suceess_Cb works.runing = true; var illusts = jore.illusts; work = Object.assign(work,jore); dlg.log("动图信息 获取进度 " + (ugoirasItems.length - dealItems.length + 1) + "/" + ugoirasItems.length); dlg.progress.set(1-dealItems.length/ugoirasItems.length); //设置当前下载进度 analyseUgoira(works,ugoirasItems,callback); //开始获取下一项 }, function(jore){//onload_haserror_Cb //返回错误消息 dlg.log("错误信息:" + (jore.error.message || jore.error.user_message)); if (work.restrict>0)//非公共权限 {//添加一条空信息 work.ugoira_metadata = { frames:[ ], zip_urls:{ medium:"", }, }; dlg.log("跳过本条,获取下一条"); analyseUgoira(works,ugoirasItems,callback); //开始获取下一项 } works.runing = false; }, function(re){//onload_notjson_Cb //返回不是JSON dlg.log("错误:返回不是JSON,或程序异常"); works.runing = false; }, function(re){//onerror_Cb //AJAX发送失败 dlg.log("错误:AJAX发送失败"); works.runing = false; } ) } } //开始下载按钮 dlg.startdownload = function() { if (dlg.downScheme.selectedOptions.length < 1){alert("没有选中方案");return;} var scheme = dlg.schemes[dlg.downScheme.selectedIndex]; var contentType = dlg.dcType[1].checked?1:0; var userInfo = dlg.user.info; var illustsItems = contentType==0?dlg.user.illusts.item:dlg.user.bookmarks.item; //将需要分析的数据储存到works里 downloadWork(scheme,userInfo,illustsItems);//调用公用下载窗口 } //启动初始化 dlg.initialise = function(){ //var dcType = (GM_getValue("pubd-down-content") == 1)?1:0; var dcType = 0; if (dlg.user.bookmarks.runing) //如果有程序正在运行,则覆盖设置。 dcType = 1; else if (dlg.user.illusts.runing) dcType = 0; dlg.dcType[dcType].checked = true; if (GM_getValue("pubd-autoanalyse")) { dlg.analyse(dcType,dlg.uinfo.userid); } dlg.schemes = pubd.downSchemes; dlg.reloadSchemes(); dlg.selectScheme(GM_getValue("pubd-defaultscheme")); }; return dlg; } //为了区分设置窗口和保存的设置,产生一个新的下载方案数组 function NewDownSchemeArrayFromJson(jsonarr) { if (typeof(jsonarr) == "string") { try { var jsonarr = JSON.parse(jsonarr); }catch(e) { console.error("拷贝新下载方案数组时失败",e); return false; } } var sarr = new Array(); if (jsonarr instanceof Array) { for (var si = 0;si<jsonarr.length;si++) { var scheme = new DownScheme(); //var scheme = Object.create(new DownScheme()); //console.log("拷贝下载方案前",scheme); scheme.loadFromJson(jsonarr[si]); sarr.push(scheme); //console.log("拷贝下载方案后",scheme); } } return sarr; } //下载具体内容 function downloadWork(scheme,userInfo,illustsItems) { try { var masklist = scheme.masklist; var works_len = illustsItems.length; var aria2 = new Aria2(scheme.rpcurl); spawnNotification("正在将 " + userInfo.user.name + " 的相关插画发送到指定的Aria2。如果图片数量较多,在此过程中可能会发生浏览器的卡顿或者暂时停止响应,这是正常情况请耐心等待。", userInfo.user.profile_image_urls.medium, "正在发送 " + userInfo.user.name + " 的相关插画"); illustsItems.reduce(function (previous, current, index, array) { var page_count = current.page_count; if (current.type == "ugoira") //动图 page_count = current.ugoira_metadata.frames.length; for (var pi = 0; pi < page_count; pi++) { var url = current.url_without_page + pi + "." + current.extention; var srtObj = { "out": replacePathSafe(showMask(scheme.savepath, scheme.masklist, userInfo, current, pi), true), "referer": "https://app-api.pixiv.net/", "user-agent": "PixivAndroidApp/5.0.49 (Android 6.0; LG-H818)", } if(scheme.savedir.length>0) { srtObj.dir = replacePathSafe(showMask(scheme.savedir, scheme.masklist, userInfo, current, pi), true); } //console.log(url,srtObj); aria2.addUri(url, srtObj); } },false) }catch(e) { console.error(e); } } function showMask(str,masklist,user,illust,page) { var newTxt = str; var pattern = "%{([^}]+)}"; var rs = null; // console.log(rs = regMask.exec(newTxt),rs = regMask.exec(newTxt),rs = regMask.exec(newTxt),rs = regMask.exec(newTxt)) while (( rs = new RegExp(pattern).exec(newTxt) ) != null) { var mymask = masklist.filter(function(mask) { return mask.name == rs[1]; }); if (mymask.length > 0) { var mask = mymask[0]; try { var evTemp = eval("(" + mask.logic + ")"); //mask的逻辑判断 if (evTemp) newTxt = newTxt.replace(rs[0], mask.content); else newTxt = newTxt.replace(rs[0], ""); }catch(e) { console.error(rs[0] + " 自定义掩码出现了异常情况",e); } } else if (rs[1] != undefined) { try { var evTemp = eval(rs[1]); if (evTemp!=undefined) newTxt = newTxt.replace(rs[0], evTemp.toString()); }catch(e) { console.error(rs[0] + " 掩码出现了异常情况",e); } } } return newTxt; } function replacePathSafe(str, keepTree) //去除Windows下无法作为文件名的字符,目前为了支持Linux暂不替换两种斜杠吧。 {//keepTree表示是否要保留目录树的字符(\、/和:) var nstr = ""; if (typeof(str) == "undefined") return nstr; str = str.toString(); if (keepTree) nstr = str.replace(/[\*\?"<>\|]/ig, "_"); else nstr = str.replace(/[\\\/:\*\?"<>\|\r\n]/ig, "_"); return nstr; } //开始构建UI function startBuild(touch,loggedIn) { if (touch) //手机版 { alert("PUBD暂不支持手机版"); }else { pubd.auth = new Auth(); try{ pubd.auth.loadFromResponse(JSON.parse(GM_getValue("pubd-auth"))); //pubd.auth.response.access_token = ""; }catch(e){ console.error("脚本初始化时,读取登录信息失败",e); } pubd.downSchemes = NewDownSchemeArrayFromJson(GM_getValue("pubd-downschemes")); var btnStartInsertPlace = document.getElementsByClassName("user-relation")[0]; if (!btnStartInsertPlace) btnStartInsertPlace = document.getElementsByClassName("badges")[0]; //自己的页面 var btnStartBox = document.createElement("li"); if (!loggedIn) { var btnStartInsertPlace = document.getElementsByClassName("introduction")[0]; var btnStartBox = document.createElement("div"); } pubd.start = buildbtnStart(touch); pubd.menu = buildbtnMenu(touch); btnStartBox.appendChild(pubd.start); btnStartBox.appendChild(pubd.menu); btnStartInsertPlace.appendChild(btnStartBox); //var btnDlgInsertPlace = document.getElementsByClassName("layout-wrapper")[0] || document.body; var btnDlgInsertPlace = document.body; pubd.dialog.config = buildDlgConfig(touch); btnDlgInsertPlace.appendChild(pubd.dialog.config); pubd.dialog.login = buildDlgLogin(touch); btnDlgInsertPlace.appendChild(pubd.dialog.login); pubd.dialog.downthis = buildDlgDownThis(touch); btnDlgInsertPlace.appendChild(pubd.dialog.downthis); } } startBuild(pubd.touch,pubd.loggedIn); //开始主程序