Pixiv Lazy plus

provide a direct link to original image ([s] link).

目前為 2021-02-09 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Pixiv Lazy plus
  3. // @namespace pixivlazyplus
  4. // @description provide a direct link to original image ([s] link).
  5. // @version 0.9.0.20
  6. // @include http://www.pixiv.net/*
  7. // @include https://www.pixiv.net/*
  8. // @include https://accounts.pixiv.net/*
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @grant GM_xmlhttpRequest
  12. // @grant GM_log
  13. // @grant GM_registerMenuCommand
  14. // ==/UserScript==
  15. // version 0.9.0.20 - tried to take care refresh_token, and overhual non-app-api version of parsing code (as urgency relief)
  16. // version 0.9.0.19 - followup https://github.com/upbit/pixivpy/issues/83#issuecomment-527232396
  17. // version 0.9.0.18 - fix medium page neighbor illust direct links
  18. // version 0.9.0.17 - fix medium page list after server side version up
  19. // version 0.9.0.16 - fix medium page after server side version up
  20. // version 0.9.0.15 - fix fetching preview urls, add a button for manual generating source links
  21. // version 0.9.0.14 - use data-src and always post-processing
  22. // version 0.9.0.13 - fix OAuth login detection URL, turn pixiv-dic URL into tag-searching URL
  23. // version 0.9.0.12 - try to auto login with tags.php ifreame reloading
  24. // version 0.9.0.11 - fix ranking [s] link attachment
  25. // version 0.9.0.10 - resize images in manga view
  26. // version 0.9.0.9 - fix for elimination of public API me.json
  27. // version 0.9.0.8 - add Auto Login menu item
  28. // version 0.9.0.7 - more fix of cookie issue
  29. // version 0.9.0.6 - fix cookie issue
  30. // version 0.9.0.5 - fix ugoira link again
  31. // version 0.9.0.4 - restore MangaFull function
  32. // version 0.9.0.3 - fix clearing accessToken logic, add function to check if accessToken is still valid
  33. // version 0.9.0.2 - fix ugoira link
  34. // version 0.9.0.1 - disable MangaFull since pixiv checks referer for full size manga pages now.
  35. // version 0.9 - upgrade to OAuth API + Pixiv Public API
  36. // version 0.8.14.1 - fix new medium page layout
  37. // version 0.8.13 - fix image response lazy link position
  38. // version 0.8.12 - fix mypage right side lazy links
  39. // version 0.8.11 - fix double links in medium page
  40. // version 0.8.10 - fix double links in medium page
  41. // version 0.8.9 - append [U] link after canvas
  42. // version 0.8.8 - fix loading big manga URL bug introduced in 0.8.7
  43. // version 0.8.7 - fix loading big manga URL in with PNG format
  44. // version 0.8.6 - fix modifying big manga URL in manga page
  45. // version 0.8.5 - fix preloading new manga URL format
  46. // version 0.8.4 - fix detecting URL new format
  47. // version 0.8.3 - fix detecting URL new format
  48. // version 0.8.2 - fix detecting URL new format
  49. // version 0.8.1 - fix detecting ugoira in prev/next
  50. // version 0.8.0 - add ability for downloading ugoira as zip
  51. // version 0.7.9 - fix for no profile image
  52. // version 0.7.8 - fix for spapi return value changes
  53. // version 0.7.7 - change [s] to [M](go directly to manga page) for manga links
  54. // version 0.7.6 - fix prev/next [s] link
  55. // version 0.7.5 - fix new manga page
  56. // version 0.7.4 - fix modified images
  57. // version 0.7.3 - fix missing session ID when it is not the end of cookie
  58. // version 0.7.2 - fix comma in tags breaking parsing logic
  59. // version 0.7.1 - fix iPhone API by supplying session ID
  60. // version 0.7 - work with new sample images with iPhone API, fix old manga
  61. // version 0.6.1 - preload manga images
  62. // version 0.6 - change manga mode to big images
  63. // version 0.5 - remove [b] link, add stylish style class
  64. // version 0.4 - updated to filter new thumbnails
  65. // version 0.3 - fix a bug, hat-tip to syosyo
  66. // version 0.2 - updated on 2008-06-25
  67. var pixivlink_run = 0;
  68. var pixivlink_reloadRequested = 0;
  69. var isNewManga = 1;
  70. var postProcImg = new Array();
  71. var preloadImg = new Array();
  72. var Imgs = new Array();
  73. var sessID1 = (/PHPSESSID=[0-9a-f]*?(?=;|$)/.exec(document.cookie) || "");
  74. var sessID2 = (/PHPSESSID=[^;]*?(?=;|$)/.exec(document.cookie) || "");
  75. var accessToken = GM_getValue("accessToken","");
  76. var refreshToken = GM_getValue("refreshToken","");
  77. var oauthUserName = GM_getValue("userName","");
  78. var oauthPassword = GM_getValue("passWord","");
  79. var autoLogin = GM_getValue("autoLogin",false);
  80. var mangaFormat = 'jpg';
  81. var pixivlink_imgs = 0;
  82.  
  83. var pixivClientID = "MOBrBDS8blbauoSck0ZfDbtuzpyT";
  84. var pixivClientSecret = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj";
  85. var xClientHashMD5Salt = "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c";
  86.  
  87. /*
  88. String.prototype.splitCSV = function(sep) {
  89. for (var foo = this.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) {
  90. if (foo[x].replace(/"\s+$/, '"').charAt(foo[x].length - 1) == '"') {
  91. if ((tl = foo[x].replace(/^\s+"/, '"')).length > 1 && tl.charAt(0) == '"') {
  92. foo[x] = foo[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
  93. } else if (x) {
  94. foo.splice(x - 1, 2, [foo[x - 1], foo[x]].join(sep));
  95. } else foo = foo.shift().split(sep).concat(foo);
  96. } else foo[x].replace(/""/g, '"');
  97. } return foo;
  98. };*/
  99.  
  100. /* use a function for the exact format desired... */
  101. function ISODateString(d){
  102. function pad(n){return n<10 ? '0'+n : n}
  103. return d.getUTCFullYear()+'-'
  104. + pad(d.getUTCMonth()+1)+'-'
  105. + pad(d.getUTCDate())+'T'
  106. + pad(d.getUTCHours())+':'
  107. + pad(d.getUTCMinutes())+':'
  108. + pad(d.getUTCSeconds())+'Z'}
  109.  
  110. /* MD5 in javascript */
  111. var MD5 = function(d){result = M(V(Y(X(d),8*d.length)));return result.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_}
  112.  
  113. function _e(id) { return document.getElementById(id); }
  114.  
  115. function getElementsByClassName(matchClass) {
  116. var clselems = new Array();
  117. var elems = document.getElementsByTagName('*'), i;
  118. for (i in elems) {
  119. if((' ' + elems[i].className + ' ').indexOf(' ' + matchClass + ' ')
  120. > -1) {
  121. clselems.push(elems[i]);
  122. }
  123. }
  124. return clselems;
  125. }
  126.  
  127. function createCookie(cookietext,days, domain) {
  128. if (days) {
  129. var date = new Date();
  130. date.setTime(date.getTime()+(days*24*60*60*1000));
  131. var expires = "; expires="+date.toGMTString();
  132. }
  133. else var expires = "";
  134. if (domain) domain = "; domain="+domain;
  135. else domain = "";
  136. document.cookie = cookietext+expires+domain+"; path=/";
  137. }
  138.  
  139. function doOAuth(obj) {
  140. var oauthUser, oauthPass, xClientTime, xClientTimeHash, returnData;
  141. oauthUser = _e("oauthUsername").value;
  142. oauthPass = _e("oauthPassword").value;
  143. xClientTime = ISODateString(new Date);
  144. xClientTimeHash = MD5(xClientTime+xClientHashMD5Salt);
  145. createCookie("PHPSESSID=",-1,""); // erase cookie first
  146. createCookie("PHPSESSID=",-1,".pixxiv.net"); // erase cookie first
  147. if(oauthUser && oauthPass) {
  148. GM_setValue("userName",oauthUser);
  149. GM_setValue("passWord",oauthPass);
  150. GM_xmlhttpRequest({
  151. url: 'https://oauth.secure.pixiv.net/auth/token',
  152. method: "POST",
  153. headers: {
  154. "Referer": "https://app-api.pixiv.net/",
  155. "User-Agent": "PixivAndroidApp/5.0.220.1 (Android 9.0.0; Android SDK built for x86)",
  156. "Accept-Language": "ja",
  157. 'App-OS': 'android',
  158. 'App-OS-Version': '9.0.0',
  159. 'App-Version': '5.0.220.1',
  160. 'X-Client-Time': xClientTime,
  161. 'X-Client-Hash': xClientTimeHash,
  162. "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
  163. },
  164. data: "client_id="+pixivClientID+"&client_secret="+pixivClientSecret+"&get_secure_url=1&device_token=pixiv"+(refreshToken?"&grant_type=refresh_token&refresh_token="+refreshToken:"&grant_type=password&username="+oauthUser+"&password="+oauthPass),
  165. onload: function (response) {
  166. if (response.status == 200) {
  167. returnData = JSON.parse(response.responseText);
  168. accessToken = returnData.response.access_token;
  169. refreshToken = returnData.response.refresh_token;
  170. GM_setValue("accessToken",accessToken);
  171. GM_setValue("refreshToken",refreshToken);
  172. if(!autoLogin) alert("Login Sucessfully.");
  173. //createCookie(sessID1,0,""); // restore cookie first
  174. createCookie(sessID2,0,".pixiv.net"); // restore cookie first
  175. window.postMessage('refresh', '*'); //location.reload();
  176. } else {
  177. GM_log("response.status="+response.status);
  178. GM_log(response.responseText);
  179. //createCookie(sessID1,0,""); // restore cookie first
  180. createCookie(sessID2,0,".pixiv.net"); // restore cookie first
  181. GM_setValue("autoLogin",false); // clear autologin flag
  182. refreshToken = "";
  183. GM_setValue("refreshToken",refreshToken); // clear refresh token
  184. alert("Login Failed!");
  185. }
  186. }
  187. });
  188. }
  189. }
  190.  
  191. function createOAuthLoginForm() {
  192. var tmp, newHTML = document.createElement ('div');
  193. newHTML.id = 'gmOAuthLoginFrm';
  194. newHTML.style.position='absolute';
  195. newHTML.style.backgroundColor='#fff';
  196. newHTML.style.top='0';
  197. newHTML.style.left='0';
  198. newHTML.style.zIndex='100';
  199. newHTML.appendChild(document.createTextNode('OAuth Login User: '));
  200. tmp = document.createElement ('input');
  201. tmp.id = 'oauthUsername';
  202. tmp.type = 'text';
  203. tmp.value = oauthUserName;
  204. newHTML.appendChild(tmp);
  205. newHTML.appendChild(document.createTextNode('Pass: '));
  206. tmp = document.createElement ('input');
  207. tmp.id = 'oauthPassword';
  208. tmp.type = 'password';
  209. tmp.value = oauthPassword;
  210. newHTML.appendChild(tmp);
  211. tmp = document.createElement ('input');
  212. tmp.id = 'oauthSubmit';
  213. tmp.type = 'button';
  214. tmp.value='Login';
  215. tmp.addEventListener("click", function(e){return doOAuth(e);}, false);
  216. newHTML.appendChild(tmp);
  217.  
  218. document.body.appendChild (newHTML);
  219. if(autoLogin) doOAuth(null);
  220. }
  221.  
  222. function checkTokenValid() {
  223. if(window==window.top) /* I'm NOT in a frame! */ {
  224. window.addEventListener('message', function(e) {
  225. if(e.data=='refresh') {
  226. if(!pixivlink_reloadRequested) {
  227. // GM_log(e.data);
  228. pixivlink_reloadRequested = 1;
  229. setTimeout("location.reload()",2000);
  230. }
  231. }
  232. }, false);
  233. }
  234.  
  235. if(getElementsByClassName('not-logged-in').length || getElementsByClassName('signup-form__submit').length) {
  236. createCookie("PHPSESSID=",-1,""); // erase oauth cookie
  237. GM_log('not logged in');
  238. var hobj;
  239. if(hobj=_e('login_pixiv_id')) hobj.value = oauthUserName;
  240. if(hobj=_e('login_password')) hobj.value = oauthPassword;
  241. /* for old login form */
  242. if(hobj=document.getElementsByName('pixiv_id')) hobj[0].value = oauthUserName;
  243. if(hobj=document.getElementsByName('password')) hobj[0].value = oauthPassword;
  244. /*if(window==window.top && (getElementsByClassName('signup-form__submit--login').length || getElementsByClassName('ui-button _login').length)) {
  245. var tmp, newHTML = document.createElement ('iframe');
  246. newHTML.setAttribute("src", "http://www.pixiv.net/tags.php");
  247. newHTML.id = 'gmAutoLoginFrame';
  248. newHTML.style.position='absolute';
  249. newHTML.style.backgroundColor='#fff';
  250. newHTML.style.top='-2000';
  251. newHTML.style.left='-2000';
  252. newHTML.height='1px';
  253. newHTML.width='1px';
  254. newHTML.style.zIndex='-100';
  255. document.body.appendChild (newHTML);
  256. }*/
  257. if(autoLogin) {
  258.  
  259. autoLogin = false;
  260. var loginForm;
  261. if(hobj=_e('login_password')) {
  262. loginForm = hobj.parentNode;
  263. do {
  264. if(loginForm.nodeName == 'FORM') {
  265. if(window!=window.top) {
  266. if(!pixivlink_reloadRequested) {
  267. pixivlink_reloadRequested = 1;
  268. window.top.postMessage('refresh', '*');
  269. }
  270. }
  271. // GM_log('called refresh! 1');
  272. loginForm.submit();
  273. }
  274. } while(loginForm = loginForm.parentNode);
  275. }
  276.  
  277. /* try old login form as well */
  278. if(hobj=document.getElementsByName('password')) {
  279. GM_log('old login submit');
  280. loginForm = hobj[0].parentNode;
  281. do {
  282. if(loginForm.nodeName == 'FORM') {
  283. if(window!=window.top) {
  284. if(!pixivlink_reloadRequested) {
  285. pixivlink_reloadRequested = 1;
  286. window.top.postMessage('refresh', '*');
  287. }
  288. }
  289. GM_log('called refresh! 2');
  290. loginForm.submit();
  291. break;
  292. }
  293. } while(loginForm = loginForm.parentNode);
  294. }
  295. }
  296. } else {
  297. if(0 /* disabled */ && window!=window.top) /* I'm in a frame! */ {
  298. if(!pixivlink_reloadRequested) {
  299. pixivlink_reloadRequested = 1;
  300. window.top.postMessage('refresh', '*');
  301. }
  302. // GM_log('called refresh! 3');
  303. }
  304. }
  305. GM_xmlhttpRequest({
  306. url: 'https://public-api.secure.pixiv.net/v1/me.json',
  307. method: "GET",
  308. headers: {
  309. Referer: "http://www.pixiv.net",
  310. "Authorization": "Bearer " + accessToken,
  311. "Cookie": sessID1
  312. },
  313. onload: function (response) {
  314. if (response.status == 200) {
  315. //GM_log(response.responseText);
  316. /* var vals = JSON.parse(response.responseText);
  317. if(vals.status == "success") {
  318. }*/
  319. } else /*if (response.status == 400)*/ {
  320. accessToken ="";
  321. GM_setValue("accessToken",accessToken);
  322. createOAuthLoginForm();
  323. }
  324. }
  325. });
  326. }
  327.  
  328. function GetImageIDFromLink(imageLink) {
  329. var imgID = 0; // If lower 11319936 it means Manga does not have Big version
  330.  
  331. var re = /\d+([_a-z0-9]+)?\.(jpe?g|gif|png)\??.*$|id=[0-9]+$/;
  332. var s = re.exec(imageLink);
  333. if (s && s.length > 0) {
  334. re = /\d+/;
  335. imgID = re.exec(s[0])[0];
  336. }
  337. return imgID;
  338. }
  339.  
  340. function pixivlink() {
  341. //alert(pixivlink_run);
  342. if (!pixivlink_run) pixivlink_run = 1;
  343. else return;
  344. checkTokenValid();
  345. var Items = document.getElementsByTagName('img');
  346. var rexa = /\?mode\=(medium|manga)\&illust_id|i\.pximg\.net|\/artworks\//;
  347. var rexb = /source.pixiv.net/;
  348. var rexc = /\/img-inf\//;
  349. var rexd = /\/mobile\//;
  350. var rexe = /\/c\//;
  351. for (var i = 0; i < Items.length; i++) {
  352. var imgR = Items[i];
  353. var aR = imgR.parentNode.parentNode;
  354. var aR2 = imgR.parentNode;
  355. var isThumbnail = ((' ' + aR2.className + ' ').indexOf(' _layout-thumbnail ') > -1) //&& ((' ' + aR2.className + ' ').indexOf(' ui-modal-trigger ') > -1)
  356. //GM_log('aR2.className = "'+aR2.className+'", imgR.src='+imgR.src);
  357. //GM_log('isThumbnail = '+isThumbnail);
  358. if (rexa.test(aR2.href)/* || isThumbnail*/) {
  359. aR = aR2;
  360. }
  361. if (rexa.test(aR.href) || isThumbnail) {
  362. if(imgR.hasAttribute("data-src")) {
  363. var imgID = GetImageIDFromLink(imgR.getAttribute("data-src"));
  364. var srcR = imgR.getAttribute("data-src").replace(/(_s|_m|_100|_64x64|_master1200|_custom1200|_square1200)\./i, ".");
  365. } else {
  366. var imgID = GetImageIDFromLink(imgR.src);
  367. var srcR = imgR.src.replace(/(_s|_m|_100|_64x64|_master1200|_custom1200|_square1200)\./i, ".");
  368. }
  369. srcR = srcR.replace(/\/c\/\d+x\d+(_\d+)?(_[a-z]\d+)?(_[a-z]\d+)?\/(img-master|custom-thumb)\//i, "/img-original/");
  370. srcR = srcR.replace(/\/img-master\//i, "/img-original/");
  371. srcR = srcR.replace(/(\d{2,})\.jpg$/, "$1_p0.jpg"); // fix ID-only URLs
  372. // var hrefR = aR.href.replace(/medium/i, "big");
  373. var tdR = aR.parentNode;
  374. //GM_log('srcR = "'+srcR);
  375. /* var linkB = document.createElement('a');
  376. linkB.href = hrefR;
  377. linkB.target = '_blank';
  378. linkB.style.padding = '0 2px';
  379. linkB.className = '_pxlazy';
  380. linkB.appendChild(document.createTextNode('[b]'));
  381. tdR.appendChild(linkB);*/
  382. // tdR.appendChild(document.createTextNode(' '));
  383. if (!rexb.test(srcR) && Imgs.indexOf(imgID) == -1 && !_e('ill_' + imgID)) {
  384. var linkS = document.createElement('a');
  385. linkS.href = srcR;
  386. linkS.target = '_blank';
  387. linkS.className = '_pxlazy _pxlazy_s';
  388. linkS.setAttribute('id', 'ill_' + imgID);
  389. linkS.appendChild(document.createTextNode('[s]'));
  390. if (aR2.tagName.toUpperCase() == 'DIV' && imgR.className.toLowerCase().indexOf('thumbnail') == -1) {
  391. var targetelem = getElementsByClassName('works_display');
  392. if(targetelem.length) {
  393. targetelem[0].appendChild(linkS);
  394. } else {
  395. tdR.appendChild(linkS);
  396. }
  397. } else {
  398. tdR.appendChild(linkS);
  399. }
  400. if (1/*rexc.test(imgR.src)||rexd.test(imgR.src)||rexe.test(imgR.src)*/) {
  401. //GM_log("postProcImg.push("+imgID+")"+imgR.src);
  402. postProcImg.push({id:imgID, url:srcR});
  403. }
  404. Imgs.push(imgID);
  405. }
  406. }
  407. }
  408.  
  409. var ItemsDiv = document.getElementsByTagName('div');
  410. //GM_log("ItemsDiv.length="+ItemsDiv.length);
  411. for (var i = 0; i < ItemsDiv.length; i++) {
  412. var divR = ItemsDiv[i];
  413. var aR = divR.parentNode.parentNode;
  414. var rexf = /\/img-master\//;
  415. var imgSrc;
  416. try{
  417. imgSrc=divR.style.backgroundImage.substr(5);
  418. imgSrc=imgSrc.substr(0,imgSrc.length-2);
  419. }catch(e) {}
  420. if(!imgSrc && divR.getAttribute("role")=='presentation') {
  421. try{
  422. imgSrc=window.getComputedStyle(divR,null).getPropertyValue('background-image').substr(5);
  423. imgSrc=imgSrc.substr(0,imgSrc.length-2);
  424. }catch(e) {}
  425. }
  426. var isThumbnail = ((' ' + divR.className + ' ').indexOf(' lazyloaded ') > -1)
  427. if(isThumbnail || rexf.test(imgSrc)) {
  428. /*var imgID = GetImageIDFromLink(divR.style.backgroundImage);
  429. var imgSrc=divR.style.backgroundImage.substr(5);
  430. imgSrc=imgSrc.substr(0,imgSrc.length-2);*/
  431. var imgID = GetImageIDFromLink(imgSrc);
  432. //GM_log("imgSrc="+imgSrc);
  433. var srcR = imgSrc.replace(/_s\.|_m\.|_100\.|_64x64|_master1200|_custom1200|_square1200\./i, ".");
  434. if (rexf.test(imgSrc) && !_e('ill_' + imgID)) {
  435. // GM_log("style.backgroundImage="+imgSrc);
  436.  
  437. var linkS = document.createElement('a');
  438. linkS.href = srcR;
  439. linkS.target = '_blank';
  440. linkS.className = '_pxlazy _pxlazy_s';
  441. linkS.setAttribute('id', 'ill_' + imgID);
  442. linkS.appendChild(document.createTextNode('[s]'));
  443.  
  444. if(aR.tagName.toUpperCase() == 'A') aR = aR.parentNode;
  445. aR.appendChild(linkS);
  446. postProcImg.push({id:imgID, url:imgSrc});
  447. }
  448. }
  449. }
  450.  
  451. if (postProcImg.length > 0) {
  452. for (var x = 0; x < postProcImg.length; x++) {
  453. if(accessToken) {
  454. GM_xmlhttpRequest({
  455. url: 'https://public-api.secure.pixiv.net/v1/works/' + postProcImg[x].id + '.json?image_sizes=large',
  456. method: "GET",
  457. headers: {
  458. Referer: "http://www.pixiv.net",
  459. "Authorization": "Bearer " + accessToken,
  460. "Cookie": sessID1
  461. },
  462. onload: function (response) {
  463. if (response.status == 200) {
  464. var rexb = /source.pixiv.net/;
  465. // var rexU = /\/c\//;
  466. var rexU = /_ugoira/;
  467. var rexe = /\/c\//;
  468. var vals = JSON.parse(response.responseText);
  469. /*var vtxt = '';
  470. for(var x=0;x < vals.length;x++)
  471. vtxt=vtxt+x+':'+vals[x]+"\n";
  472. GM_log(vtxt);*/
  473. if (vals.status == "success") {
  474. var slnk, imgID, isRestricted;
  475. isRestricted = rexb.test(vals.response[0].image_urls.large);
  476. isUgoira = rexU.test(vals.response[0].image_urls.large);
  477. // if (!isRestricted) {
  478. //GM_log("imgID = vals[0]");
  479. imgID = vals.response[0].id;
  480. /* } else {
  481. //GM_log("GetImageIDFromLink("+response.finalUrl+")");
  482. imgID = GetImageIDFromLink(response.finalUrl);
  483. }*/
  484. slnk = _e('ill_' + imgID);
  485. if (slnk) {
  486. var goodSlink;
  487. if (vals.response[0].is_manga) {
  488. goodSlink = 'http://www.pixiv.net/member_illust.php?mode=manga&illust_id=' + imgID;
  489. slnk.innerHTML = '[M]';
  490. } else {
  491. var re = new RegExp('/' + imgID + '_.*$');
  492. if (isUgoira) {// grab zip!
  493. //GM_log("isUgoira");
  494. slnk.innerHTML = '[U]';
  495. goodSlink = vals.response[0].image_urls.large.replace(/img-original/, 'img-zip-ugoira').replace(re, '/' + imgID + '_ugoira1920x1080.zip');
  496. /* } else if (rexe.test(vals[9])) {// new 480mw URL
  497. //GM_log("480mw");
  498. goodSlink = vals[9].replace(/c\/480x960\//, '').replace(/img-master/, 'img-original').replace(re, '/' + vals[0] + '_p0.' + vals[2]);
  499. } else if (!isRestricted && !rexe.test(vals[9])) {// use 480mw instead
  500. //GM_log("480mw");
  501. goodSlink = vals[9].replace(/mobile\//, '').replace(re, '/' + vals[0] + '.' + vals[2]);
  502. } else { //salvage from profile image
  503. //GM_log("salvage");
  504. re = /\/[0-9_]+\..*$/;
  505. goodSlink = vals[29].replace(/mobile\//, '').replace(/profile\//, 'img/').replace(re, '/' + imgID + '.' + vals[2]);
  506. */
  507. } else {
  508. goodSlink = vals.response[0].image_urls.large;
  509. }
  510. }
  511. slnk.href = goodSlink;
  512. slnk.title=vals.response[0].reuploaded_time;
  513. slnk.className = '_pxlazy _pxlazy_s _pxlazy_s_new';
  514. }
  515. }
  516. } else if (response.status == 400) {
  517. accessToken ="";
  518. GM_setValue("accessToken",accessToken);
  519. }
  520. }
  521. });
  522. } else {
  523. //GM_log("check="+JSON.stringify(postProcImg[x], null, 4));
  524. //GM_log("check url="+(postProcImg[x]).url);
  525. GM_xmlhttpRequest({
  526. url: postProcImg[x].url,
  527. method: "HEAD",
  528. headers: {
  529. Referer: "http://www.pixiv.net",
  530. "Cookie": sessID1
  531. },
  532. onload: function (response) {
  533. var slnk, imgID, isRestricted;
  534. imgID = GetImageIDFromLink(response.finalUrl);
  535. slnk = _e('ill_' + imgID);
  536. //GM_log("response="+JSON.stringify(response, null, 4));
  537. if (response.status == 200) {
  538. //GM_log("url="+response.finalUrl+" exists");
  539. } else /* assume error */ {
  540. GM_log("url="+response.finalUrl+" NOT exist!");
  541. slnk.href = slnk.href.replace(/\.jpg$/,".png"); // dumb replacing jpg to png
  542. }
  543. }
  544. });
  545. }
  546. }
  547. }
  548.  
  549. /* var links = document.getElementsByTagName('a');
  550. var tagslink = /tags\.php\?tag=/;
  551. for (var i = 0; i < links.length; i++) {
  552. if (tagslink.test(links[i].href))
  553. links[i].href = links[i].href.replace("tags.php?tag=", "search.php?s_mode=s_tag&word=");
  554. }*/
  555.  
  556. if (unsafeWindow.pixiv && unsafeWindow.pixiv.context.images) {
  557. var illustID = GetImageIDFromLink(unsafeWindow.pixiv.context.images[0]/*[0]*/);
  558. isNewManga = (illustID >= 11319936);
  559. //GM_log("illustID="+illustID);
  560. GM_xmlhttpRequest({
  561. url: 'https://public-api.secure.pixiv.net/v1/works/' + illustID + '.json?image_sizes=large',
  562. method: "GET",
  563. headers: {
  564. Referer: "http://www.pixiv.net",
  565. "Authorization": "Bearer " + accessToken,
  566. "Cookie": sessID1
  567. },
  568. onload: function (response) {
  569. if (response.status == 200) {
  570. //GM_log(response.responseText);
  571. var vals = JSON.parse(response.responseText);
  572. var rexe = /\/c\//;
  573. if(vals.status == "success") {
  574. mangaFormat = vals.response[0].metadata.pages[0].image_urls.large.split('.').pop();
  575. //GM_log(mangaFormat);
  576. /*var vtxt = '';
  577. for(var x=0;x < vals.length;x++)
  578. vtxt=vtxt+x+':'+vals[x]+"\n";
  579. GM_log(vtxt);*/
  580. //GM_log("2nd");
  581. /*if (rexe.test(vals[9]))*/ mangaFull();
  582. }
  583. } else if (response.status == 400) {
  584. accessToken ="";
  585. GM_setValue("accessToken",accessToken);
  586. }
  587. }
  588. });
  589. var rexe = /\/c\//;
  590. //GM_log("isNewManga");
  591. //setTimeout(mangaFull,250);
  592. //GM_log("2nd");
  593. // mangaFull();
  594. }
  595. }
  596.  
  597. var vp_w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
  598. var vp_h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
  599. function resizeImg(obj){
  600. //console.log("resizeImg");
  601. var imgW=obj.width;
  602. var imgH=obj.height;
  603. var imgAR=imgW/imgH;
  604.  
  605. obj.alt = obj.src;
  606.  
  607. /* set min size to 16x16px */
  608. obj.style.minWidth = '16px';
  609. obj.style.minHeight = '16px';
  610.  
  611. if(imgW > vp_w || imgH > vp_h) {
  612. if(imgAR < 1.0) {
  613. obj.height = vp_h*0.95;
  614. obj.width = obj.height*imgAR;
  615. } else {
  616. obj.width = vp_w*0.88;
  617. obj.height = obj.width/imgAR;
  618. }
  619. }
  620. }
  621.  
  622. function mangaFull() {
  623. Items = document.getElementsByTagName('img');
  624. var rexe = /\/img-/;
  625. for (var x = 0; x < unsafeWindow.pixiv.context.images.length; x++) {
  626. if (isNewManga) {
  627. if(rexe.test(unsafeWindow.pixiv.context.images[x]))
  628. unsafeWindow.pixiv.context.images[x]/*[0]*/ = unsafeWindow.pixiv.context.images[x]/*[0]*/.replace(/c\/1200x1200\//, '').replace(/img-master/, 'img-original').replace(/_p(\d+).*(\.[a-zA-Z\?\d]+)$/, "_p$1."+mangaFormat);
  629. else
  630. unsafeWindow.pixiv.context.images[x]/*[0]*/ = unsafeWindow.pixiv.context.images[x]/*[0]*/.replace(/_p(\d+\.[a-zA-Z\?\d]+)$/, "_big_p$1");
  631. }
  632. preloadImg.push(new Image());
  633. preloadImg[preloadImg.length - 1].src = unsafeWindow.pixiv.context.images[x]/*[0]*/;
  634. }
  635.  
  636. for (var x = 0; x < Items.length; x++) {
  637. var datasrc = Items[x].getAttribute("data-src");
  638. if (datasrc) {
  639. //GM_log("original-datasrc="+datasrc+" ,mangaFormat="+mangaFormat);
  640. if(rexe.test(datasrc))
  641. datasrc = datasrc.replace(/c\/1200x1200\//, '').replace(/img-master/, 'img-original').replace(/_p(\d+).*(\.[a-zA-Z\?\d]+)$/, "_p$1."+mangaFormat);
  642. else
  643. datasrc = datasrc.replace(/_p(\d+\.[a-zA-Z\?\d]+)$/, "_big_p$1");
  644. //GM_log("new-datasrc="+datasrc+" ,mangaFormat="+mangaFormat);
  645. }
  646. Items[x].setAttribute("data-src", datasrc);
  647. Items[x].addEventListener('load', function(e) {resizeImg(e.target);},true);
  648. if (isNewManga) {
  649. //GM_log(x+".src="+Items[x].src);
  650. if(datasrc)
  651. Items[x].src = datasrc;
  652. else if(rexe.test(Items[x].src))
  653. Items[x].src = Items[x].src.replace(/c\/1200x1200\//, '').replace(/img-master/, 'img-original').replace(/_p(\d+).*(\.[a-zA-Z\?\d]+)$/, "_p$1$2");
  654. else
  655. Items[x].src = datasrc ? datasrc : Items[x].src.replace(/_p(\d+\.[a-zA-Z\?\d]+)$/, "_big_p$1");
  656. }
  657. }
  658. }
  659.  
  660. if(!autoLogin) {
  661. GM_registerMenuCommand("Enable Auto Login", function(){
  662. GM_setValue("autoLogin",true);
  663. });
  664. } else {
  665. GM_registerMenuCommand("Disable Auto Login", function(){
  666. GM_setValue("autoLogin",false);
  667. });
  668. }
  669. window.addEventListener("load", pixivlink, true);
  670.  
  671. // create button for manually trigger source link generation
  672. tmp = document.createElement ('input');
  673. tmp.id = 'pxlink';
  674. tmp.type = 'button';
  675. tmp.value='P';
  676. tmp.accessKey='x';
  677. tmp.style.position = "fixed";
  678. tmp.style.bottom = "0px";
  679. tmp.style.left = "0px";
  680. tmp.style.backgroundColor="#fdd";
  681.  
  682. tmp.addEventListener("click", function(e){postProcImg = new Array();pixivlink_run = 0;pixivlink();}, false);
  683. document.body.appendChild(tmp);
  684.  
  685. if(location.pathname != "/")
  686. setTimeout(function() {
  687. document.getElementById('pxlink').click();
  688. }, 2000);