Pixiv Previewer

显示预览图(支持单图,多图,动图);动图压缩包下载;搜索页按热门度(收藏数)排序并显示收藏数,适配11月更新。

当前为 2020-12-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Pixiv Previewer
  3. // @namespace https://github.com/Ocrosoft/PixivPreviewer
  4. // @version 3.3.3
  5. // @description Display preview images (support single image, multiple images, moving images); Download animation(.zip); Sorting the search page by favorite count(and display it). Updated for the latest search page.
  6. // @description:zh-CN 显示预览图(支持单图,多图,动图);动图压缩包下载;搜索页按热门度(收藏数)排序并显示收藏数,适配11月更新。
  7. // @description:ja プレビュー画像の表示(単一画像、複数画像、動画のサポート); アニメーションのダウンロード(.zip); お気に入りの数で検索ページをソートします(そして表示します)。 最新の検索ページ用に更新されました。
  8. // @description:zh_TW 顯示預覽圖像(支持單幅圖像,多幅圖像,運動圖像); 下載動畫(.zip); 按收藏夾數對搜索頁進行排序(並顯示)。 已為最新的搜索頁面適配。
  9. // @author Ocrosoft
  10. // @match *://www.pixiv.net/*
  11. // @grant none
  12. // @compatible Chrome
  13. // ==/UserScript==
  14.  
  15. // 测试 JQuery,如果不支持就插入
  16. //let $ = function () { };
  17. try {
  18. $();
  19. } catch (e) {
  20. let script = document.createElement('script');
  21. script.src = 'https://code.jquery.com/jquery-2.2.4.min.js';
  22. document.head.appendChild(script);
  23. }
  24.  
  25. let Lang = {
  26. // 中文-中国大陆
  27. zh_CN: 0,
  28. // 英语-美国
  29. en_US: 1,
  30. };
  31. let Texts = {};
  32. Texts[Lang.zh_CN] = {
  33. // 安装或更新后弹出的提示
  34. install_title: '欢迎使用 PixivPreviewer v',
  35. install_body: '<div style="position: absolute;width: 40%;left: 30%;top: 30%;font-size: 20px; color: white;"><p style="text-indent: 2em; color: skyblue;">功能更新(v3.3.0): 增加“延迟显示预览图”设置项,默认延迟200毫秒显示,可在设置中调节以避免预览图遮挡操作。</p><br><p style="text-indent: 2em;">欢迎反馈问题和提出建议!><a style="color: green;" href="https://greasyfork.org/zh-CN/scripts/30766-pixiv-previewer/feedback" target="_blank">反馈页面</a><</p><br><p style="text-indent: 2em;">如果您是第一次使用,推荐到<a style="color: green;" href="https://greasyfork.org/zh-CN/scripts/30766-pixiv-previewer" target="_blank"> 详情页 </a>查看脚本介绍。</p></div>',
  36. // 设置项
  37. setting_preview: '预览',
  38. setting_sort: '排序(仅搜索页生效)',
  39. setting_anime: '动图下载(动图预览及详情页生效)',
  40. setting_origin: '预览时优先显示原图(慢)',
  41. setting_previewDelay: '延迟显示预览图(毫秒)',
  42. setting_maxPage: '每次排序时统计的最大页数',
  43. setting_hideWork: '隐藏收藏数少于设定值的作品',
  44. setting_hideFav: '排序时隐藏已收藏的作品',
  45. setting_hideFollowed: '排序时隐藏已关注画师作品',
  46. setting_blank: '使用新标签页打开作品详情页',
  47. setting_turnPage: '使用键盘←→进行翻页(排序后的搜索页)',
  48. setting_save: '保存设置',
  49. setting_reset: '重置脚本',
  50. setting_resetHint: '这会删除所有设置,相当于重新安装脚本,确定要重置吗?',
  51. // 搜索时过滤值太高
  52. sort_noWork: '没有可以显示的作品',
  53. sort_getWorks: '正在获取第%1/%2页作品',
  54. sort_getBookmarkCount: '获取收藏数:%1/%2',
  55. sort_getPublicFollowing: '获取公开关注画师',
  56. sort_getPrivateFollowing: '获取私有关注画师',
  57. sort_filtering: '过滤%1收藏量低于%2的作品',
  58. sort_filteringHideFavorite: '已收藏和',
  59. };
  60. // translate by google
  61. Texts[Lang.en_US] = {
  62. install_title: 'Welcome to PixivPreviewer v',
  63. install_body: '<div style="position: absolute;width: 40%;left: 30%;top: 30%;font-size: 20px; color: white;"><p style="text-indent: 2em; color: skyblue;">Feature update(v3.2.0): Add an option "Delay of display preview image", default value is 200 million seconds, you can change it in the settings.</p><br><p style="text-indent: 2em;">Feedback questions and suggestions are welcome! ><a style="color: green;" href="https://greasyfork.org/zh-CN/scripts/30766-pixiv-previewer/feedback" target="_blank">Feedback Page</a><</p><br><p style="text-indent: 2em;">If you are using it for the first time, it is recommended to go to the<a style="color: green;" href="https://greasyfork.org/zh-CN/scripts/30766-pixiv-previewer" target="_blank"> Details Page </a>to see the script introduction.</p></div>',
  64. setting_preview: 'Preview',
  65. setting_sort: 'Sorting (Search page)',
  66. setting_anime: 'Animation download (Preview and Artwork page)',
  67. setting_origin: 'Display original image when preview (slow)',
  68. setting_previewDelay: 'Delay of display preview image(Million seconds)',
  69. setting_maxPage: 'Maximum number of pages counted per sort',
  70. setting_hideWork: 'Hide works with bookmark count less than set value',
  71. setting_hideFav: 'Hide favorites when sorting',
  72. setting_hideFollowed: 'Hide artworks of followed artists when sorting',
  73. setting_blank: 'Open works\' details page in new tab',
  74. setting_turnPage: 'Use ← → to turn pages (Search page)',
  75. setting_save: 'Save',
  76. setting_reset: 'Reset',
  77. setting_resetHint: 'This will delete all settings and set it to default. Are you sure?',
  78. sort_noWork: 'No works to display',
  79. sort_getWorks: 'Getting artworks of page: %1 of %2',
  80. sort_getBookmarkCount: 'Getting bookmark count of artworks:%1 of %2',
  81. sort_getPublicFollowing: 'Getting public following list',
  82. sort_getPrivateFollowing: 'Getting private following list',
  83. sort_filtering: 'Filtering%1works with bookmark count less than %2',
  84. sort_filteringHideFavorite: ' favorited works and ',
  85. };
  86.  
  87. let LogLevel = {
  88. None: 0,
  89. Error: 1,
  90. Warning: 2,
  91. Info: 3,
  92. Elements: 4,
  93. };
  94. function DoLog(level, msgOrElement) {
  95. if (level <= g_logLevel) {
  96. let prefix = '%c';
  97. let param = '';
  98.  
  99. if (level == LogLevel.Error) {
  100. prefix += '[Error]';
  101. param = 'color:#ff0000';
  102. } else if (level == LogLevel.Warning) {
  103. prefix += '[Warning]';
  104. param = 'color:#ffa500';
  105. } else if (level == LogLevel.Info) {
  106. prefix += '[Info]';
  107. param = 'color:#000000';
  108. } else if (level == LogLevel.Elements) {
  109. prefix += 'Elements';
  110. param = 'color:#000000';
  111. }
  112.  
  113. if (level != LogLevel.Elements) {
  114. console.log(prefix + msgOrElement, param);
  115. } else {
  116. console.log(msgOrElement);
  117. }
  118.  
  119. if (++g_logCount > 512) {
  120. //console.clear();
  121. g_logCount = 0;
  122. }
  123. }
  124. }
  125.  
  126. // 语言,如果 g_autoDetectLanguage 的值为 true,则默认值无效;如果希望使用某种语言,请这样操作:
  127. // 1.修改 g_language 的值,中文(Lang.zh_CN)、英文(Lang.en_US)
  128. // 2.将 g_autoDetectLanguage 的值从 true 修改为 false
  129. // =====
  130. // If you want to set language instead auto detect it, follow this:
  131. // 1.Change g_language's value, Chinese(Lang.zh_CN), English(Lang.en_US).
  132. // 2.Change g_autoDetectLanguage's value from true to false.
  133. let g_language = Lang.zh_CN;
  134. // 自动检测语言,开启后 g_language 的默认值将无效
  135. let g_autoDetectLanguage = true;
  136. // 版本号,第三位不需要跟脚本的版本号对上,第三位更新只有需要弹更新提示的时候才需要更新这里
  137. let g_version = '3.2.0';
  138. // 添加收藏需要这个
  139. let g_csrfToken = '';
  140. // 打的日志数量,超过一定数值清空控制台
  141. let g_logCount = 0;
  142. // 当前页面类型
  143. let g_pageType = -1;
  144. // 图片详情页的链接,使用时替换 #id#
  145. let g_artworkUrl = '/artworks/#id#';
  146. // 获取图片链接的链接
  147. let g_getArtworkUrl = '/ajax/illust/#id#/pages';
  148. // 获取动图下载链接的链接
  149. let g_getUgoiraUrl = '/ajax/illust/#id#/ugoira_meta';
  150. // 鼠标位置
  151. let g_mousePos = { x: 0, y: 0 };
  152. // 加载中图片
  153. let g_loadingImage = 'https://pp-1252089172.cos.ap-chengdu.myqcloud.com/loading.gif';
  154. // 页面打开时的 url
  155. let initialUrl = location.href;
  156. // 默认设置,仅用于首次脚本初始化
  157. let g_defaultSettings = {
  158. 'enablePreview': 1,
  159. 'enableSort': 1,
  160. 'enableAnimeDownload': 1,
  161. 'original': 0,
  162. 'previewDelay': 200,
  163. 'pageCount': 2,
  164. 'favFilter': 0,
  165. 'hideFavorite': 0,
  166. 'hideFollowed': 0,
  167. 'linkBlank': 1,
  168. 'pageByKey': 0,
  169. 'logLevel': 1,
  170. 'version': g_version,
  171. };
  172. // 设置
  173. let g_settings;
  174. // 日志等级
  175. let g_logLevel = LogLevel.Error;
  176. // 排序时同时请求收藏量的 Request 数量,没必要太多,并不会加快速度
  177. let g_maxXhr = 64;
  178. // 排序是否完成(如果排序时页面出现了非刷新切换,强制刷新)
  179. let g_sortComplete = true;
  180.  
  181. // 页面相关的一些预定义,包括处理页面元素等
  182. let PageType = {
  183. // 搜索
  184. Search: 0,
  185. // 关注的新作品
  186. BookMarkNew: 1,
  187. // 发现
  188. Discovery: 2,
  189. // 用户主页
  190. Member: 3,
  191. // 首页
  192. Home: 4,
  193. // 排行榜
  194. Ranking: 5,
  195. // 大家的新作品
  196. NewIllust: 6,
  197. // R18
  198. R18: 7,
  199. // 自己的收藏页
  200. BookMark: 8,
  201. // 动态
  202. Stacc: 9,
  203. // 作品详情页(处理动图预览及下载)
  204. Artwork: 10,
  205.  
  206. // 总数
  207. PageTypeCount: 11,
  208. };
  209. let Pages = {};
  210. /* Pages 必须实现的函数
  211. * PageTypeString: string,字符串形式的 PageType
  212. * bool CheckUrl: function(string url),用于检查一个 url 是否是当前页面的目标 url
  213. * ReturnMap ProcessPageElements: function(),处理页面(寻找图片元素、添加属性等),返回 ReturnMap
  214. * ReturnMap GetProcessedPageElements: function(), 返回上一次 ProcessPageElements 的返回值(如果没有上次调用则调用一次)
  215. * Object GetToolBar: function(), 返回工具栏元素(右下角那个,用来放设置按钮)
  216. * HasAutoLoad: bool,表示这个页面是否有自动加载功能
  217. */
  218. let ReturnMapSample = {
  219. // 页面是否加载完成,false 意味着后面的成员无效
  220. loadingComplete: false,
  221. // 控制元素,每个图片的鼠标响应元素
  222. controlElements: [],
  223. // 可有可无,如果为 true,强制重新刷新预览功能
  224. forceUpdate: false,
  225. };
  226. let ControlElementsAttributesSample = {
  227. // 图片信息,内容如下:
  228. // [必需] 图片 id
  229. illustId: 0,
  230. // [必需] 图片类型(0:普通图片,2:动图)
  231. illustType: 0,
  232. // [必需] 页数
  233. pageCount: 1,
  234. // [可选] 标题
  235. title: '',
  236. // [可选] 作者 id
  237. userId: 0,
  238. // [可选] 作者昵称
  239. userName: '',
  240. // [可选] 收藏数
  241. bookmarkCount: 0,
  242. };
  243.  
  244. function findToolbarCommon() {
  245. /*let div = $('#root').children('div');
  246. // 搜索页前面插入了一个新的 div 节点
  247. if ($('#root').children('#gtm-var-theme-kind').length > 0) {
  248. let max_children = 0;
  249. let max_children_i = 0;
  250. for (let i = 0; i < div.length; ++i) {
  251. if ($(div[i]).children().length > max_children) {
  252. max_children_i = i;
  253. max_children = $(div[i]).children().length;
  254. }
  255. }
  256. div = $(div[max_children_i]).children();
  257. }
  258. for (let i = div.length - 1; i >= 0; i--) {
  259. if ($(div.get(i)).children('ul').length > 0) {
  260. return $(div.get(i)).children('ul').get(0);
  261. }
  262. }*/
  263. // 目前第三级div,除了目标div外,子元素都是div
  264. return $('#root>div>div>ul').get(0);
  265. }
  266. function findToolbarOld() {
  267. return $('._toolmenu').get(0);
  268. }
  269.  
  270. Pages[PageType.Search] = {
  271. PageTypeString: 'SearchPage',
  272. CheckUrl: function (url) {
  273. // 没有 /artworks 的页面不支持
  274. return /^https?:\/\/www.pixiv.net\/tags\/.*\/(artworks|illustrations|manga)/.test(url) ||
  275. /^https?:\/\/www.pixiv.net\/en\/tags\/.*\/(artworks|illustrations|manga)/.test(url);
  276. },
  277. ProcessPageElements: function () {
  278. let returnMap = {
  279. loadingComplete: false,
  280. controlElements: [],
  281. };
  282.  
  283. let sections = $('section');
  284. DoLog(LogLevel.Info, 'Page has ' + sections.length + ' <section>.');
  285. DoLog(LogLevel.Elements, sections);
  286. // 先对 section 进行评分
  287. let sectionIndex = -1;
  288. let bestScore = -99;
  289. sections.each(function (i, e) {
  290. let section = $(e);
  291. let score = 0;
  292. if (section.find('ul').length > 0) {
  293. let childrenCount = section.children().length;
  294. if (childrenCount != 2) {
  295. DoLog(LogLevel.Warning, '<ul> was found in this <section>, but it has ' + childrenCount + ' children!');
  296. score--;
  297. }
  298. let ul = section.find('ul');
  299. if (ul.length > 1) {
  300. DoLog(LogLevel.Warning, 'This section has more than one <ul>?');
  301. score--;
  302. }
  303. if ($(ul.parent().get(0)).css('display') == 'none' || $(ul.get(0)).css('display') == 'none') {
  304. DoLog(LogLevel.Info, '<ul> or it\'s parentNode is not visible now, continue waiting.');
  305. sectionIndex = -1;
  306. bestScore = 999;
  307. return false;
  308. }
  309. if ($(ul.get(0)).next().length === 0) {
  310. DoLog(LogLevel.Info, 'Page selector not exists, continue waiting.');
  311. sectionIndex = -1;
  312. bestScore = 999;
  313. return false;
  314. }
  315. let lis = ul.find('li');
  316. if (lis.length === 0) {
  317. DoLog(LogLevel.Info, 'This <ul> has 0 children, will be skipped.');
  318. return false;
  319. }
  320. if ($(lis.get(0)).find('figure').length > 0) {
  321. DoLog(LogLevel.Warning, '<figure> was found in the first <li>, continue waiting.');
  322. sectionIndex = -1;
  323. bestScore = 999;
  324. return false;
  325. }
  326. if (lis.length > 4) {
  327. score += 5;
  328. }
  329. // 正确的会在后面
  330. if (score >= bestScore) {
  331. bestScore = score;
  332. sectionIndex = i;
  333. }
  334. } else {
  335. DoLog(LogLevel.Info, 'This section(' + i + ' is not has <ul>, will be skipped.');
  336. }
  337. });
  338.  
  339. if (sectionIndex == -1) {
  340. if (bestScore < 100) {
  341. DoLog(LogLevel.Error, 'No suitable <section>!');
  342. }
  343. return returnMap;
  344. }
  345.  
  346. let lis = $(sections[sectionIndex]).find('ul').find('li');
  347. lis.each(function (i, e) {
  348. let li = $(e);
  349.  
  350. // 只填充必须的几个,其他的目前用不着
  351. let ctlAttrs = {
  352. illustId: 0,
  353. illustType: 0,
  354. pageCount: 1,
  355. };
  356.  
  357. let img = $(li.find('img').get(0));
  358. let imageLink = img.parent().parent();
  359. let additionDiv = img.parent().prev();
  360. let animationSvg = img.parent().find('svg');
  361. let pageCountSpan = additionDiv.find('span');
  362.  
  363. if (img == null || imageLink == null) {
  364. DoLog(LogLevel.Warning, 'Can not found img or imageLink, skip this.');
  365. return;
  366. }
  367.  
  368. let link = imageLink.attr('href');
  369. if (link == null) {
  370. DoLog(LogLevel.Warning, 'Invalid href, skip this.');
  371. return;
  372. }
  373. let linkMatched = link.match(/artworks\/(\d+)/);
  374. let illustId = '';
  375. if (linkMatched) {
  376. ctlAttrs.illustId = linkMatched[1];
  377. } else {
  378. DoLog(LogLevel.Error, 'Get illustId failed, skip this list item!');
  379. return;
  380. }
  381. if (animationSvg.length > 0) {
  382. ctlAttrs.illustType = 2;
  383. }
  384. if (pageCountSpan.length > 0) {
  385. ctlAttrs.pageCount = parseInt(pageCountSpan.text());
  386. }
  387.  
  388. // 添加 attr
  389. let control = li.children('div:first').children('div:first');
  390. control.attr({
  391. 'illustId': ctlAttrs.illustId,
  392. 'illustType': ctlAttrs.illustType,
  393. 'pageCount': ctlAttrs.pageCount
  394. });
  395.  
  396. control.addClass('pp-control');
  397. });
  398. returnMap.controlElements = $('.pp-control');
  399. this.private.pageSelector = $($(sections[sectionIndex]).find('ul').get(0)).next().get(0);
  400. returnMap.loadingComplete = true;
  401. this.private.imageListConrainer = $(sections[sectionIndex]).find('ul').get(0);
  402.  
  403. DoLog(LogLevel.Info, 'Process page elements complete.');
  404. DoLog(LogLevel.Elements, returnMap);
  405.  
  406. this.private.returnMap = returnMap;
  407. return returnMap;
  408. },
  409. GetProcessedPageElements: function () {
  410. if (this.private.returnMap == null) {
  411. return this.ProcessPageElements();
  412. }
  413. return this.private.returnMap;
  414. },
  415. GetToolBar: function () {
  416. return findToolbarCommon();
  417. },
  418. // 搜索页有 lazyload,不开排序的情况下,最后几张图片可能会无法预览。这里把它当做自动加载处理
  419. HasAutoLoad: true,
  420. GetImageListContainer: function () {
  421. return this.private.imageListConrainer;
  422. },
  423. GetFirstImageElement: function () {
  424. return $(this.private.imageListConrainer).find('li').get(0);
  425. },
  426. GetPageSelector: function () {
  427. return this.private.pageSelector;
  428. },
  429. private: {
  430. imageListContainer: null,
  431. pageSelector: null,
  432. returnMap: null,
  433. },
  434. };
  435. Pages[PageType.BookMarkNew] = {
  436. PageTypeString: 'BookMarkNewPage',
  437. CheckUrl: function (url) {
  438. return /^https:\/\/www.pixiv.net\/bookmark_new_illust.php.*/.test(url) ||
  439. /^https:\/\/www.pixiv.net\/bookmark_new_illust_r18.php.*/.test(url);
  440. },
  441. ProcessPageElements: function () {
  442. let returnMap = {
  443. loadingComplete: false,
  444. controlElements: [],
  445. };
  446.  
  447. let containerDiv = $('#js-mount-point-latest-following').children('div:first');
  448. if (containerDiv.length > 0) {
  449. DoLog(LogLevel.Info, 'Found container div.');
  450. DoLog(LogLevel.Elements, containerDiv);
  451. } else {
  452. DoLog(LogLevel.Error, 'Can not found container div.');
  453. return returnMap;
  454. }
  455.  
  456. containerDiv.children().each(function (i, e) {
  457. let _this = $(e);
  458.  
  459. let figure = _this.find('figure');
  460. if (figure.length === 0) {
  461. DoLog(LogLevel.Warning, 'Can not found <fingure>, skip this element.');
  462. return;
  463. }
  464.  
  465. let link = figure.children('div:first').children('a:first');
  466. if (link.length === 0) {
  467. DoLog(LogLevel.Warning, 'Can not found <a>, skip this element.');
  468. return;
  469. }
  470.  
  471. let ctlAttrs = {
  472. illustId: 0,
  473. illustType: 0,
  474. pageCount: 1,
  475. };
  476.  
  477. let href = link.attr('href');
  478. if (href == null || href === '') {
  479. DoLog(LogLevel.Warning, 'No href found, skip.');
  480. return;
  481. } else {
  482. let matched = href.match(/artworks\/(\d+)/);
  483. if (matched) {
  484. ctlAttrs.illustId = matched[1];
  485. } else {
  486. DoLog(LogLevel.Warning, 'Can not found illust id, skip.');
  487. return;
  488. }
  489. }
  490.  
  491. if (link.children().length > 1) {
  492. if (link.children('div:first').find('span').length > 0) {
  493. let span = link.children('div:first').children('span:first');
  494. if (span.length === 0) {
  495. DoLog(LogLevel.Warning, 'Can not found <span>, skip this element.');
  496. return;
  497. }
  498. ctlAttrs.pageCount = span.text();
  499. } else {
  500. ctlAttrs.illustType = 2;
  501. }
  502. }
  503.  
  504. let control = figure.children('div:first');
  505. control.attr({
  506. 'illustId': ctlAttrs.illustId,
  507. 'illustType': ctlAttrs.illustType,
  508. 'pageCount': ctlAttrs.pageCount
  509. });
  510.  
  511. returnMap.controlElements.push(control.get(0));
  512. });
  513.  
  514. DoLog(LogLevel.Info, 'Process page elements complete.');
  515. DoLog(LogLevel.Elements, returnMap);
  516.  
  517. returnMap.loadingComplete = true;
  518. this.private.returnMap = returnMap;
  519. return returnMap;
  520. },
  521. GetProcessedPageElements: function () {
  522. if (this.private.returnMap == null) {
  523. return this.ProcessPageElements();
  524. }
  525. return this.private.returnMap;
  526. },
  527. GetToolBar: function () {
  528. return findToolbarOld();
  529. },
  530. HasAutoLoad: false,
  531. private: {
  532. returnMap: null,
  533. },
  534. };
  535. Pages[PageType.Discovery] = {
  536. PageTypeString: 'DiscoveryPage',
  537. CheckUrl: function (url) {
  538. return /^https?:\/\/www.pixiv.net\/discovery.*/.test(url);
  539. },
  540. ProcessPageElements: function () {
  541. let returnMap = {
  542. loadingComplete: false,
  543. controlElements: [],
  544. };
  545.  
  546. let containerDiv = $('.gtm-illust-recommend-zone');
  547. if (containerDiv.length > 0) {
  548. DoLog(LogLevel.Info, 'Found container div.');
  549. DoLog(LogLevel.Elements, containerDiv);
  550. } else {
  551. DoLog(LogLevel.Error, 'Can not found container div.');
  552. return returnMap;
  553. }
  554.  
  555. containerDiv.children().each(function (i, e) {
  556. let _this = $(e);
  557.  
  558. let figure = _this.find('figure');
  559. if (figure.length === 0) {
  560. DoLog(LogLevel.Warning, 'Can not found <fingure>, skip this element.');
  561. return;
  562. }
  563.  
  564. let link = figure.children('div:first').children('a:first');
  565. if (link.length === 0) {
  566. DoLog(LogLevel.Warning, 'Can not found <a>, skip this element.');
  567. return;
  568. }
  569.  
  570. let ctlAttrs = {
  571. illustId: 0,
  572. illustType: 0,
  573. pageCount: 1,
  574. };
  575.  
  576. let href = link.attr('href');
  577. if (href == null || href === '') {
  578. DoLog(LogLevel.Warning, 'No href found, skip.');
  579. return;
  580. } else {
  581. let matched = href.match(/artworks\/(\d+)/);
  582. if (matched) {
  583. ctlAttrs.illustId = matched[1];
  584. } else {
  585. DoLog(LogLevel.Warning, 'Can not found illust id, skip.');
  586. return;
  587. }
  588. }
  589.  
  590. if (link.children().length > 1) {
  591. if (link.children('div:first').find('span').length > 0) {
  592. let span = link.children('div:first').children('span:first');
  593. if (span.length === 0) {
  594. DoLog(LogLevel.Warning, 'Can not found <span>, skip this element.');
  595. return;
  596. }
  597. ctlAttrs.pageCount = span.text();
  598. } else if (link.children('div:last').css('background-image').indexOf('.svg') != -1) {
  599. ctlAttrs.illustType = 2;
  600. }
  601. }
  602.  
  603. let control = figure.children('div:first');
  604. control.attr({
  605. 'illustId': ctlAttrs.illustId,
  606. 'illustType': ctlAttrs.illustType,
  607. 'pageCount': ctlAttrs.pageCount
  608. });
  609.  
  610. returnMap.controlElements.push(control.get(0));
  611. });
  612.  
  613. DoLog(LogLevel.Info, 'Process page elements complete.');
  614. DoLog(LogLevel.Elements, returnMap);
  615.  
  616. returnMap.loadingComplete = true;
  617. this.private.returnMap = returnMap;
  618. return returnMap;
  619. },
  620. GetProcessedPageElements: function () {
  621. if (this.private.returnMap == null) {
  622. return this.ProcessPageElements();
  623. }
  624. return this.private.returnMap;
  625. },
  626. GetToolBar: function () {
  627. return findToolbarOld();
  628. },
  629. HasAutoLoad: true,
  630. private: {
  631. returnMap: null,
  632. },
  633. };
  634. Pages[PageType.Member] = {
  635. PageTypeString: 'MemberPage/MemberIllustPage/MemberBookMark',
  636. CheckUrl: function (url) {
  637. return /^https?:\/\/www.pixiv.net\/users\/\d+/.test(url);
  638. },
  639. ProcessPageElements: function () {
  640. let returnMap = {
  641. loadingComplete: false,
  642. controlElements: [],
  643. };
  644.  
  645. let sections = $('section');
  646. DoLog(LogLevel.Info, 'Page has ' + sections.length + ' <section>.');
  647. DoLog(LogLevel.Elements, sections);
  648.  
  649. let lis = sections.find('ul').find('li');
  650. lis.each(function (i, e) {
  651. let li = $(e);
  652.  
  653. // 只填充必须的几个,其他的目前用不着
  654. let ctlAttrs = {
  655. illustId: 0,
  656. illustType: 0,
  657. pageCount: 1,
  658. };
  659.  
  660. let img = $(li.find('img').get(0));
  661. let imageLink = img.parent().parent();
  662. let additionDiv = img.parent().prev();
  663. let animationSvg = img.parent().find('svg');
  664. let pageCountSpan = additionDiv.find('span');
  665.  
  666. if (!img || !imageLink) {
  667. DoLog(LogLevel.Warning, 'Can not found img or imageLink, skip this.');
  668. return;
  669. }
  670.  
  671. let link = imageLink.attr('href');
  672. if (link == null) {
  673. DoLog(LogLevel.Warning, 'Can not found illust id, skip this.');
  674. return;
  675. }
  676.  
  677. let linkMatched = link.match(/artworks\/(\d+)/);
  678. let illustId = '';
  679. if (linkMatched) {
  680. ctlAttrs.illustId = linkMatched[1];
  681. } else {
  682. DoLog(LogLevel.Error, 'Get illustId failed, skip this list item!');
  683. return;
  684. }
  685. if (animationSvg.length > 0) {
  686. ctlAttrs.illustType = 2;
  687. }
  688. if (pageCountSpan.length > 0) {
  689. ctlAttrs.pageCount = parseInt(pageCountSpan.text());
  690. }
  691.  
  692. // 添加 attr
  693. let control = li.children('div:first').children('div:first');
  694. if (control.length === 0) {
  695. control = li.children('div:last').children('div:first');
  696. }
  697. control.attr({
  698. 'illustId': ctlAttrs.illustId,
  699. 'illustType': ctlAttrs.illustType,
  700. 'pageCount': ctlAttrs.pageCount
  701. });
  702.  
  703. control.addClass('pp-control');
  704. });
  705. returnMap.controlElements = $('.pp-control');
  706. returnMap.loadingComplete = true;
  707.  
  708. DoLog(LogLevel.Info, 'Process page elements complete.');
  709. DoLog(LogLevel.Elements, returnMap);
  710.  
  711. this.private.returnMap = returnMap;
  712. return returnMap;
  713. },
  714. GetProcessedPageElements: function () {
  715. if (this.private.returnMap == null) {
  716. return this.ProcessPageElements();
  717. }
  718. return this.private.returnMap;
  719. },
  720. GetToolBar: function () {
  721. return findToolbarCommon();
  722. },
  723. // 跟搜索页一样的情况
  724. HasAutoLoad: true,
  725. private: {
  726. returnMap: null,
  727. },
  728. };
  729. Pages[PageType.Home] = {
  730. PageTypeString: 'HomePage',
  731. CheckUrl: function (url) {
  732. return /https?:\/\/www.pixiv.net\/?$/.test(url) ||
  733. /https?:\/\/www.pixiv.net\/en\/?$/.test(url);
  734. },
  735. ProcessPageElements: function () {
  736. let returnMap = {
  737. loadingComplete: false,
  738. controlElements: [],
  739. forceUpdate: false,
  740. };
  741.  
  742. let illust_div = $('div[type="illust"]');
  743.  
  744. DoLog(LogLevel.Info, 'This page has ' + illust_div.length + ' illust <div>.');
  745. if (illust_div.length < 1) {
  746. DoLog(LogLevel.Warning, 'Less than one <div>, continue waiting.');
  747. return returnMap;
  748. }
  749.  
  750. // 实际里面还套了一个 div,处理一下,方便一点
  751. let illust_div_c = [];
  752. illust_div.each(function(i, e) {
  753. illust_div_c.push($(e).children('div:first'));
  754. });
  755. illust_div = illust_div_c;
  756. $.each(illust_div, function (i, e) {
  757. let _this = $(e);
  758.  
  759. let a = _this.children('a:first');
  760. if (a.length == 0 || a.attr('href').indexOf('artworks') == -1) {
  761. DoLog(LogLevel.Warning, 'No href or an invalid href was found, skip this.');
  762. return;
  763. }
  764.  
  765. let ctlAttrs = {
  766. illustId: 0,
  767. illustType: 0,
  768. pageCount: 1,
  769. };
  770.  
  771. let illustId = a.attr('href').match(/\d+/);
  772. if (illustId == null) {
  773. DoLog(LogLevel.Warning, 'Can not found illust id of this image, skip.');
  774. return;
  775. } else {
  776. ctlAttrs.illustId = illustId[0];
  777. }
  778. let pageCount = a.children('div:first').find('span');
  779. if (pageCount.length > 0) {
  780. ctlAttrs.pageCount = parseInt($(pageCount.get(pageCount.length - 1)).text());
  781. }
  782. if ($(a.children('div').get(1)).find('svg').length > 0) {
  783. ctlAttrs.illustType = 2;
  784. }
  785.  
  786. let control = a;
  787. if (control.attr('illustId') != ctlAttrs.illustId) {
  788. returnMap.forceUpdate = true;
  789. }
  790. control.attr({
  791. 'illustId': ctlAttrs.illustId,
  792. 'illustType': ctlAttrs.illustType,
  793. 'pageCount': ctlAttrs.pageCount
  794. });
  795.  
  796. returnMap.controlElements.push(control.get(0));
  797. });
  798.  
  799. DoLog(LogLevel.Info, 'Process page elements complete.');
  800. DoLog(LogLevel.Elements, returnMap);
  801.  
  802. returnMap.loadingComplete = true;
  803. this.private.returnMap = returnMap;
  804. return returnMap;
  805. },
  806. GetProcessedPageElements: function () {
  807. if (this.private.returnMap == null) {
  808. return this.ProcessPageElements();
  809. }
  810. return this.private.returnMap;
  811. },
  812. GetToolBar: function () {
  813. return findToolbarCommon();
  814. },
  815. HasAutoLoad: true,
  816. private: {
  817. returnMap: null,
  818. },
  819. };
  820. Pages[PageType.Ranking] = {
  821. PageTypeString: 'RankingPage',
  822. CheckUrl: function (url) {
  823. return /^https?:\/\/www.pixiv.net\/ranking.php.*/.test(url);
  824. },
  825. ProcessPageElements: function () {
  826. let returnMap = {
  827. loadingComplete: false,
  828. controlElements: [],
  829. };
  830.  
  831. let works = $('._work');
  832.  
  833. DoLog(LogLevel.Info, 'Found .work, length: ' + works.length);
  834. DoLog(LogLevel.Elements, works);
  835.  
  836. works.each(function (i, e) {
  837. let _this = $(e);
  838.  
  839. let ctlAttrs = {
  840. illustId: 0,
  841. illustType: 0,
  842. pageCount: 1,
  843. };
  844.  
  845. let href = _this.attr('href');
  846.  
  847. if (href == null || href === '') {
  848. DoLog('Can not found illust id, skip this.');
  849. return;
  850. }
  851.  
  852. let matched = href.match(/artworks\/(\d+)/);
  853. if (matched) {
  854. ctlAttrs.illustId = matched[1];
  855. } else {
  856. DoLog('Can not found illust id, skip this.');
  857. return;
  858. }
  859.  
  860. if (_this.hasClass('multiple')) {
  861. ctlAttrs.pageCount = _this.find('.page-count').find('span').text();
  862. }
  863.  
  864. if (_this.hasClass('ugoku-illust')) {
  865. ctlAttrs.illustType = 2;
  866. }
  867.  
  868. // 添加 attr
  869. _this.attr({
  870. 'illustId': ctlAttrs.illustId,
  871. 'illustType': ctlAttrs.illustType,
  872. 'pageCount': ctlAttrs.pageCount
  873. });
  874.  
  875. returnMap.controlElements.push(e);
  876. });
  877.  
  878. returnMap.loadingComplete = true;
  879.  
  880. DoLog(LogLevel.Info, 'Process page elements complete.');
  881. DoLog(LogLevel.Elements, returnMap);
  882.  
  883. this.private.returnMap = returnMap;
  884. return returnMap;
  885. },
  886. GetProcessedPageElements: function () {
  887. if (this.private.returnMap == null) {
  888. return this.ProcessPageElements();
  889. }
  890. return this.private.returnMap;
  891. },
  892. GetToolBar: function () {
  893. return findToolbarOld();
  894. },
  895. HasAutoLoad: false,
  896. private: {
  897. returnMap: null,
  898. },
  899. };
  900. Pages[PageType.NewIllust] = {
  901. PageTypeString: 'NewIllustPage',
  902. CheckUrl: function (url) {
  903. return /^https?:\/\/www.pixiv.net\/new_illust.php.*/.test(url);
  904. },
  905. ProcessPageElements: function () {
  906. let returnMap = {
  907. loadingComplete: false,
  908. controlElements: [],
  909. };
  910.  
  911. let ul = $('#root').find('ul:first');
  912. if (ul.length === 0) {
  913. DoLog(LogLevel.Error, 'Can not found <ul>!');
  914. return returnMap;
  915. }
  916.  
  917. ul.find('li').each(function (i, e) {
  918. let _this = $(e);
  919.  
  920. let link = _this.find('a:first');
  921. let href = link.attr('href');
  922. if (href == null || href === '') {
  923. DoLog(LogLevel.Error, 'Can not found illust id, skip this.');
  924. return;
  925. }
  926.  
  927. let ctlAttrs = {
  928. illustId: 0,
  929. illustType: 0,
  930. pageCount: 1,
  931. };
  932.  
  933. let matched = href.match(/artworks\/(\d+)/);
  934. if (matched) {
  935. ctlAttrs.illustId = matched[1];
  936. } else {
  937. DoLog(LogLevel.Warning, 'Can not found illust id, skip this.');
  938. return;
  939. }
  940.  
  941. if (link.children().length > 1) {
  942. let span = link.find('svg').parent().parent().next();
  943. if (span.length > 0 && span.get(0).tagName == 'SPAN') {
  944. ctlAttrs.pageCount = span.text();
  945. } else if (link.find('svg').length > 0) {
  946. ctlAttrs.illustType = 2;
  947. }
  948. }
  949.  
  950. let control = _this.children('div:first').children('div:first');
  951. control.attr({
  952. 'illustId': ctlAttrs.illustId,
  953. 'illustType': ctlAttrs.illustType,
  954. 'pageCount': ctlAttrs.pageCount
  955. });
  956.  
  957. returnMap.controlElements.push(control.get(0));
  958. });
  959.  
  960. returnMap.loadingComplete = true;
  961.  
  962. DoLog(LogLevel.Info, 'Process page elements complete.');
  963. DoLog(LogLevel.Elements, returnMap);
  964.  
  965. this.private.returnMap = returnMap;
  966. return returnMap;
  967. },
  968. GetProcessedPageElements: function () {
  969. if (this.private.returnMap == null) {
  970. return this.ProcessPageElements();
  971. }
  972. return this.private.returnMap;
  973. },
  974. GetToolBar: function () {
  975. return findToolbarCommon();
  976. },
  977. HasAutoLoad: true,
  978. private: {
  979. returnMap: null,
  980. },
  981. };
  982. Pages[PageType.R18] = {
  983. PageTypeString: 'R18Page',
  984. CheckUrl: function (url) {
  985. return /^https?:\/\/www.pixiv.net\/cate_r18.php.*/.test(url);
  986. },
  987. ProcessPageElements: function () {
  988. //
  989. },
  990. GetToolBar: function () {
  991. //
  992. },
  993. HasAutoLoad: false,
  994. };
  995. Pages[PageType.BookMark] = {
  996. PageTypeString: 'BookMarkPage',
  997. CheckUrl: function (url) {
  998. return /^https:\/\/www.pixiv.net\/bookmark.php\/?$/.test(url);
  999. },
  1000. ProcessPageElements: function () {
  1001. let returnMap = {
  1002. loadingComplete: false,
  1003. controlElements: [],
  1004. };
  1005.  
  1006. let images = $('.image-item');
  1007. DoLog(LogLevel.Info, 'Found images, length: ' + images.length);
  1008. DoLog(LogLevel.Elements, images);
  1009.  
  1010. images.each(function (i, e) {
  1011. let _this = $(e);
  1012.  
  1013. let work = _this.find('._work');
  1014. if (work.length === 0) {
  1015. DoLog(LogLevel.Warning, 'Can not found ._work, skip this.');
  1016. return;
  1017. }
  1018.  
  1019. let ctlAttrs = {
  1020. illustId: 0,
  1021. illustType: 0,
  1022. pageCount: 1,
  1023. };
  1024.  
  1025. let href = work.attr('href');
  1026. if (href == null || href === '') {
  1027. DoLog(LogLevel.Warning, 'Can not found illust id, skip this.');
  1028. return;
  1029. }
  1030.  
  1031. let matched = href.match(/artworks\/(\d+)/);
  1032. if (matched) {
  1033. ctlAttrs.illustId = matched[1];
  1034. } else {
  1035. DoLog(LogLevel.Warning, 'Can not found illust id, skip this.');
  1036. return;
  1037. }
  1038.  
  1039. if (work.hasClass('multiple')) {
  1040. ctlAttrs.pageCount = _this.find('.page-count').find('span').text();
  1041. }
  1042.  
  1043. if (work.hasClass('ugoku-illust')) {
  1044. ctlAttrs.illustType = 2;
  1045. }
  1046.  
  1047. // 添加 attr
  1048. let control = _this.children('a:first');
  1049. control.attr({
  1050. 'illustId': ctlAttrs.illustId,
  1051. 'illustType': ctlAttrs.illustType,
  1052. 'pageCount': ctlAttrs.pageCount
  1053. });
  1054.  
  1055. returnMap.controlElements.push(control.get(0));
  1056. });
  1057.  
  1058. returnMap.loadingComplete = true;
  1059.  
  1060. DoLog(LogLevel.Info, 'Process page elements complete.');
  1061. DoLog(LogLevel.Elements, returnMap);
  1062.  
  1063. this.private.returnMap = returnMap;
  1064. return returnMap;
  1065. },
  1066. GetProcessedPageElements: function () {
  1067. if (this.private.returnMap == null) {
  1068. return this.ProcessPageElements();
  1069. }
  1070. return this.private.returnMap;
  1071. },
  1072. GetToolBar: function () {
  1073. return findToolbarOld();
  1074. },
  1075. HasAutoLoad: false,
  1076. private: {
  1077. returnMap: null,
  1078. },
  1079. };
  1080. Pages[PageType.Stacc] = {
  1081. PageTypeString: 'StaccPage',
  1082. CheckUrl: function (url) {
  1083. return /^https:\/\/www.pixiv.net\/stacc.*/.test(url);
  1084. },
  1085. ProcessPageElements: function () {
  1086. let returnMap = {
  1087. loadingComplete: false,
  1088. controlElements: [],
  1089. };
  1090.  
  1091. let works = $('._work');
  1092.  
  1093. DoLog(LogLevel.Info, 'Found .work, length: ' + works.length);
  1094. DoLog(LogLevel.Elements, works);
  1095.  
  1096. works.each(function (i, e) {
  1097. let _this = $(e);
  1098.  
  1099. let ctlAttrs = {
  1100. illustId: 0,
  1101. illustType: 0,
  1102. pageCount: 1,
  1103. };
  1104.  
  1105. let href = _this.attr('href');
  1106.  
  1107. if (href == null || href === '') {
  1108. DoLog('Can not found illust id, skip this.');
  1109. return;
  1110. }
  1111.  
  1112. let matched = href.match(/illust_id=(\d+)/);
  1113. if (matched) {
  1114. ctlAttrs.illustId = matched[1];
  1115. } else {
  1116. DoLog('Can not found illust id, skip this.');
  1117. return;
  1118. }
  1119.  
  1120. if (_this.hasClass('multiple')) {
  1121. ctlAttrs.pageCount = _this.find('.page-count').find('span').text();
  1122. }
  1123.  
  1124. if (_this.hasClass('ugoku-illust')) {
  1125. ctlAttrs.illustType = 2;
  1126. }
  1127.  
  1128. // 添加 attr
  1129. _this.attr({
  1130. 'illustId': ctlAttrs.illustId,
  1131. 'illustType': ctlAttrs.illustType,
  1132. 'pageCount': ctlAttrs.pageCount
  1133. });
  1134.  
  1135. returnMap.controlElements.push(e);
  1136. });
  1137.  
  1138. returnMap.loadingComplete = true;
  1139.  
  1140. DoLog(LogLevel.Info, 'Process page elements complete.');
  1141. DoLog(LogLevel.Elements, returnMap);
  1142.  
  1143. this.private.returnMap = returnMap;
  1144. return returnMap;
  1145. },
  1146. GetProcessedPageElements: function () {
  1147. if (this.private.returnMap == null) {
  1148. return this.ProcessPageElements();
  1149. }
  1150. return this.private.returnMap;
  1151. },
  1152. GetToolBar: function () {
  1153. return findToolbarOld();
  1154. },
  1155. HasAutoLoad: true,
  1156. private: {
  1157. returnMap: null,
  1158. },
  1159. };
  1160. Pages[PageType.Artwork] = {
  1161. PageTypeString: 'ArtworkPage',
  1162. CheckUrl: function (url) {
  1163. return /^https:\/\/www.pixiv.net\/artworks\/.*/.test(url) ||
  1164. /^https:\/\/www.pixiv.net\/en\/artworks\/.*/.test(url);
  1165. },
  1166. ProcessPageElements: function () {
  1167. let returnMap = {
  1168. loadingComplete: false,
  1169. controlElements: [],
  1170. };
  1171.  
  1172. // 是动图
  1173. let canvas = $('main').find('figure').find('canvas');
  1174. if ($('main').find('figure').find('canvas').length > 0) {
  1175. this.private.needProcess = true;
  1176. canvas.addClass('pp-canvas');
  1177. }
  1178.  
  1179. if (location.href.indexOf('#preview') == -1) {
  1180. // 相关作品,container找不到说明还没加载
  1181. let containerDiv = $('.gtm-illust-recommend-zone');
  1182. if (containerDiv.length > 0) {
  1183. DoLog(LogLevel.Info, 'Found container div.');
  1184. DoLog(LogLevel.Elements, containerDiv);
  1185.  
  1186. containerDiv.find('ul:first').children().each(function (i, e) {
  1187. let _this = $(e);
  1188.  
  1189. let img = _this.find('img');
  1190. if (img.length === 0) {
  1191. DoLog(LogLevel.Warning, 'Can not found <img>, skip this element.');
  1192. return;
  1193. }
  1194.  
  1195. let link = _this.find('a:first');
  1196. if (link.length === 0) {
  1197. DoLog(LogLevel.Warning, 'Can not found <a>, skip this element.');
  1198. return;
  1199. }
  1200.  
  1201. let ctlAttrs = {
  1202. illustId: 0,
  1203. illustType: 0,
  1204. pageCount: 1,
  1205. };
  1206.  
  1207. let href = link.attr('href');
  1208. if (href == null || href === '') {
  1209. DoLog(LogLevel.Warning, 'No href found, skip.');
  1210. return;
  1211. } else {
  1212. let matched = href.match(/artworks\/(\d+)/);
  1213. if (matched) {
  1214. ctlAttrs.illustId = matched[1];
  1215. } else {
  1216. DoLog(LogLevel.Warning, 'Can not found illust id, skip.');
  1217. return;
  1218. }
  1219. }
  1220.  
  1221. if (link.children().length > 1) {
  1222. if (link.children('div:first').find('span').length > 0) {
  1223. let span = link.children('div:first').find('span:first');
  1224. if (span.length === 0) {
  1225. DoLog(LogLevel.Warning, 'Can not found <span>, skip this element.');
  1226. return;
  1227. }
  1228. ctlAttrs.pageCount = span.next().text();
  1229. } else if (link.children('div:last').find('svg').length > 0) {
  1230. ctlAttrs.illustType = 2;
  1231. }
  1232. }
  1233.  
  1234. let control = link.parent();
  1235. control.attr({
  1236. 'illustId': ctlAttrs.illustId,
  1237. 'illustType': ctlAttrs.illustType,
  1238. 'pageCount': ctlAttrs.pageCount
  1239. });
  1240.  
  1241. returnMap.controlElements.push(control.get(0));
  1242. });
  1243. }
  1244.  
  1245. DoLog(LogLevel.Info, 'Process page elements complete.');
  1246. DoLog(LogLevel.Elements, returnMap);
  1247. }
  1248.  
  1249. returnMap.loadingComplete = true;
  1250. this.private.returnMap = returnMap;
  1251. return returnMap;
  1252. },
  1253. GetProcessedPageElements: function () {
  1254. if (this.private.returnMap == null) {
  1255. return this.ProcessPageElements();
  1256. }
  1257. return this.private.returnMap;
  1258. },
  1259. GetToolBar: function () {
  1260. return findToolbarCommon();
  1261. },
  1262. HasAutoLoad: true,
  1263. Work: function () {
  1264. function AddDownloadButton(button, offsetToOffsetTop) {
  1265. if (!g_settings.enableAnimeDownload) {
  1266. return;
  1267. }
  1268.  
  1269. let cloneButton = button.clone().css({ 'bottom': '50px', 'padding': 0, 'width': '48px', 'height': '48px', 'opacity': '0.4', 'cursor': 'pointer' });
  1270. cloneButton.get(0).innerHTML = '<svg viewBox="0 0 120 120" style="width: 40px; height: 40px; stroke-width: 10; stroke-linecap: round; stroke-linejoin: round; border-radius: 24px; background-color: black; stroke: limegreen; fill: none;" class="_3Fo0Hjg"><polyline points="60,30 60,90"></polyline><polyline points="30,60 60,90 90,60"></polyline></svg></button>';
  1271.  
  1272. function MoveButton() {
  1273. function getOffset(e) {
  1274. if (e.offsetParent) {
  1275. let offset = getOffset(e.offsetParent);
  1276. return {
  1277. offsetTop: e.offsetTop + offset.offsetTop,
  1278. offsetLeft: e.offsetLeft + offset.offsetLeft,
  1279. };
  1280. } else {
  1281. return {
  1282. offsetTop: e.offsetTop,
  1283. offsetLeft: e.offsetLeft,
  1284. };
  1285. }
  1286. }
  1287.  
  1288. /*let offset = getOffset(button.get(0));
  1289. DoLog(LogLevel.Info, 'offset of download button: ' + offset.offsetTop + ', ' + offset.offsetLeft);
  1290. DoLog(LogLevel.Elements, offset);
  1291.  
  1292. cloneButton.css({ 'position': 'absolute' }).show();*/
  1293. }
  1294.  
  1295. MoveButton();
  1296. $(window).on('resize', MoveButton);
  1297. button.after(cloneButton);
  1298.  
  1299. cloneButton.mouseover(function () {
  1300. $(this).css('opacity', '0.2');
  1301. }).mouseleave(function () {
  1302. $(this).css('opacity', '0.4');
  1303. }).click(function () {
  1304. let illustId = '';
  1305.  
  1306. let matched = location.href.match(/artworks\/(\d+)/);
  1307. if (matched) {
  1308. illustId = matched[1];
  1309. DoLog(LogLevel.Info, 'IllustId=' + illustId);
  1310. } else {
  1311. DoLog(LogLevel.Error, 'Can not found illust id!');
  1312. return;
  1313. }
  1314.  
  1315. $.ajax(g_getUgoiraUrl.replace('#id#', illustId), {
  1316. method: 'GET',
  1317. success: function (json) {
  1318. DoLog(LogLevel.Elements, json);
  1319.  
  1320. if (json.error == true) {
  1321. DoLog(LogLevel.Error, 'Server response an error: ' + json.message);
  1322. return;
  1323. }
  1324.  
  1325. // 因为浏览器会拦截不同域的 open 操作,绕一下
  1326. let newWindow = window.open('_blank');
  1327. newWindow.location = json.body.originalSrc;
  1328. },
  1329. error: function () {
  1330. DoLog(LogLevel.Error, 'Request zip file failed!');
  1331. }
  1332. });
  1333. });
  1334. }
  1335.  
  1336. if (this.private.needProcess) {
  1337. let canvas = $('.pp-canvas');
  1338.  
  1339. // 预览模式,需要调成全屏,并且添加下载按钮到全屏播放的 div 里
  1340. if (location.href.indexOf('#preview') != -1) {
  1341. canvas.click();
  1342.  
  1343. $('#root').remove();
  1344.  
  1345. let callbackInterval = setInterval(function () {
  1346. let div = $('div[role="presentation"]');
  1347. if (div.length < 1) {
  1348. return;
  1349. }
  1350.  
  1351. DoLog(LogLevel.Info, 'found <div>, continue to next step.');
  1352.  
  1353. clearInterval(callbackInterval);
  1354.  
  1355. let presentationCanvas = div.find('canvas');
  1356. if (presentationCanvas.length < 1) {
  1357. DoLog(LogLevel.Error, 'Can not found canvas in the presentation div.');
  1358. return;
  1359. }
  1360.  
  1361. let width = 0, height = 0;
  1362. let tWidth = presentationCanvas.attr('width');
  1363. let tHeight = presentationCanvas.attr('height');
  1364. if (tWidth && tHeight) {
  1365. width = parseInt(tWidth);
  1366. height = parseInt(tHeight);
  1367. } else {
  1368. tWidth = presentationCanvas.css('width');
  1369. tHeight = presentationCanvas.css('height');
  1370. width = parseInt(tWidth);
  1371. height = parseInt(this);
  1372. }
  1373.  
  1374. let parent = presentationCanvas.parent();
  1375. for (let i = 0; i < 3; i++) {
  1376. parent.get(0).className = '';
  1377. parent = parent.parent();
  1378. }
  1379. presentationCanvas.css({ 'width': width + 'px', 'height': height + 'px', 'cursor': 'default' }).addClass('pp-presentationCanvas');
  1380. let divForStopClick = $('<div class="pp-disableClick"></div>').css({
  1381. 'width': width + 'px', 'height': height + 'px',
  1382. 'opacity': 0,
  1383. 'position': 'absolute', 'top': '0px', 'left': '0px', 'z-index': 99999,
  1384. });
  1385. div.append(divForStopClick);
  1386. div.append(presentationCanvas.next().css('z-index', 99999));
  1387. presentationCanvas.next().remove();
  1388. // 防止预览图消失
  1389. $('html').addClass('pp-main');
  1390.  
  1391. // 调整 canvas 大小的函数
  1392. window.ResizeCanvas = function (newWidth, newHeight) {
  1393. DoLog(LogLevel.Info, 'Resize canvas: ' + newWidth + 'x' + newHeight);
  1394. $('.pp-disableClick').css({ 'width': newWidth, 'height': newHeight });
  1395. $('.pp-presentationCanvas').css({ 'width': newWidth, 'height': newHeight });
  1396. };
  1397. window.GetCanvasSize = function () {
  1398. return {
  1399. width: width,
  1400. height: height,
  1401. };
  1402. }
  1403.  
  1404. // 添加下载按钮
  1405. AddDownloadButton(divForStopClick.next(), 0);
  1406.  
  1407. window.parent.PreviewCallback(width, height);
  1408. }, 500);
  1409. }
  1410. // 普通模式,只需要添加下载按钮到内嵌模式的 div 里
  1411. else {
  1412. let div = $('div[role="presentation"]:last');
  1413. let button = div.find('button');
  1414.  
  1415. let headerRealHeight = parseInt($('header').css('height')) +
  1416. parseInt($('header').css('padding-top')) + parseInt($('header').css('padding-bottom')) +
  1417. parseInt($('header').css('margin-top')) + parseInt($('header').css('margin-bottom')) +
  1418. parseInt($('header').css('border-bottom-width')) + parseInt($('header').css('border-top-width'));
  1419.  
  1420. AddDownloadButton(button, headerRealHeight);
  1421. }
  1422. }
  1423. },
  1424. private: {
  1425. needProcess: false,
  1426. returnMap: null,
  1427. },
  1428. };
  1429.  
  1430. function CheckUrlTest() {
  1431. let urls = [
  1432. 'http://www.pixiv.net',
  1433. 'http://www.pixiv.net',
  1434. 'https://www.pixiv.net',
  1435. 'https://www.pixiv.net/',
  1436. 'https://www.pixiv.net/?lang=en',
  1437. 'https://www.pixiv.net/search.php?s_mode=s_tag&word=miku',
  1438. 'https://www.pixiv.net/search.php?word=VOCALOID&s_mode=s_tag_full',
  1439. 'https://www.pixiv.net/discovery',
  1440. 'https://www.pixiv.net/discovery?x=1',
  1441. 'https://www.pixiv.net/member.php?id=3207350',
  1442. 'https://www.pixiv.net/member_illust.php?id=3207350&type=illust',
  1443. 'https://www.pixiv.net/bookmark.php?id=3207350&rest=show',
  1444. 'https://www.pixiv.net/ranking.php?mode=daily&content=ugoira',
  1445. 'https://www.pixiv.net/ranking.php?mode=daily',
  1446. 'https://www.pixiv.net/new_illust.php',
  1447. 'https://www.pixiv.net/new_illust.php?x=1',
  1448. 'https://www.pixiv.net/cate_r18.php',
  1449. 'https://www.pixiv.net/cate_r18.php?x=1',
  1450. 'https://www.pixiv.net/bookmark.php',
  1451. 'https://www.pixiv.net/bookmark.php?x=1',
  1452. 'https://www.pixiv.net/stacc?mode=unify',
  1453. 'https://www.pixiv.net/artworks/77996773',
  1454. 'https://www.pixiv.net/artworks/77996773#preview',
  1455. ];
  1456.  
  1457. for (let j = 0; j < urls.length; j++) {
  1458. for (let i = 0; i < PageType.PageTypeCount; i++) {
  1459. if (Pages[i].CheckUrl(urls[j])) {
  1460. console.log(urls[j]);
  1461. console.log('[' + j + '] is ' + Pages[i].PageTypeString);
  1462. }
  1463. }
  1464. }
  1465. }
  1466.  
  1467. /* ---------------------------------------- 预览 ---------------------------------------- */
  1468. let autoLoadInterval = null;
  1469. function PixivPreview() {
  1470. // 最终需要显示的预览图ID,用于避免鼠标滑过多张图片时,最终显示的图片错误
  1471. let previewTargetIllustId = '';
  1472.  
  1473. // 开启预览功能
  1474. function ActivePreview() {
  1475. let returnMap = Pages[g_pageType].GetProcessedPageElements();
  1476. if (!returnMap.loadingComplete) {
  1477. DoLog(LogLevel.Error, 'Page not load, should not call Preview!');
  1478. return;
  1479. }
  1480.  
  1481. // 鼠标进入
  1482. $(returnMap.controlElements).mouseenter(function (e) {
  1483. // 按住 Ctrl键 不显示预览图
  1484. if (e.ctrlKey) {
  1485. return;
  1486. }
  1487.  
  1488. let startTime = new Date().getTime();
  1489. let delay = parseInt(g_settings.previewDelay == null ? g_defaultSettings.previewDelay : g_settings.previewDelay);
  1490.  
  1491. let _this = $(this);
  1492. let illustId = _this.attr('illustId');
  1493. let illustType = _this.attr('illustType');
  1494. let pageCount = _this.attr('pageCount');
  1495.  
  1496. if (illustId == null) {
  1497. DoLog(LogLevel.Error, 'Can not found illustId in this element\'s attrbutes.');
  1498. return;
  1499. }
  1500. if (illustType == null) {
  1501. DoLog(LogLevel.Error, 'Can not found illustType in this element\'s attrbutes.');
  1502. return;
  1503. }
  1504. if (pageCount == null) {
  1505. DoLog(LogLevel.Error, 'Can not found pageCount in this element\'s attrbutes.');
  1506. return;
  1507. }
  1508. previewTargetIllustId = illustId;
  1509.  
  1510. // 鼠标位置
  1511. g_mousePos = { x: e.pageX, y: e.pageY };
  1512. // 预览 Div
  1513. let previewDiv = $(document.createElement('div')).addClass('pp-main').attr('illustId', illustId)
  1514. .css({
  1515. 'position': 'absolute', 'z-index': '999999', 'left': g_mousePos.x + 'px', 'top': g_mousePos.y + 'px',
  1516. 'border-style': 'solid', 'border-color': '#6495ed', 'border-width': '2px', 'border-radius': '20px',
  1517. 'width': '48px', 'height': '48px',
  1518. 'background-image': 'url(https://pp-1252089172.cos.ap-chengdu.myqcloud.com/transparent.png)',
  1519. 'display': 'none'
  1520. });
  1521. // 添加到 body
  1522. $('.pp-main').remove();
  1523. $('body').append(previewDiv);
  1524.  
  1525. let waitTime = delay - (new Date().getTime() - startTime);
  1526. if (waitTime > 0) {
  1527. setTimeout(function() {
  1528. previewDiv.show();
  1529. }, waitTime);
  1530. } else {
  1531. previewDiv.show();
  1532. }
  1533.  
  1534. // 加载中图片
  1535. let loadingImg = $(new Image()).addClass('pp-loading').attr('src', g_loadingImage).css({
  1536. 'position': 'absolute', 'border-radius': '20px',
  1537. });
  1538. previewDiv.append(loadingImg);
  1539.  
  1540. // 要显示的预览图节点
  1541. let loadImg = $(new Image()).addClass('pp-image').css({ 'height': '0px', 'width': '0px', 'display': 'none', 'border-radius': '20px' });
  1542. previewDiv.append(loadImg);
  1543.  
  1544. // 原图(笑脸)图标
  1545. let originIcon = $(new Image()).addClass('pp-original').attr('src', 'https://source.pixiv.net/www/images/pixivcomic-favorite.png')
  1546. .css({ 'position': 'absolute', 'bottom': '5px', 'right': '5px', 'display': 'none' });
  1547. previewDiv.append(originIcon);
  1548.  
  1549. // 点击图标新网页打开原图
  1550. originIcon.click(function () {
  1551. window.open($(previewDiv).children('img')[1].src);
  1552. });
  1553.  
  1554. // 右上角张数标记
  1555. let pageCountHTML = '<div class="pp-pageCount" style="display: flex;-webkit-box-align: center;align-items: center;box-sizing: border-box;margin-left: auto;height: 20px;color: rgb(255, 255, 255);font-size: 10px;line-height: 12px;font-weight: bold;flex: 0 0 auto;padding: 4px 6px;background: rgba(0, 0, 0, 0.32);border-radius: 10px;margin-top:5px;margin-right:5px;">\<svg viewBox="0 0 9 10" width="9" height="10" style="stroke: none;line-height: 0;font-size: 0px;fill: currentcolor;"><path d="M8,3 C8.55228475,3 9,3.44771525 9,4 L9,9 C9,9.55228475 8.55228475,10 8,10 L3,10 C2.44771525,10 2,9.55228475 2,9 L6,9 C7.1045695,9 8,8.1045695 8,7 L8,3 Z M1,1 L6,1 C6.55228475,1 7,1.44771525 7,2 L7,7 C7,7.55228475 6.55228475,8 6,8 L1,8 C0.44771525,8 0,7.55228475 0,7 L0,2 C0,1.44771525 0.44771525,1 1,1 Z"></path></svg><span style="margin-left:2px;" class="pp-page">0/0</span></div>';
  1556. let pageCountDiv = $(pageCountHTML)
  1557. .css({ 'position': 'absolute', 'top': '0px', 'display': 'none', 'right': '0px', 'display': 'none' });
  1558. previewDiv.append(pageCountDiv);
  1559.  
  1560. $('.pp-main').mouseleave(function (e) {
  1561. $(this).remove();
  1562. });
  1563.  
  1564. let url = '';
  1565. if (illustType == 2) {
  1566. // 动图
  1567. let screenWidth = document.documentElement.clientWidth;
  1568. let screenHeight = document.documentElement.clientHeight;
  1569. previewDiv.get(0).innerHTML = '<iframe class="pp-iframe" style="width: 48px; height: 48px; display: none; border-radius: 20px;" src="https://www.pixiv.net/artworks/' + illustId + '#preview" />';
  1570. previewDiv.append(loadingImg);
  1571. } else {
  1572. url = g_getArtworkUrl.replace('#id#', illustId);
  1573.  
  1574. // 获取图片链接
  1575. $.ajax(url, {
  1576. method: 'GET',
  1577. success: function (json) {
  1578. DoLog(LogLevel.Info, 'Got artwork urls:');
  1579. DoLog(LogLevel.Elements, json);
  1580.  
  1581. if (json.error === true) {
  1582. DoLog(LogLevel.Error, 'Server responsed an error: ' + json.message);
  1583. return;
  1584. }
  1585.  
  1586. // 已经不需要显示这个预览图了,直接丢弃
  1587. if (illustId != previewTargetIllustId) {
  1588. DoLog(LogLevel.Info, 'Drop this preview request.');
  1589. return;
  1590. }
  1591.  
  1592. let regular = [];
  1593. let original = [];
  1594. for (let i = 0; i < json.body.length; i++) {
  1595. regular.push(json.body[i].urls.regular);
  1596. original.push(json.body[i].urls.original);
  1597. }
  1598.  
  1599. DoLog(LogLevel.Info, 'Process urls complete.');
  1600. DoLog(LogLevel.Elements, regular);
  1601. DoLog(LogLevel.Elements, original);
  1602.  
  1603. ViewImages(regular, 0, original, g_settings.original, illustId);
  1604. },
  1605. error: function (data) {
  1606. DoLog(LogLevel.Error, 'Request image urls failed!');
  1607. if (data) {
  1608. DoLog(LogLevel.Elements, data);
  1609. }
  1610. }
  1611. });
  1612. }
  1613. });
  1614.  
  1615. // 鼠标移出图片
  1616. $(returnMap.controlElements).mouseleave(function (e) {
  1617. let _this = $(this);
  1618. let illustId = _this.attr('illustId');
  1619. let illustType = _this.attr('illustType');
  1620. let pageCount = _this.attr('pageCount');
  1621.  
  1622. let moveToElement = $(e.relatedTarget);
  1623. let isMoveToPreviewElement = false;
  1624. // 鼠标移动到预览图上
  1625. while (true) {
  1626. if (moveToElement.hasClass('pp-main') && moveToElement.attr('illustId') == illustId) {
  1627. isMoveToPreviewElement = true;
  1628. }
  1629.  
  1630. if (moveToElement.parent().length < 1) {
  1631. break;
  1632. }
  1633.  
  1634. moveToElement = moveToElement.parent();
  1635. }
  1636. if (!isMoveToPreviewElement) {
  1637. // 非预览图上
  1638. $('.pp-main').remove();
  1639. }
  1640. });
  1641.  
  1642. // 鼠标移动,调整位置
  1643. $(returnMap.controlElements).mousemove(function (e) {
  1644. // Ctrl 和 中键 都可以禁止预览图移动,这样就可以单手操作了
  1645. if (e.ctrlKey || e.buttons & 4) {
  1646. return;
  1647. }
  1648. let screenWidth = document.documentElement.clientWidth;
  1649. let screenHeight = document.documentElement.clientHeight;
  1650. g_mousePos.x = e.pageX; g_mousePos.y = e.pageY;
  1651.  
  1652. AdjustDivPosition();
  1653. });
  1654.  
  1655. // 这个页面有自动加载
  1656. if (Pages[g_pageType].HasAutoLoad && autoLoadInterval == null) {
  1657. autoLoadInterval = setInterval(ProcessAutoLoad, 1000);
  1658. DoLog(LogLevel.Info, 'Auto load interval set.');
  1659. }
  1660.  
  1661. // 插一段回调函数
  1662. window.PreviewCallback = PreviewCallback;
  1663. DoLog(LogLevel.Info, 'Callback function was inserted.');
  1664. DoLog(LogLevel.Elements, window.PreviewCallback);
  1665.  
  1666. DoLog(LogLevel.Info, 'Preview enable succeed!');
  1667. }
  1668.  
  1669. // 关闭预览功能,不是给外部用的
  1670. function DeactivePreview() {
  1671. let returnMap = Pages[g_pageType].GetProcessedPageElements();
  1672. if (!returnMap.loadingComplete) {
  1673. DoLog(LogLevel.Error, 'Page not load, should not call Preview!');
  1674. return;
  1675. }
  1676.  
  1677. // 只需要取消绑定事件, attrs 以及回调都不需要删除
  1678. $(returnMap.controlElements).unbind('mouseenter').unbind('mouseleave').unbind('mousemove');
  1679.  
  1680. if (autoLoadInterval) {
  1681. clearInterval(autoLoadInterval);
  1682. autoLoadInterval = null;
  1683. }
  1684.  
  1685. DoLog(LogLevel.Info, 'Preview disable succeed!');
  1686. }
  1687.  
  1688. // iframe 的回调函数
  1689. function PreviewCallback(canvasWidth, canvasHeight) {
  1690. DoLog(LogLevel.Info, 'iframe callback, width: ' + canvasWidth + ', height: ' + canvasHeight);
  1691.  
  1692. let size = AdjustDivPosition();
  1693.  
  1694. $('.pp-loading').hide();
  1695. $('.pp-iframe').css({ 'width': size.width, 'height': size.height }).show();
  1696. }
  1697.  
  1698. // 调整预览 Div 的位置
  1699. function AdjustDivPosition() {
  1700. // 鼠标到预览图的距离
  1701. let fromMouseToDiv = 30;
  1702.  
  1703. let screenWidth = document.documentElement.clientWidth;
  1704. let screenHeight = document.documentElement.clientHeight;
  1705. let left = 0;
  1706. let top = document.body.scrollTop + document.documentElement.scrollTop;
  1707.  
  1708. let width = 0, height = 0;
  1709. if ($('.pp-main').find('iframe').length > 0) {
  1710. let iframe = $('.pp-main').find('iframe').get(0);
  1711. if (iframe.contentWindow.GetCanvasSize) {
  1712. let canvasSize = iframe.contentWindow.GetCanvasSize();
  1713. width = canvasSize.width;
  1714. height = canvasSize.height;
  1715. } else {
  1716. width = 0;
  1717. height = 0;
  1718. }
  1719. } else {
  1720. $('.pp-image').css({ 'width': '', 'height': '' });
  1721. width = $('.pp-image').get(0) == null ? 0 : $('.pp-image').get(0).width;
  1722. height = $('.pp-image').get(0) == null ? 0 : $('.pp-image').get(0).height;
  1723. }
  1724.  
  1725. let isShowOnLeft = g_mousePos.x > screenWidth / 2;
  1726.  
  1727. let newWidth = 48, newHeight = 48;
  1728. if (width > 0 && height > 0) {
  1729. newWidth = isShowOnLeft ? g_mousePos.x - fromMouseToDiv : screenWidth - g_mousePos.x - fromMouseToDiv;
  1730. newHeight = height / width * newWidth;
  1731. // 高度不足以完整显示,只能让两侧留空了
  1732. if (newHeight > screenHeight) {
  1733. newHeight = screenHeight;
  1734. newWidth = newHeight / height * width;
  1735. }
  1736. newWidth -= 5;
  1737. newHeight -= 5;
  1738.  
  1739. // 设置新的宽高
  1740. if ($('.pp-main').find('iframe').length > 0) {
  1741. let iframe = $('.pp-main').find('iframe');
  1742. iframe.get(0).contentWindow.ResizeCanvas(newWidth, newHeight);
  1743. iframe.css({ 'width': newWidth, 'height': newHeight });
  1744. }
  1745. else {
  1746. $('.pp-image').css({ 'height': newHeight + 'px', 'width': newWidth + 'px' });
  1747. }
  1748.  
  1749. // 调整下一次 loading 出现的位置
  1750. $('.pp-loading').css({ 'left': newWidth / 2 - 24 + 'px', 'top': newHeight / 2 - 24 + 'px' });
  1751. }
  1752.  
  1753. // 图片宽度大于高度很多时,会显示在页面顶部,鼠标碰不到,把它移动到下面
  1754. if (top + newHeight <= g_mousePos.y) {
  1755. top = (g_mousePos.y - newHeight - fromMouseToDiv);
  1756. }
  1757. // 调整DIV的位置
  1758. left = isShowOnLeft ? g_mousePos.x - newWidth - fromMouseToDiv : g_mousePos.x + fromMouseToDiv;
  1759.  
  1760. $('.pp-main').css({ 'left': left + 'px', 'top': top + 'px', 'width': newWidth, 'height': newHeight });
  1761.  
  1762. // 返回新的宽高
  1763. return {
  1764. width: newWidth,
  1765. height: newHeight,
  1766. };
  1767. }
  1768.  
  1769. // 请求显示的预览图ID
  1770. let displayTargetIllustId = '';
  1771. // 显示预览图
  1772. function ViewImages(regular, index, original, isShowOriginal, illustId) {
  1773. displayTargetIllustId = illustId;
  1774. if (!regular || regular.length === 0) {
  1775. DoLog(LogLevel.Error, 'Regular url array is null, can not view images!');
  1776. return;
  1777. }
  1778. if (index == null || index < 0 || index >= regular.length) {
  1779. DoLog(LogLevel.Error, 'Index(' + index + ') out of range, can not view images!');
  1780. return;
  1781. }
  1782. if (original == null || original.length === 0) {
  1783. DoLog(LogLevel.Warning, 'Original array is null, replace it with regular array.');
  1784. original = regular;
  1785. }
  1786. if (original.length < regular) {
  1787. DoLog(LogLevel.Warning, 'Original array\'s length is less than regular array, replace it with regular array.');
  1788. original = regular;
  1789. }
  1790. if (isShowOriginal == null) {
  1791. isShowOriginal = false;
  1792. }
  1793.  
  1794. if (original.length > 1) {
  1795. $('.pp-page').text((index + 1) + '/' + regular.length);
  1796. $('.pp-pageCount').show();
  1797. }
  1798. if (isShowOriginal) {
  1799. $('.pp-image').addClass('original');
  1800. } else {
  1801. $('.pp-image').removeClass('original');
  1802. }
  1803. g_settings.original = isShowOriginal ? 1 : 0;
  1804.  
  1805. // 隐藏页数和原图标签
  1806. $('.pp-original, .pp-pageCount').hide();
  1807.  
  1808. // 第一次需要绑定事件
  1809. if ($('.pp-image').attr('index') == null || $('.pp-image').attr('pageCount') != regular.length) {
  1810. $('.pp-image').attr('pageCount', regular.length);
  1811.  
  1812. // 绑定点击事件,Ctrl+左键 单击切换原图
  1813. $('.pp-image').on('click', function (ev) {
  1814. let _this = $(this);
  1815. let isOriginal = _this.hasClass('original');
  1816. let index = _this.attr('index');
  1817. if (index == null) {
  1818. index = 0;
  1819. } else {
  1820. index = parseInt(index);
  1821. }
  1822.  
  1823. if (ev.ctrlKey) {
  1824. // 按住 Ctrl 来回切换原图
  1825. isOriginal = !isOriginal;
  1826. ViewImages(regular, index, original, isOriginal, illustId);
  1827. }
  1828. else if (ev.shiftKey) {
  1829. // 按住 Shift 点击图片新标签页打开原图
  1830. window.open(original[index]);
  1831. } else {
  1832. if (regular.length == 1) {
  1833. return;
  1834. }
  1835. // 如果是多图,点击切换下一张
  1836. if (++index >= regular.length) {
  1837. index = 0;
  1838. }
  1839. ViewImages(regular, index, original, isOriginal, illustId);
  1840. // 预加载
  1841. for (let i = index + 1; i < regular.length && i <= index + 3; i++) {
  1842. let image = new Image();
  1843. image.src = isOriginal ? original[i] : regular[i];;
  1844. }
  1845. }
  1846. });
  1847.  
  1848. // 图片预加载完成
  1849. $('.pp-image').on('load', function () {
  1850. // 显示图片前也判断一下是不是目标图片
  1851. if (displayTargetIllustId != previewTargetIllustId) {
  1852. DoLog(LogLevel.Info, '(2)Drop this preview request.');
  1853. return;
  1854. }
  1855.  
  1856. // 调整图片位置和大小
  1857. let _this = $(this);
  1858. let size = AdjustDivPosition();
  1859. let isShowOriginal = _this.hasClass('original');
  1860.  
  1861. $('.pp-loading').css('display', 'none');
  1862. // 显示图像、页数、原图标签
  1863. $('.pp-image').css('display', '');
  1864. if (regular.length > 1) {
  1865. $('.pp-pageCount').show();
  1866. }
  1867. if (isShowOriginal) {
  1868. $('.pp-original').show();
  1869. }
  1870.  
  1871. // 预加载
  1872. for (let i = index + 1; i < regular.length && i <= index + 3; i++) {
  1873. let image = new Image();
  1874. image.src = isShowOriginal ? original[i] : regular[i];;
  1875. }
  1876. }).on('error', function () {
  1877. DoLog(LogLevel.Error, 'Load image failed!');
  1878. });
  1879. }
  1880.  
  1881. $('.pp-image').attr('src', isShowOriginal ? original[index] : regular[index]).attr('index', index);
  1882. }
  1883.  
  1884. // 处理自动加载
  1885. function ProcessAutoLoad() {
  1886. if (Pages[g_pageType].GetProcessedPageElements() == null) {
  1887. DoLog(LogLevel.Error, 'Call ProcessPageElements first!');
  1888. return;
  1889. }
  1890.  
  1891. let oldReturnMap = Pages[g_pageType].GetProcessedPageElements();
  1892. let newReturnMap = Pages[g_pageType].ProcessPageElements();
  1893.  
  1894. if (newReturnMap.loadingComplete) {
  1895. if (oldReturnMap.controlElements.length < newReturnMap.controlElements.length || newReturnMap.forceUpdate) {
  1896. DoLog(LogLevel.Info, 'Page loaded ' + (newReturnMap.controlElements.length - oldReturnMap.controlElements.length) + ' new work(s).');
  1897.  
  1898. if (g_settings.linkBlank) {
  1899. $(newReturnMap.controlElements).find('a').attr('target', '_blank');
  1900. }
  1901.  
  1902. SetTargetBlank(newReturnMap);
  1903. DeactivePreview();
  1904. ActivePreview();
  1905.  
  1906. return;
  1907. } else if (oldReturnMap.controlElements.length > newReturnMap.controlElements.length) {
  1908. DoLog(LogLevel.Warning, 'works become less?');
  1909.  
  1910. Pages[g_pageType].private.returnMap = oldReturnMap;
  1911.  
  1912. return;
  1913. }
  1914. }
  1915.  
  1916. DoLog(LogLevel.Info, 'Page not change.');
  1917. }
  1918.  
  1919. // 开启预览
  1920. ActivePreview();
  1921. }
  1922. /* ---------------------------------------- 排序 ---------------------------------------- */
  1923. let imageElementTemplate = null;
  1924. function PixivSK(callback) {
  1925. // 不合理的设定
  1926. if (g_settings.pageCount < 1 || g_settings.favFilter < 0) {
  1927. g_settings.pageCount = 1;
  1928. g_settings.favFilter = 0;
  1929. }
  1930. // 当前已经取得的页面数量
  1931. let currentGettingPageCount = 0;
  1932. // 当前加载的页面 URL
  1933. let currentUrl = 'https://www.pixiv.net/ajax/search/';
  1934. // 当前加载的是第几张页面
  1935. let currentPage = 0;
  1936. // 获取到的作品
  1937. let works = [];
  1938.  
  1939. // 仅搜索页启用
  1940. if (g_pageType != PageType.Search) {
  1941. return;
  1942. }
  1943.  
  1944. // 获取第 currentPage 页的作品
  1945. let getWorks = function (onloadCallback) {
  1946. $('#progress').text(Texts[g_language].sort_getWorks.replace('%1', currentGettingPageCount + 1).replace('%2', g_settings.pageCount));
  1947.  
  1948. let url = currentUrl.replace(/p=\d+/, 'p=' + currentPage);
  1949.  
  1950. if (location.href.indexOf('?') != -1) {
  1951. let param = location.href.split('?')[1];
  1952. param = param.replace(/^p=\d+/, '');
  1953. param = param.replace(/&p=\d+/, '');
  1954. url += '&' + param;
  1955. }
  1956.  
  1957. if (url.indexOf('order=') == -1) {
  1958. url += '&order=date_d';
  1959. }
  1960. if (url.indexOf('mode=') == -1) {
  1961. url += '&mode=all';
  1962. }
  1963. if (url.indexOf('s_mode=') == -1) {
  1964. url += '&s_mode=s_tag_full';
  1965. }
  1966.  
  1967. DoLog(LogLevel.Info, 'getWorks url: ' + url);
  1968.  
  1969. let req = new XMLHttpRequest();
  1970. req.open('GET', url, true);
  1971. req.onload = function (event) {
  1972. onloadCallback(req);
  1973. };
  1974. req.onerror = function (event) {
  1975. DoLog(LogLevel.Error, 'Request search page error!');
  1976. };
  1977.  
  1978. req.send(null);
  1979. };
  1980.  
  1981. function getFollowingOfType(user_id, type, offset) {
  1982. return new Promise(function(resolve, reject) {
  1983. if (offset == null) {
  1984. offset = 0;
  1985. }
  1986. let limit = 100;
  1987. let following_show = [];
  1988. $.ajax('https://www.pixiv.net/ajax/user/' + user_id + '/following?offset=' + offset + '&limit=' + limit + '&rest=' + type, {
  1989. async: true,
  1990. success: function(data) {
  1991. if (data == null || data.error) {
  1992. DoLog(LogLevel.Error, 'Following response contains an error.');
  1993. resolve([]);
  1994. return;
  1995. }
  1996. if (data.body.users.length == 0) {
  1997. resolve([]);
  1998. return;
  1999. }
  2000. $.each(data.body.users, function(i, user) {
  2001. following_show.push(user.userId);
  2002. });
  2003. getFollowingOfType(user_id, type, offset + limit).then(function(members) {
  2004. resolve(following_show.concat(members));
  2005. return;
  2006. });
  2007. },
  2008. error: function() {
  2009. DoLog(LogLevel.Error, 'Request following failed.');
  2010. resolve([]);
  2011. }
  2012. });
  2013. });
  2014. }
  2015.  
  2016. function getFollowingOfCurrentUser() {
  2017. return new Promise(function(resolve, reject) {
  2018. let user_id = '';
  2019.  
  2020. try {
  2021. user_id = dataLayer[0].user_id;
  2022. } catch(ex) {
  2023. DoLog(LogLevel.Error, 'Get user id failed.');
  2024. resolve([]);
  2025. return;
  2026. }
  2027.  
  2028. // show/hide
  2029. $('#progress').text(Texts[g_language].sort_getPublicFollowing);
  2030. getFollowingOfType(user_id, 'show').then(function(members) {
  2031. $('#progress').text(Texts[g_language].sort_getPrivateFollowing);
  2032. getFollowingOfType(user_id, 'hide').then(function(members2) {
  2033. resolve(members.concat(members2));
  2034. });
  2035. });
  2036. });
  2037. }
  2038.  
  2039. // 筛选已关注画师作品
  2040. let filterByUser = function() {
  2041. return new Promise(function(resolve, reject) {
  2042. if (!g_settings.hideFollowed) {
  2043. resolve();
  2044. }
  2045.  
  2046. getFollowingOfCurrentUser().then(function(members) {
  2047. let tempWorks = [];
  2048. let hideWorkCount = 0;
  2049. $(works).each(function (i, work) {
  2050. let found = false;
  2051. for (let i = 0; i < members.length; i++) {
  2052. if (members[i] == work.userId) {
  2053. found = true;
  2054. break;
  2055. }
  2056. }
  2057. if (!found) {
  2058. tempWorks.push(work);
  2059. } else {
  2060. hideWorkCount++;
  2061. }
  2062. });
  2063. works = tempWorks;
  2064.  
  2065. DoLog(LogLevel.Info, hideWorkCount + ' works were hide.');
  2066. DoLog(LogLevel.Elements, works);
  2067. resolve();
  2068. });
  2069. });
  2070. };
  2071.  
  2072. // 排序和筛选
  2073. let filterAndSort = function () {
  2074. return new Promise(function(resolve, reject) {
  2075. DoLog(LogLevel.Info, 'Start sort.');
  2076. DoLog(LogLevel.Elements, works);
  2077.  
  2078. // 收藏量低于 FAV_FILTER 的作品不显示
  2079. let text = Texts[g_language].sort_filtering.replace('%2', g_settings.favFilter);
  2080. text = text.replace('%1', (g_settings.hideFavorite ? Texts[g_language].sort_filteringHideFavorite : ''));
  2081. $('#progress').text(text); // 实际上这个太快完全看不到
  2082. let tmp = [];
  2083. $(works).each(function (i, work) {
  2084. let bookmarkCount = work.bookmarkCount ? work.bookmarkCount : 0;
  2085. if (bookmarkCount >= g_settings.favFilter && !(g_settings.hideFavorite && work.bookmarkData)) {
  2086. tmp.push(work);
  2087. }
  2088. });
  2089. works = tmp;
  2090.  
  2091. filterByUser().then(function() {
  2092. // 排序
  2093. works.sort(function (a, b) {
  2094. let favA = a.bookmarkCount;
  2095. let favB = b.bookmarkCount;
  2096. if (!favA) {
  2097. favA = 0;
  2098. }
  2099. if (!favB) {
  2100. favB = 0;
  2101. }
  2102. if (favA > favB) {
  2103. return -1;
  2104. }
  2105. if (favA < favB) {
  2106. return 1;
  2107. }
  2108. return 0;
  2109. });
  2110. DoLog(LogLevel.Info, 'Sort complete.');
  2111. DoLog(LogLevel.Elements, works);
  2112. resolve();
  2113. });
  2114. });
  2115. };
  2116.  
  2117. if (currentPage === 0) {
  2118. let url = location.href;
  2119.  
  2120. if (url.indexOf('&p=') == -1 && url.indexOf('?p=') == -1) {
  2121. DoLog(LogLevel.Warning, 'Can not found page in url.');
  2122. if (url.indexOf('?') == -1) {
  2123. url += '?p=1';
  2124. DoLog(LogLevel.Info, 'Add "?p=1": ' + url);
  2125. } else {
  2126. url += '&p=1';
  2127. DoLog(LogLevel.Info, 'Add "&p=1": ' + url);
  2128. }
  2129. }
  2130. let wordMatch = url.match(/\/tags\/([^/]*)\//);
  2131. let searchWord = '';
  2132. if (wordMatch) {
  2133. DoLog(LogLevel.Info, 'Search key word: ' + searchWord);
  2134. searchWord = wordMatch[1];
  2135. } else {
  2136. DoLog(LogLevel.Error, 'Can not found search key word!');
  2137. return;
  2138. }
  2139.  
  2140. // page
  2141. let page = url.match(/p=(\d*)/)[1];
  2142. currentPage = parseInt(page);
  2143. DoLog(LogLevel.Info, 'Current page: ' + currentPage);
  2144.  
  2145. let type = url.match(/tags\/.*\/(.*)[?$]/)[1];
  2146. currentUrl += type + '/';
  2147.  
  2148. currentUrl += searchWord + '?word=' + searchWord + '&p=' + currentPage;
  2149. DoLog(LogLevel.Info, 'Current url: ' + currentUrl);
  2150. } else {
  2151. DoLog(LogLevel.Error, '???');
  2152. }
  2153.  
  2154. let imageContainer = Pages[PageType.Search].GetImageListContainer();
  2155. // loading
  2156. $(imageContainer).hide().before('<div id="loading" style="width:100%;text-align:center;"><img src="' + g_loadingImage + '" /><p id="progress" style="text-align: center;font-size: large;font-weight: bold;padding-top: 10px;">0%</p></div>');
  2157.  
  2158. // page
  2159. if (true) {
  2160. let pageSelectorDiv = Pages[PageType.Search].GetPageSelector();
  2161. if (pageSelectorDiv == null) {
  2162. DoLog(LogLevel.Error, 'Can not found page selector!');
  2163. return;
  2164. }
  2165.  
  2166. if ($(pageSelectorDiv).find('a').length > 2) {
  2167. let pageButton = $(pageSelectorDiv).find('a').get(1);
  2168. let newPageButtons = [];
  2169. let pageButtonString = 'Previewer';
  2170. for (let i = 0; i < 9; i++) {
  2171. let newPageButton = pageButton.cloneNode(true);
  2172. $(newPageButton).find('span').text(pageButtonString[i]);
  2173. newPageButtons.push(newPageButton);
  2174. }
  2175.  
  2176. $(pageSelectorDiv).find('button').remove();
  2177. while ($(pageSelectorDiv).find('a').length > 2) {
  2178. $(pageSelectorDiv).find('a:first').next().remove();
  2179. }
  2180.  
  2181. for (let i = 0; i < 9; i++) {
  2182. $(pageSelectorDiv).find('a:last').before(newPageButtons[i]);
  2183. }
  2184.  
  2185. $(pageSelectorDiv).find('a').attr('href', 'javascript:;');
  2186.  
  2187. let pageUrl = location.href;
  2188. if (pageUrl.indexOf('&p=') == -1 && pageUrl.indexOf('?p=') == -1) {
  2189. if (pageUrl.indexOf('?') == -1) {
  2190. pageUrl += '?p=1';
  2191. } else {
  2192. pageUrl += '&p=1';
  2193. }
  2194. }
  2195. let prevPageUrl = pageUrl.replace(/p=\d+/, 'p=' + (currentPage - g_settings.pageCount > 1 ? currentPage - g_settings.pageCount : 1));
  2196. let nextPageUrl = pageUrl.replace(/p=\d+/, 'p=' + (currentPage + g_settings.pageCount));
  2197. DoLog(LogLevel.Info, 'Previous page url: ' + prevPageUrl);
  2198. DoLog(LogLevel.Info, 'Next page url: ' + nextPageUrl);
  2199. // 重新插入一遍清除事件绑定
  2200. let prevButton = $(pageSelectorDiv).find('a:first');
  2201. prevButton.before(prevButton.clone());
  2202. prevButton.remove();
  2203. let nextButton = $(pageSelectorDiv).find('a:last');
  2204. nextButton.before(nextButton.clone());
  2205. nextButton.remove();
  2206. $(pageSelectorDiv).find('a:first').attr('href', prevPageUrl).addClass('pp-prevPage');
  2207. $(pageSelectorDiv).find('a:last').attr('href', nextPageUrl).addClass('pp-nextPage');
  2208. }
  2209.  
  2210. let onloadCallback = function (req) {
  2211. let no_artworks_found = false;
  2212.  
  2213. try {
  2214. let json = JSON.parse(req.responseText);
  2215. if (json.hasOwnProperty('error')) {
  2216. if (json.error === false) {
  2217. let data;
  2218. if (json.body.illustManga) {
  2219. data = json.body.illustManga.data;
  2220. } else if (json.body.manga) {
  2221. data = json.body.manga.data;
  2222. } else if (json.body.illust) {
  2223. data = json.body.illust.data;
  2224. }
  2225. if (data.length > 0) {
  2226. works = works.concat(data);
  2227. } else {
  2228. no_artworks_found = true;
  2229. }
  2230. } else {
  2231. DoLog(LogLevel.Error, 'ajax error!');
  2232. return;
  2233. }
  2234. } else {
  2235. DoLog(LogLevel.Error, 'Key "error" not found!');
  2236. return;
  2237. }
  2238. } catch (e) {
  2239. DoLog(LogLevel.Error, 'A invalid json string!');
  2240. DoLog(LogLevel.Info, req.responseText);
  2241. }
  2242.  
  2243. currentPage++;
  2244. currentGettingPageCount++;
  2245.  
  2246. // 后面已经没有作品了
  2247. if (no_artworks_found) {
  2248. DoLog(LogLevel.Warning, 'No artworks found, ignore ' + (g_settings.pageCount - currentGettingPageCount) + ' pages.');
  2249. currentPage += g_settings.pageCount - currentGettingPageCount;
  2250. currentGettingPageCount = g_settings.pageCount;
  2251. }
  2252. // 设定数量的页面加载完成
  2253. if (currentGettingPageCount == g_settings.pageCount) {
  2254. DoLog(LogLevel.Info, 'Load complete, start to load bookmark count.');
  2255. DoLog(LogLevel.Elements, works);
  2256.  
  2257. // 获取到的作品里面可能有广告,先删掉,否则后面一些处理需要做判断
  2258. let tempWorks = [];
  2259. for (let i = 0; i < works.length; i++) {
  2260. if (works[i].id) {
  2261. tempWorks.push(works[i]);
  2262. }
  2263. }
  2264. works = tempWorks;
  2265. DoLog(LogLevel.Info, 'Clear ad container complete.');
  2266. DoLog(LogLevel.Elements, works);
  2267.  
  2268. GetBookmarkCount(0);
  2269. } else {
  2270. getWorks(onloadCallback);
  2271. }
  2272. };
  2273.  
  2274. getWorks(onloadCallback);
  2275. }
  2276.  
  2277. let xhrs = [];
  2278. let currentRequestGroupMinimumIndex = 0;
  2279. function FillXhrsArray() {
  2280. xhrs.length = 0;
  2281. let onloadFunc = function (event) {
  2282. let json = null;
  2283. try {
  2284. json = JSON.parse(event.currentTarget.responseText);
  2285. } catch(e) {
  2286. DoLog(LogLevel.Error, 'Parse json failed!');
  2287. DoLog(LogLevel.Element, e);
  2288. return;
  2289. }
  2290.  
  2291. if (json) {
  2292. let illustId = '';
  2293. let illustIdMatched = event.currentTarget.responseURL.match(/illust_id=(\d+)/);
  2294. if (illustIdMatched) {
  2295. illustId = illustIdMatched[1];
  2296. } else {
  2297. DoLog(LogLevel.Error, 'Can not get illust id from url!');
  2298. return;
  2299. }
  2300. let indexOfThisRequest = -1;
  2301. for (let j = 0; j < g_maxXhr; j++) {
  2302. if (xhrs[j].illustId == illustId) {
  2303. indexOfThisRequest = j;
  2304. break;
  2305. }
  2306. }
  2307. if (indexOfThisRequest == -1) {
  2308. DoLog('This url not match any request!');
  2309. return;
  2310. }
  2311. xhrs[indexOfThisRequest].complete = true;
  2312.  
  2313. if (!json.error) {
  2314. let bookmarkCount = json.body.illust_details.bookmark_user_total;
  2315. works[currentRequestGroupMinimumIndex + indexOfThisRequest].bookmarkCount = parseInt(bookmarkCount);
  2316. DoLog(LogLevel.Info, 'IllustId: ' + illustId + ', bookmarkCount: ' + bookmarkCount);
  2317. } else {
  2318. DoLog(LogLevel.Error, 'Some error occured: ' + json.message);
  2319. }
  2320.  
  2321. let completeCount = 0;
  2322. // 真实完成数(不包含没有发起请求的XHR,最后一批请求时)
  2323. let completeReally = 0;
  2324. for (let j = 0; j < g_maxXhr; j++) {
  2325. if (xhrs[j].complete) {
  2326. completeCount++;
  2327. if (xhrs[j].illustId != '') {
  2328. completeReally++;
  2329. }
  2330. }
  2331. }
  2332. $('#loading').find('#progress').text(Texts[g_language].sort_getBookmarkCount.replace('%1', currentRequestGroupMinimumIndex + completeReally).replace('%2', works.length));
  2333. if (completeCount == g_maxXhr) {
  2334. currentRequestGroupMinimumIndex += g_maxXhr;
  2335. GetBookmarkCount(currentRequestGroupMinimumIndex);
  2336. }
  2337. }
  2338. };
  2339. let onerrorFunc = function (event) {
  2340. let illustId = '';
  2341. let illustIdMatched = event.currentTarget.__sentry_xhr__.url.match(/artworks\/(\d+)/);
  2342. if (illustIdMatched) {
  2343. illustId = illustIdMatched[1];
  2344. } else {
  2345. DoLog(LogLevel.Error, 'Can not get illust id from url!');
  2346. return;
  2347. }
  2348.  
  2349. DoLog(LogLevel.Error, 'Send request failed, set this illust(' + illustId + ')\'s bookmark count to 0!');
  2350.  
  2351. let indexOfThisRequest = -1;
  2352. for (let j = 0; j < g_maxXhr; j++) {
  2353. if (xhrs[j].illustId == illustId) {
  2354. indexOfThisRequest = j;
  2355. break;
  2356. }
  2357. }
  2358. if (indexOfThisRequest == -1) {
  2359. DoLog('This url not match any request!');
  2360. return;
  2361. }
  2362. xhrs[indexOfThisRequest].complete = true;
  2363.  
  2364. let completeCount = 0;
  2365. let completeReally = 0;
  2366. for (let j = 0; j < g_maxXhr; j++) {
  2367. if (xhrs[j].complete) {
  2368. completeCount++;
  2369. if (xhrs[j].illustId != '') {
  2370. completeReally++;
  2371. }
  2372. }
  2373. }
  2374. $('#loading').find('#progress').text(Texts[g_language].sort_getBookmarkCount.replace('%1', currentRequestGroupMinimumIndex + completeReally).replace('%2', works.length));
  2375. if (completeCount == g_maxXhr) {
  2376. GetBookmarkCount(currentRequestGroupMinimumIndex + g_maxXhr);
  2377. }
  2378. };
  2379. for (let i = 0; i < g_maxXhr; i++) {
  2380. xhrs.push({
  2381. xhr: new XMLHttpRequest(),
  2382. illustId: '',
  2383. complete: false,
  2384. });
  2385. xhrs[i].xhr.onload = onloadFunc;
  2386. xhrs[i].xhr.onerror = onerrorFunc;
  2387. }
  2388. }
  2389.  
  2390. let GetBookmarkCount = function (index) {
  2391. if (index >= works.length) {
  2392. clearAndUpdateWorks();
  2393. return;
  2394. }
  2395.  
  2396. if (xhrs.length === 0) {
  2397. FillXhrsArray();
  2398. }
  2399.  
  2400. for (let i = 0; i < g_maxXhr; i++) {
  2401. if (index + i >= works.length) {
  2402. xhrs[i].complete = true;
  2403. xhrs[i].illustId = '';
  2404. continue;
  2405. }
  2406.  
  2407. let illustId = works[index + i].id;
  2408. let url = 'https://www.pixiv.net/touch/ajax/illust/details?illust_id=' + illustId;
  2409. xhrs[i].illustId = illustId;
  2410. xhrs[i].complete = false;
  2411. xhrs[i].xhr.open('GET', url, true);
  2412. xhrs[i].xhr.send(null);
  2413. }
  2414. };
  2415.  
  2416. /*
  2417. li
  2418. -div
  2419. --div
  2420. ---div
  2421. ----div
  2422. -----div
  2423. ------a
  2424. -------div: 多图标签、R18标签
  2425. -------div: 里面是 img (以及 svg 动图标签)
  2426. ------div: 里面是 like 相关的元素
  2427. ---a: 作品标题,跳转链接
  2428. ---div: 作者头像和昵称
  2429. */
  2430. let clearAndUpdateWorks = function () {
  2431. filterAndSort().then(function() {
  2432.  
  2433. let container = Pages[PageType.Search].GetImageListContainer();
  2434. let firstImageElement = Pages[PageType.Search].GetFirstImageElement();
  2435. if (imageElementTemplate == null) {
  2436. imageElementTemplate = firstImageElement.cloneNode(true);
  2437.  
  2438. // 清理模板
  2439. // image
  2440. let img = $($(imageElementTemplate).find('img').get(0));
  2441. let imageDiv = img.parent();
  2442. let imageLink = imageDiv.parent();
  2443. let imageLinkDiv = imageLink.parent();
  2444. let titleLinkParent = imageLinkDiv.parent().next();
  2445. if (img == null || imageDiv == null || imageLink == null || imageLinkDiv == null || titleLinkParent == null) {
  2446. DoLog(LogLevel.Error, 'Can not found some elements!');
  2447. }
  2448. let titleLink = $('<a></a>');
  2449. if (titleLinkParent.children().length == 0) {
  2450. titleLinkParent.append(titleLink);
  2451. } else {
  2452. titleLink = titleLinkParent.children('a:first');
  2453. }
  2454.  
  2455. // author
  2456. let authorDiv = titleLinkParent.next();
  2457. let authorLinkProfileImage = authorDiv.find('a:first');
  2458. let authorLink = authorDiv.find('a:last');
  2459. let authorName = authorLink;
  2460. let authorImage = $(authorDiv.find('img').get(0));
  2461.  
  2462. // others
  2463. let bookmarkDiv = imageLink.next();
  2464. let bookmarkSvg = bookmarkDiv.find('svg');
  2465. let additionTagDiv = imageDiv.prev();
  2466. let animationTag = imageDiv.find('svg');
  2467.  
  2468. let bookmarkCountDiv = additionTagDiv.clone();
  2469. bookmarkCountDiv.css({ 'top': 'auto', 'bottom': '0px', 'width': '50%' });
  2470. additionTagDiv.parent().append(bookmarkCountDiv);
  2471.  
  2472. // 添加 class,方便后面修改内容
  2473. img.addClass('ppImg');
  2474. imageLink.addClass('ppImageLink');
  2475. //if (titleLink.get(0).tagName == 'A') {
  2476. titleLink.addClass('ppTitleLink');
  2477. //} else {
  2478. // titleLink.append('<a class="ppTitleLink"></a>');
  2479. //}
  2480. authorLinkProfileImage.addClass('ppAuthorLinkProfileImage');
  2481. authorLink.addClass('ppAuthorLink');
  2482. authorName.addClass('ppAuthorName');
  2483. authorImage.addClass('ppAuthorImage');
  2484. bookmarkSvg.addClass('ppBookmarkSvg');
  2485. additionTagDiv.addClass('ppAdditionTag');
  2486. bookmarkCountDiv.addClass('ppBookmarkCount');
  2487.  
  2488. img.attr('src', '');
  2489. additionTagDiv.empty();
  2490. bookmarkCountDiv.empty();
  2491. animationTag.remove();
  2492. bookmarkSvg.find('path:first').css('fill', 'rgb(31, 31, 31)');
  2493. bookmarkSvg.find('path:last').css('fill', 'rgb(255, 255, 255)');
  2494.  
  2495. if (g_settings.linkBlank) {
  2496. imageLink.attr('target', '_blank');
  2497. titleLink.attr('target', '_blank');
  2498. authorLinkProfileImage.attr('target', '_blank');
  2499. authorLink.attr('target', '_blank');
  2500. }
  2501. }
  2502.  
  2503. $(container).empty();
  2504. for (let i = 0; i < works.length; i++) {
  2505. let li = $(imageElementTemplate.cloneNode(true));
  2506.  
  2507. li.find('.ppImg').attr('src', works[i].url);
  2508. li.find('.ppImageLink').attr('href', '/artworks/' + works[i].id);
  2509. li.find('.ppTitleLink').attr('href', '/artworks/' + works[i].id).text(works[i].title);
  2510. li.find('.ppAuthorLink, .ppAuthorLinkProfileImage').attr('href', '/member.php?id=' + works[i].userId).attr({'userId': works[i].userId, 'profileImageUrl': works[i].profileImageUrl, 'userName': works[i].userName});
  2511. li.find('.ppAuthorName').text(works[i].userName);
  2512. li.find('.ppAuthorImage').attr('src', works[i].profileImageUrl);
  2513. li.find('.ppBookmarkSvg').attr('illustId', works[i].id);
  2514. if (works[i].bookmarkData) {
  2515. li.find('.ppBookmarkSvg').find('path').css('fill', 'rgb(255, 64, 96)');
  2516. li.find('.ppBookmarkSvg').attr('bookmarkId', works[i].bookmarkData.id);
  2517. }
  2518. if (works[i].xRestrict !== 0) {
  2519. let R18HTML = '<div style="margin-top: 2px; margin-left: 2px;"><div style="color: rgb(255, 255, 255);font-weight: bold;font-size: 10px;line-height: 1;padding: 3px 6px;border-radius: 3px;background: rgb(255, 64, 96);">R-18</div></div>';
  2520. li.find('.ppAdditionTag').append(R18HTML);
  2521. }
  2522. if (works[i].pageCount > 1) {
  2523. let pageCountHTML = '<div style="display: flex;-webkit-box-align: center;align-items: center;box-sizing: border-box;margin-left: auto;height: 20px;color: rgb(255, 255, 255);font-size: 10px;line-height: 12px;font-weight: bold;flex: 0 0 auto;padding: 4px 6px;background: rgba(0, 0, 0, 0.32);border-radius: 10px;">\<svg viewBox="0 0 9 10" width="9" height="10" style="stroke: none;line-height: 0;font-size: 0px;fill: currentcolor;"><path d="M8,3 C8.55228475,3 9,3.44771525 9,4 L9,9 C9,9.55228475 8.55228475,10 8,10 L3,10 C2.44771525,10 2,9.55228475 2,9 L6,9 C7.1045695,9 8,8.1045695 8,7 L8,3 Z M1,1 L6,1 C6.55228475,1 7,1.44771525 7,2 L7,7 C7,7.55228475 6.55228475,8 6,8 L1,8 C0.44771525,8 0,7.55228475 0,7 L0,2 C0,1.44771525 0.44771525,1 1,1 Z"></path></svg><span style="margin-left: 2px;">' + works[i].pageCount + '</span></div>';
  2524. li.find('.ppAdditionTag').append(pageCountHTML);
  2525. }
  2526. let bookmarkCountHTML = '<div style="margin-bottom: 6px; margin-left: 2px;"><div style="color: rgb(7, 95, 166);font-weight: bold;font-size: 13px;line-height: 1;padding: 3px 6px;border-radius: 3px;background: rgb(204, 236, 255);">' + works[i].bookmarkCount + ' likes</div></div>';
  2527. li.find('.ppBookmarkCount').append(bookmarkCountHTML);
  2528. if (works[i].illustType == 2) {
  2529. let animationHTML = '<svg viewBox="0 0 24 24" style="width: 48px; height: 48px;stroke: none;fill: rgb(255, 255, 255);line-height: 0;font-size: 0px;vertical-align: middle;position:absolute;"><circle cx="12" cy="12" r="10" style="fill: rgb(0, 0, 0);fill-opacity: 0.4;"></circle><path d="M9,8.74841664 L9,15.2515834 C9,15.8038681 9.44771525,16.2515834 10,16.2515834 C10.1782928,16.2515834 10.3533435,16.2039156 10.5070201,16.1135176 L16.0347118,12.8619342 C16.510745,12.5819147 16.6696454,11.969013 16.3896259,11.4929799 C16.3034179,11.3464262 16.1812655,11.2242738 16.0347118,11.1380658 L10.5070201,7.88648243 C10.030987,7.60646294 9.41808527,7.76536339 9.13806578,8.24139652 C9.04766776,8.39507316 9,8.57012386 9,8.74841664 Z"></path></svg>';
  2530. li.find('.ppImg').after(animationHTML);
  2531. }
  2532.  
  2533. $(container).append(li);
  2534. }
  2535.  
  2536. // 监听加入书签点击事件,监听父节点,但是按照 <svg> 节点处理
  2537. $('.ppBookmarkSvg').parent().on('click', function (ev) {
  2538. if (g_csrfToken == '') {
  2539. DoLog(LogLevel.Error, 'No g_csrfToken, failed to add bookmark!');
  2540. alert('获取 Token 失败,无法添加,请到详情页操作。');
  2541. return;
  2542. }
  2543. // 非公开收藏
  2544. let restrict = 0;
  2545. if (ev.ctrlKey) {
  2546. restrict = 1;
  2547. }
  2548.  
  2549. let _this = $(this).children('svg:first');
  2550. let illustId = _this.attr('illustId');
  2551. let bookmarkId = _this.attr('bookmarkId');
  2552. if (bookmarkId == null || bookmarkId == '') {
  2553. DoLog(LogLevel.Info, 'Add bookmark, illustId: ' + illustId);
  2554. $.ajax('/ajax/illusts/bookmarks/add', {
  2555. method: 'POST',
  2556. contentType: 'application/json;charset=utf-8',
  2557. headers: { 'x-csrf-token': g_csrfToken },
  2558. data: '{"illust_id":"' + illustId + '","restrict":' +restrict + ',"comment":"","tags":[]}',
  2559. success: function (data) {
  2560. DoLog(LogLevel.Info, 'addBookmark result: ');
  2561. DoLog(LogLevel.Elements, data);
  2562. if (data.error) {
  2563. DoLog(LogLevel.Error, 'Server returned an error: ' + data.message);
  2564. return;
  2565. }
  2566. let bookmarkId = data.body.last_bookmark_id;
  2567. DoLog(LogLevel.Info, 'Add bookmark success, bookmarkId is ' + bookmarkId);
  2568. _this.attr('bookmarkId', bookmarkId);
  2569. _this.find('path').css('fill', 'rgb(255, 64, 96)');
  2570. }
  2571. });
  2572. } else {
  2573. DoLog(LogLevel.Info, 'Delete bookmark, bookmarkId: ' + bookmarkId);
  2574. $.ajax('/rpc/index.php', {
  2575. method: 'POST',
  2576. headers: { 'x-csrf-token': g_csrfToken },
  2577. data: { "mode": "delete_illust_bookmark", "bookmark_id": bookmarkId },
  2578. success: function (data) {
  2579. DoLog(LogLevel.Info, 'addBookmark result: ');
  2580. DoLog(LogLevel.Elements, data);
  2581. if (data.error) {
  2582. DoLog(LogLevel.Error, 'Server returned an error: ' + data.message);
  2583. return;
  2584. }
  2585. DoLog(LogLevel.Info, 'Delete bookmark success.');
  2586. _this.attr('bookmarkId', '');
  2587. _this.find('path:first').css('fill', 'rgb(31, 31, 31)');
  2588. _this.find('path:last').css('fill', 'rgb(255, 255, 255)');
  2589. }
  2590. });
  2591. }
  2592.  
  2593. _this.parent().focus();
  2594. });
  2595.  
  2596. $('.ppAuthorLink').on('mouseenter', function(e){
  2597. let _this = $(this);
  2598.  
  2599. function getOffset(e) {
  2600. if (e.offsetParent) {
  2601. let offset = getOffset(e.offsetParent);
  2602. return {
  2603. offsetTop: e.offsetTop + offset.offsetTop,
  2604. offsetLeft: e.offsetLeft + offset.offsetLeft,
  2605. };
  2606. } else {
  2607. return {
  2608. offsetTop: e.offsetTop,
  2609. offsetLeft: e.offsetLeft,
  2610. };
  2611. }
  2612. }
  2613.  
  2614. let isFollowed = false;
  2615. $.ajax('https://www.pixiv.net/ajax/user/' + _this.attr('userId') + '?full=1', {
  2616. method: 'GET',
  2617. async: false,
  2618. success: function(data) {
  2619. if (data.error == false && data.body.isFollowed) {
  2620. isFollowed = true;
  2621. }
  2622. },
  2623. });
  2624.  
  2625. $('.pp-authorDiv').remove();
  2626. let pres = $('<div class="pp-authorDiv"><div class="ppa-main" style="position: absolute; top: 0px; left: 0px; border-width: 1px; border-style: solid; z-index: 1; border-color: rgba(0, 0, 0, 0.08); border-radius: 8px;"><div class=""style=" width: 336px; background-color: rgb(255, 255, 255); padding-top: 24px; flex-flow: column;"><div class=""style=" display: flex; align-items: center; flex-flow: column;"><a class="ppa-authorLink"><div role="img"size="64"class=""style=" display: inline-block; width: 64px; height: 64px; border-radius: 50%; overflow: hidden;"><img class="ppa-authorImage" width="64"height="64"style="object-fit: cover; object-position: center top;"></div></a><a class="ppa-authorLink"><div class="ppa-authorName" style=" line-height: 24px; font-size: 16px; font-weight: bold; margin: 4px 0px 0px;"></div></a><div class=""style=" margin: 12px 0px 24px;"><button type="button"class="ppa-follow"style=" padding: 9px 25px; line-height: 1; border: none; border-radius: 16px; font-weight: 700; background-color: #0096fa; color: #fff; cursor: pointer;"><span style="margin-right: 4px;"><svg viewBox="0 0 8 8"width="10"height="10"class=""style=" stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-width: 2;"><line x1="1"y1="4"x2="7"y2="4"></line><line x1="4"y1="1"x2="4"y2="7"></line></svg></span>关注</button></div></div></div></div></div>');
  2627. $('body').append(pres);
  2628. let offset = getOffset(this);
  2629. pres.find('.ppa-main').css({'top': offset.offsetTop - 196 + 'px', 'left': offset.offsetLeft - 113 + 'px'});
  2630. pres.find('.ppa-authorLink').attr('href', '/member.php?id=' + _this.attr('userId'));
  2631. pres.find('.ppa-authorImage').attr('src', _this.attr('profileImageUrl'));
  2632. pres.find('.ppa-authorName').text(_this.attr('userName'));
  2633. if (isFollowed) {
  2634. pres.find('.ppa-follow').get(0).outerHTML = '<button type="button" class="ppa-follow followed" data-click-action="click" data-click-label="follow" style="padding: 9px 25px;line-height: 1;border: none;border-radius: 16px;font-size: 14px;font-weight: 700;cursor: pointer;">关注中</button>';
  2635. }
  2636. pres.find('.ppa-follow').attr('userId', _this.attr('userId'));
  2637. pres.on('mouseleave', function(e) {
  2638. $(this).remove();
  2639. }).on('mouseenter', function() {
  2640. $(this).addClass('mouseenter');
  2641. });
  2642.  
  2643. pres.find('.ppa-follow').on('click', function() {
  2644. let userId = $(this).attr('userId');
  2645. if ($(this).hasClass('followed')) {
  2646. // 取关
  2647. $.ajax('https://www.pixiv.net/rpc_group_setting.php', {
  2648. method: 'POST',
  2649. headers: { 'x-csrf-token': g_csrfToken },
  2650. data: 'mode=del&type=bookuser&id=' + userId,
  2651. success: function(data) {
  2652. DoLog(LogLevel.Info, 'delete bookmark result: ');
  2653. DoLog(LogLevel.Elements, data);
  2654.  
  2655. if (data.type == 'bookuser') {
  2656. $('.ppa-follow').get(0).outerHTML = '<button type="button"class="ppa-follow"style=" padding: 9px 25px; line-height: 1; border: none; border-radius: 16px; font-weight: 700; background-color: #0096fa; color: #fff; cursor: pointer;"><span style="margin-right: 4px;"><svg viewBox="0 0 8 8"width="10"height="10"class=""style=" stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-width: 2;"><line x1="1"y1="4"x2="7"y2="4"></line><line x1="4"y1="1"x2="4"y2="7"></line></svg></span>关注</button>';
  2657. }
  2658. else {
  2659. DoLog(LogLevel.Error, 'Delete follow failed!');
  2660. }
  2661. }
  2662. });
  2663. } else {
  2664. // 关注
  2665. $.ajax('https://www.pixiv.net/bookmark_add.php', {
  2666. method: 'POST',
  2667. headers: {'x-csrf-token': g_csrfToken},
  2668. data: 'mode=add&type=user&user_id=' + userId + '&tag=&restrict=0&format=json',
  2669. success: function (data) {
  2670. DoLog(LogLevel.Info, 'addBookmark result: ');
  2671. DoLog(LogLevel.Elements, data);
  2672. // success
  2673. if (data.length === 0) {
  2674. $('.ppa-follow').get(0).outerHTML = '<button type="button" class="ppa-follow followed" data-click-action="click" data-click-label="follow" style="padding: 9px 25px;line-height: 1;border: none;border-radius: 16px;font-size: 14px;font-weight: 700;cursor: pointer;">关注中</button>';
  2675. } else {
  2676. DoLog(LogLevel.Error, 'Follow failed!');
  2677. }
  2678. }
  2679. });
  2680. }
  2681. });
  2682. }).on('mouseleave', function(e) {
  2683. setTimeout(function() {
  2684. if (!$('.pp-authorDiv').hasClass('mouseenter')) {
  2685. $('.pp-authorDiv').remove();
  2686. }
  2687. }, 200);
  2688. });
  2689.  
  2690. if (works.length === 0) {
  2691. $(container).show().get(0).outerHTML = '<div class=""style="display: flex;align-items: center;justify-content: center; height: 408px;flex-flow: column;"><div class=""style="margin-bottom: 12px;color: rgba(0, 0, 0, 0.16);"><svg viewBox="0 0 16 16"size="72"style="fill: currentcolor;height: 72px;vertical-align: middle;"><path d="M8.25739 9.1716C7.46696 9.69512 6.51908 10 5.5 10C2.73858 10 0.5 7.76142 0.5 5C0.5 2.23858 2.73858 0 5.5 0C8.26142 0 10.5 2.23858 10.5 5C10.5 6.01908 10.1951 6.96696 9.67161 7.75739L11.7071 9.79288C12.0976 10.1834 12.0976 10.8166 11.7071 11.2071C11.3166 11.5976 10.6834 11.5976 10.2929 11.2071L8.25739 9.1716ZM8.5 5C8.5 6.65685 7.15685 8 5.5 8C3.84315 8 2.5 6.65685 2.5 5C2.5 3.34315 3.84315 2 5.5 2C7.15685 2 8.5 3.34315 8.5 5Z"transform="translate(2.25 2.25)"fill-rule="evenodd"clip-rule="evenodd"></path></svg></div><span class="sc-LzMCO fLDUzU">' + Texts[g_language].sort_noWork + '</span></div>';
  2692. }
  2693.  
  2694. // 恢复显示
  2695. $('#loading').remove();
  2696. $(container).show();
  2697.  
  2698. Pages[PageType.Search].ProcessPageElements();
  2699.  
  2700. // 监听键盘的左右键,用来翻页
  2701. $(document).keydown(function (e) {
  2702. if (g_settings.pageByKey != 1) {
  2703. return;
  2704. }
  2705. if (e.keyCode == 39) {
  2706. let btn = $('.pp-nextPage');
  2707. if (btn.length < 1 || btn.attr('hidden') == 'hidden') {
  2708. return;
  2709. }
  2710. // 很奇怪不能用 click()
  2711. location.href = btn.attr('href');
  2712. } else if (e.keyCode == 37) {
  2713. let btn = $('.pp-prevPage');
  2714. if (btn.length < 1 || btn.attr('hidden') == 'hidden') {
  2715. return;
  2716. }
  2717. location.href = btn.attr('href');
  2718. }
  2719. });
  2720.  
  2721. if (callback) {
  2722. callback();
  2723. }
  2724. });
  2725. }
  2726. };
  2727. /* ---------------------------------------- 设置 ---------------------------------------- */
  2728. function SetCookie(name, value) {
  2729. let Days = 180;
  2730. let exp = new Date();
  2731. exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
  2732. let str = JSON.stringify(value);
  2733. document.cookie = name + "=" + str + ";expires=" + exp.toGMTString() + ';path=\/';
  2734. }
  2735. function GetCookie(name) {
  2736. let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
  2737. if (arr = document.cookie.match(reg)) {
  2738. return unescape(arr[2]);
  2739. }
  2740. else {
  2741. return null;
  2742. }
  2743. }
  2744. function ShowInstallMessage() {
  2745. $('#pp-bg').remove();
  2746. let bg = $('<div id="pp-bg"></div>').css({
  2747. 'width': document.documentElement.clientWidth + 'px', 'height': document.documentElement.clientHeight + 'px', 'position': 'fixed',
  2748. 'z-index': 999999, 'background-color': 'rgba(0,0,0,0.8)',
  2749. 'left': '0px', 'top': '0px'
  2750. });
  2751. $('body').append(bg);
  2752.  
  2753. bg.get(0).innerHTML = '<img id="pps-close"src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/Close.png"style="position: absolute; right: 35px; top: 20px; width: 32px; height: 32px; cursor: pointer;"><div style="position: absolute;width: 40%;left: 30%;top: 25%;font-size: 25px; text-align: center; color: white;">' + Texts[g_language].install_title + g_version + '</div><br>' + Texts[g_language].install_body;
  2754. $('#pps-close').click(function () {
  2755. $('#pp-bg').remove();
  2756. });
  2757. }
  2758. function GetSettings() {
  2759. let settings;
  2760.  
  2761. let cookie = GetCookie('PixivPreview');
  2762. // 新安装
  2763. if (cookie == null || cookie == 'null') {
  2764. settings = g_defaultSettings;
  2765. SetCookie('PixivPreview', settings);
  2766.  
  2767. ShowInstallMessage();
  2768. } else {
  2769. settings = JSON.parse(cookie);
  2770. }
  2771.  
  2772. // 升级
  2773. if (settings.version != g_version) {
  2774. ShowInstallMessage();
  2775. }
  2776.  
  2777. if (settings.version == null || settings.version != g_version) {
  2778. settings.version = g_version;
  2779. SetCookie('PixivPreview', settings);
  2780. }
  2781.  
  2782. return settings;
  2783. }
  2784. function ShowSetting() {
  2785. let screenWidth = document.documentElement.clientWidth;
  2786. let screenHeight = document.documentElement.clientHeight;
  2787.  
  2788. $('#pp-bg').remove();
  2789. let bg = $('<div id="pp-bg"></div>').css({
  2790. 'width': screenWidth + 'px', 'height': screenHeight + 'px', 'position': 'fixed',
  2791. 'z-index': 999999, 'background-color': 'rgba(0,0,0,0.8)',
  2792. 'left': '0px', 'top': '0px'
  2793. });
  2794. $('body').append(bg);
  2795.  
  2796. let settings = GetSettings();
  2797.  
  2798. let settingHTML = '<div style="color: white; font-size: 1em;">' +
  2799. '<img id="pps-close" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/Close.png" style="position: absolute; right: 35px; top: 20px; width: 32px; height: 32px; cursor: pointer;">' +
  2800. '<div style="position: absolute; width: 40%; left: 25%; top: 25%; overflow: hidden;">' +
  2801. '<ul style="list-style: none; padding: 0; margin: 0;">' +
  2802. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_preview + '</li>' +
  2803. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_sort + '</li>' +
  2804. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_anime + '</li>' +
  2805. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_origin + '</li>' +
  2806. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_previewDelay + '</li>' +
  2807. '<li style="height: 32px; font-size: 25px;"></li>' +
  2808. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_maxPage + '</li>' +
  2809. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_hideWork + '</li>' +
  2810. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_hideFav + '</li>' +
  2811. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_hideFollowed + '</li>' +
  2812. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_blank + '</li>' +
  2813. '<li style="height: 32px; font-size: 25px;">' + Texts[g_language].setting_turnPage + '</li>' +
  2814. '</ul></div>' +
  2815. '<div id="pps-right" style="position: absolute; width: 10%; right: 25%; text-align: right; top: 25%;">' +
  2816. '<ul style="list-style: none; padding: 0; margin: 0;">' +
  2817. '<li style="height: 32px;"><img id="pps-preview" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2818. '<li style="height: 32px;"><img id="pps-sort" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2819. '<li style="height: 32px;"><img id="pps-anime" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2820. '<li style="height: 32px;"><img id="pps-original" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2821. '<li style="height: 32px;"><input id="pps-previewDelay" style="height: 28px; font-size: 24px; padding: 0px; margin: 0px; border-width: 0px; width: 64px; text-align: center;"></li>' +
  2822. '<li style="height: 32px;"></li>' +
  2823. '<li style="height: 32px;"><input id="pps-maxPage" style="height: 28px; font-size: 24px; padding: 0px; margin: 0px; border-width: 0px; width: 64px; text-align: center;"></li>' +
  2824. '<li style="height: 32px;"><input id="pps-hideLess" style="height: 28px; font-size: 24px; padding: 0px; margin: 0px; border-width: 0px; width: 64px; text-align: center;"></li>' +
  2825. '<li style="height: 32px;"><img id="pps-hideBookmarked" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2826. '<li style="height: 32px;"><img id="pps-hideFollowed" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2827. '<li style="height: 32px;"><img id="pps-newTab" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2828. '<li style="height: 32px;"><img id="pps-pageKey" src="https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png" style="height: 32px; cursor: pointer;"></li>' +
  2829. '</ul></div>' +
  2830. '<div style="margin-top: 10px;position: absolute;bottom: 20%;width: 100%;text-align: center;">' +
  2831. '<button id="pps-save" style="font-size: 25px;border-radius: 15px;height: 48px;width: 128px;background-color: green;color: white;margin: 0 32px 0 32px;cursor: pointer;border: none;">' + Texts[g_language].setting_save + '</button>' +
  2832. '<button id="pps-reset" style="font-size: 25px;border-radius: 15px;height: 48px;width: 128px;background-color: darkred;color: white;margin: 0 32px 0 32px;cursor: pointer;border: none;">' + Texts[g_language].setting_reset + '</button>' +
  2833. '</div></div>';
  2834.  
  2835. bg.get(0).innerHTML = settingHTML;
  2836.  
  2837. let imgOn = 'https://pp-1252089172.cos.ap-chengdu.myqcloud.com/On.png';
  2838. let imgOff = 'https://pp-1252089172.cos.ap-chengdu.myqcloud.com/Off.png'
  2839. $('#pps-preview').attr('src', settings.enablePreview ? imgOn : imgOff).addClass(settings.enablePreview ? 'on' : 'off').css('cursor: pointer');
  2840. $('#pps-sort').attr('src', settings.enableSort ? imgOn : imgOff).addClass(settings.enableSort ? 'on' : 'off').css('cursor: pointer');
  2841. $('#pps-anime').attr('src', settings.enableAnimeDownload ? imgOn : imgOff).addClass(settings.enableAnimeDownload ? 'on' : 'off').css('cursor: pointer');
  2842. $('#pps-original').attr('src', settings.original ? imgOn : imgOff).addClass(settings.original ? 'on' : 'off').css('cursor: pointer');
  2843. $('#pps-previewDelay').val(settings.previewDelay == null ? g_defaultSettings.previewDelay : settings.previewDelay);
  2844. $('#pps-maxPage').val(settings.pageCount == null ? g_defaultSettings.pageCount : settings.pageCount);
  2845. $('#pps-hideLess').val(settings.favFilter == null ? g_defaultSettings.favFilter : settings.favFilter);
  2846. $('#pps-hideBookmarked').attr('src', settings.hideFavorite ? imgOn : imgOff).addClass(settings.hideFavorite ? 'on' : 'off').css('cursor: pointer');
  2847. $('#pps-hideFollowed').attr('src', settings.hideFollowed ? imgOn : imgOff).addClass(settings.hideFollowed ? 'on' : 'off').css('cursor: pointer');
  2848. $('#pps-newTab').attr('src', settings.linkBlank ? imgOn : imgOff).addClass(settings.linkBlank ? 'on' : 'off').css('cursor: pointer');
  2849. $('#pps-pageKey').attr('src', settings.pageByKey ? imgOn : imgOff).addClass(settings.pageByKey ? 'on' : 'off').css('cursor: pointer');
  2850.  
  2851. $('#pps-right').find('img').click(function () {
  2852. let _this = $(this);
  2853.  
  2854. if (_this.hasClass('on')) {
  2855. _this.attr('src', imgOff).removeClass('on').addClass('off');
  2856. } else {
  2857. _this.attr('src', imgOn).removeClass('off').addClass('on');
  2858. }
  2859. });
  2860.  
  2861. $('#pps-save').click(function () {
  2862. if ($('#pps-maxPage').val() === '') {
  2863. $('#pps-maxPage').val(g_defaultSettings.pageCount);
  2864. }
  2865. if ($('#pps-hideLess').val() == '') {
  2866. $('#pps-hideLess').val(g_defaultSettings.favFilter);
  2867. }
  2868.  
  2869. let settings = {
  2870. 'enablePreview': $('#pps-preview').hasClass('on') ? 1 : 0,
  2871. 'enableSort': $('#pps-sort').hasClass('on') ? 1 : 0,
  2872. 'enableAnimeDownload': $('#pps-anime').hasClass('on') ? 1 : 0,
  2873. 'original': $('#pps-original').hasClass('on') ? 1 : 0,
  2874. 'previewDelay': parseInt($('#pps-previewDelay').val()),
  2875. 'pageCount': parseInt($('#pps-maxPage').val()),
  2876. 'favFilter': parseInt($('#pps-hideLess').val()),
  2877. 'hideFavorite': $('#pps-hideBookmarked').hasClass('on') ? 1 : 0,
  2878. 'hideFollowed': $('#pps-hideFollowed').hasClass('on') ? 1 : 0,
  2879. 'linkBlank': $('#pps-newTab').hasClass('on') ? 1 : 0,
  2880. 'pageByKey': $('#pps-pageKey').hasClass('on') ? 1 : 0,
  2881. 'version': g_version,
  2882. }
  2883.  
  2884. SetCookie('PixivPreview', settings);
  2885.  
  2886. location.href = location.href;
  2887. });
  2888.  
  2889. $('#pps-reset').click(function () {
  2890. let comfirmText = Texts[g_language].setting_resetHint;
  2891. if (confirm(comfirmText)) {
  2892. SetCookie('PixivPreview', null);
  2893. location.href = location.href;
  2894. }
  2895. });
  2896.  
  2897. $('#pps-close').click(function () {
  2898. $('#pp-bg').remove();
  2899. });
  2900.  
  2901. // 不换行
  2902. $('#pp-bg').find('li').css('overflow', 'hidden');
  2903.  
  2904. if (screenWidth < 1400) {
  2905. let fontSize = parseInt(25 - (1400 - screenWidth) / 40);
  2906. $('#pp-bg').find('li').css('font-size', fontSize + 'px');
  2907. }
  2908. }
  2909. function SetTargetBlank(returnMap) {
  2910. if (g_settings.linkBlank) {
  2911. let target = [];
  2912. $.each(returnMap.controlElements, function(i, e) {
  2913. if (e.tagName == 'A') {
  2914. target.push(e);
  2915. }
  2916. });
  2917.  
  2918. $.each($(returnMap.controlElements).find('a'), function(i, e) {
  2919. target.push(e);
  2920. });
  2921.  
  2922. $.each(target, function(i, e) {
  2923. $(e).attr({'target': '_blank', 'rel': 'external'});
  2924. // 主页这里用的是js监听跳转,特殊处理
  2925. if (g_pageType == PageType.Home || g_pageType == PageType.Member || g_pageType == PageType.Artwork) {
  2926. e.addEventListener("click", function(ev) {
  2927. ev.stopPropagation();
  2928. })
  2929. }
  2930. });
  2931. }
  2932. }
  2933. /* --------------------------------------- 主函数 --------------------------------------- */
  2934. let loadInterval = null;
  2935. let itv = null;
  2936. function Load() {
  2937. // 匹配当前页面
  2938. for (let i = 0; i < PageType.PageTypeCount; i++) {
  2939. if (Pages[i].CheckUrl(location.href)) {
  2940. g_pageType = i;
  2941. break;
  2942. }
  2943. }
  2944. if (g_pageType >= 0) {
  2945. DoLog(LogLevel.Info, 'Current page is ' + Pages[g_pageType].PageTypeString);
  2946. } else {
  2947. DoLog(LogLevel.Info, 'Unsupported page.');
  2948. clearInterval(loadInterval);
  2949. return;
  2950. }
  2951.  
  2952. // 自动检测语言
  2953. if (g_autoDetectLanguage) {
  2954. let lang = $('html').attr('lang');
  2955. if (lang && lang.indexOf('zh') != -1) {
  2956. // 简体中文和繁体中文都用简体中文
  2957. g_language = Lang.zh_CN;
  2958. } else {
  2959. // 其他的统一用英语,其他语言也不知道谷歌翻译得对不对
  2960. g_language = Lang.en_US;
  2961. }
  2962. }
  2963.  
  2964. // 设置按钮
  2965. let toolBar = Pages[g_pageType].GetToolBar();
  2966. if (toolBar) {
  2967. DoLog(LogLevel.Elements, toolBar);
  2968. clearInterval(loadInterval);
  2969. } else {
  2970. DoLog(LogLevel.Warning, 'Get toolbar failed.');
  2971. return;
  2972. }
  2973.  
  2974. window.onresize = function() {
  2975. if ($('#pps-save').length > 0) {
  2976. let screenWidth = document.documentElement.clientWidth;
  2977. let screenHeight = document.documentElement.clientHeight;
  2978. $('#pp-bg').css({'width': screenWidth + 'px', 'height': screenHeight + 'px'});
  2979.  
  2980. if (screenWidth < 1400) {
  2981. let fontSize = parseInt(25 - (1400 - screenWidth) / 40);
  2982. $('#pp-bg').find('li').css('font-size', fontSize + 'px');
  2983. }
  2984. }
  2985. };
  2986.  
  2987. if ($('#pp-settings').length == 0) {
  2988. toolBar.appendChild(toolBar.firstChild.cloneNode(true));
  2989. toolBar.lastChild.outerHTML = '<button id="pp-settings" style="background-color: rgb(0, 0, 0);margin-top: 5px;opacity: 0.8;cursor: pointer;border: none;padding: 12px;border-radius: 24px;width: 48px;height: 48px;"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve" style="fill: white;"><metadata> Svg Vector Icons : http://www.sfont.cn </metadata><g><path d="M377.5,500c0,67.7,54.8,122.5,122.5,122.5S622.5,567.7,622.5,500S567.7,377.5,500,377.5S377.5,432.3,377.5,500z"></path><path d="M990,546v-94.8L856.2,411c-8.9-35.8-23-69.4-41.6-100.2L879,186L812,119L689,185.2c-30.8-18.5-64.4-32.6-100.2-41.5L545.9,10h-94.8L411,143.8c-35.8,8.9-69.5,23-100.2,41.5L186.1,121l-67,66.9L185.2,311c-18.6,30.8-32.6,64.4-41.5,100.3L10,454v94.8L143.8,589c8.9,35.8,23,69.4,41.6,100.2L121,814l67,67l123-66.2c30.8,18.6,64.5,32.6,100.3,41.5L454,990h94.8L589,856.2c35.8-8.9,69.4-23,100.2-41.6L814,879l67-67l-66.2-123.1c18.6-30.7,32.6-64.4,41.5-100.2L990,546z M500,745c-135.3,0-245-109.7-245-245c0-135.3,109.7-245,245-245s245,109.7,245,245C745,635.3,635.3,745,500,745z"></path></g></svg></button>';
  2990. $(toolBar.lastChild).css('margin-top', '10px');
  2991. $(toolBar.lastChild).css('opacity', '0.8');
  2992. $(toolBar.lastChild).click(function () {
  2993. ShowSetting();
  2994. });
  2995. }
  2996.  
  2997. // 读取设置
  2998. g_settings = GetSettings();
  2999.  
  3000. // g_csrfToken
  3001. if (g_pageType == PageType.Search) {
  3002. $.get(location.href, function (data) {
  3003. let matched = data.match(/token":"([a-z0-9]{32})/);
  3004. if (matched.length > 0) {
  3005. g_csrfToken = matched[1];
  3006. DoLog(LogLevel.Info, 'Got g_csrfToken: ' + g_csrfToken);
  3007. } else {
  3008. DoLog(LogLevel.Error, 'Can not get g_csrfToken, so you can not add works to bookmark when sorting has enabled.');
  3009. }
  3010. });
  3011. }
  3012.  
  3013. // 排序、预览
  3014. itv = setInterval(function () {
  3015. let returnMap = Pages[g_pageType].ProcessPageElements();
  3016. if (!returnMap.loadingComplete) {
  3017. return;
  3018. }
  3019.  
  3020. DoLog(LogLevel.Info, 'Process page comlete, sorting and prevewing begin.');
  3021. DoLog(LogLevel.Elements, returnMap);
  3022.  
  3023. clearInterval(itv);
  3024.  
  3025. SetTargetBlank(returnMap);
  3026.  
  3027. try {
  3028. if (g_pageType == PageType.Artwork) {
  3029. Pages[g_pageType].Work();
  3030. if (g_settings.enablePreview) {
  3031. PixivPreview();
  3032. }
  3033. }
  3034. else if (g_pageType == PageType.Search) {
  3035. if (g_settings.enableSort) {
  3036. g_sortComplete = false;
  3037. PixivSK(function() {
  3038. g_sortComplete = true;
  3039. if (g_settings.enablePreview) {
  3040. PixivPreview();
  3041. }
  3042. });
  3043. } else if (g_settings.enablePreview) {
  3044. PixivPreview();
  3045. }
  3046. } else if (g_settings.enablePreview) {
  3047. PixivPreview();
  3048. }
  3049. }
  3050. catch (e) {
  3051. DoLog(LogLevel.Error, 'Unknown error: ' + e);
  3052. }
  3053. }, 500);
  3054. }
  3055. loadInterval = setInterval(Load, 1000);
  3056. setInterval(function() {
  3057. if (location.href != initialUrl) {
  3058. // 排序中点击搜索tag,可能导致进行中的排序出现混乱,加取消太麻烦,直接走刷新
  3059. if (!g_sortComplete) {
  3060. location.href = location.href;
  3061. return;
  3062. }
  3063. // fix 主页预览图出现后点击图片,进到详情页,预览图不消失的问题
  3064. if ($('.pp-main').length > 0) {
  3065. $('.pp-main').remove();
  3066. }
  3067. initialUrl = location.href;
  3068. clearInterval(loadInterval);
  3069. clearInterval(itv);
  3070. clearInterval(autoLoadInterval);
  3071. autoLoadInterval = null;
  3072. g_pageType = -1;
  3073. loadInterval = setInterval(Load, 300);
  3074. }
  3075. }, 1000);