Pixiv Previewer

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.

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

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

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址