// ==UserScript== // @name Pixiv Previewer // @namespace https://github.com/Ocrosoft/PixivPreviewer // @version 3.6.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. // @description:zh-CN 显示预览图(支持单图,多图,动图);动图压缩包下载;搜索页按热门度(收藏数)排序并显示收藏数,适配11月更新。 // @description:ja プレビュー画像の表示(単一画像、複数画像、動画のサポート); アニメーションのダウンロード(.zip); お気に入りの数で検索ページをソートします(そして表示します)。 最新の検索ページ用に更新されました。 // @description:zh_TW 顯示預覽圖像(支持單幅圖像,多幅圖像,運動圖像); 下載動畫(.zip); 按收藏夾數對搜索頁進行排序(並顯示)。 已為最新的搜索頁面適配。 // @author Ocrosoft // @match *://www.pixiv.net/* // @grant unsafeWindow // @compatible Chrome // @downloadURL none // ==/UserScript== // https://greasyfork.org/zh-CN/scripts/417761-ilog // 后面把DoLog替换掉 function ILog() { this.prefix = ''; this.v = function (value) { if (level <= this.LogLevel.Verbose) { console.log(this.prefix + value); } } this.i = function (info) { if (level <= this.LogLevel.Info) { console.info(this.prefix + info); } } this.w = function (warning) { if (level <= this.LogLevel.Warning) { console.warn(this.prefix + warning); } } this.e = function (error) { if (level <= this.LogLevel.Error) { console.error(this.prefix + error); } } this.d = function (element) { if (level <= this.LogLevel.Verbose) { console.log(element); } } this.setLogLevel = function (logLevel) { level = logLevel; } this.LogLevel = { Verbose: 0, Info: 1, Warning: 2, Error: 3, }; let level = this.LogLevel.Verbose; } var iLog = new ILog(); // https://greasyfork.org/zh-CN/scripts/417760-checkjquery var checkJQuery = function () { let jqueryCdns = [ 'http://code.jquery.com/jquery-2.1.4.min.js', 'https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js', 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js', 'https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js', 'https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js', ]; function isJQueryValid() { try { let wd = unsafeWindow; if (wd.jQuery && !wd.$) { wd.$ = wd.jQuery; } $(); return true; } catch (exception) { return false; } } function insertJQuery(url) { let script = document.createElement('script'); script.src = url; document.head.appendChild(script); return script; } function converProtocolIfNeeded(url) { let isHttps = location.href.indexOf('https://') != -1; let urlIsHttps = url.indexOf('https://') != -1; if (isHttps && !urlIsHttps) { return url.replace('http://', 'https://'); } else if (!isHttps && urlIsHttps) { return url.replace('https://', 'http://'); } return url; } function waitAndCheckJQuery(cdnIndex, resolve) { if (cdnIndex >= jqueryCdns.length) { iLog.e('无法加载 JQuery,正在退出。'); resolve(false); return; } let url = converProtocolIfNeeded(jqueryCdns[cdnIndex]); iLog.i('尝试第 ' + (cdnIndex + 1) + ' 个 JQuery CDN:' + url + '。'); let script = insertJQuery(url); setTimeout(function () { if (isJQueryValid()) { iLog.i('已加载 JQuery。'); resolve(true); } else { iLog.w('无法访问。'); script.remove(); waitAndCheckJQuery(cdnIndex + 1, resolve); } }, 100); } return new Promise(function (resolve) { if (isJQueryValid()) { iLog.i('已加载 jQuery。'); resolve(true); } else { iLog.i('未发现 JQuery,尝试加载。'); waitAndCheckJQuery(0, resolve); } }); } let Lang = { // 自动选择 auto: -1, // 中文-中国大陆 zh_CN: 0, // 英语-美国 en_US: 1, // 俄语-俄罗斯 ru_RU: 2, }; let Texts = {}; Texts[Lang.zh_CN] = { // 安装或更新后弹出的提示 install_title: '欢迎使用 PixivPreviewer v', install_body: '

欢迎反馈问题和提出建议!>反馈页面<


如果您是第一次使用,推荐到 详情页 查看脚本介绍。

', // 设置项 setting_language: '语言', setting_preview: '预览', setting_sort: '排序(仅搜索页生效)', setting_anime: '动图下载(动图预览及详情页生效)', setting_origin: '预览时优先显示原图(慢)', setting_previewDelay: '延迟显示预览图(毫秒)', setting_maxPage: '每次排序时统计的最大页数', setting_hideWork: '隐藏收藏数少于设定值的作品', setting_hideFav: '排序时隐藏已收藏的作品', setting_hideFollowed: '排序时隐藏已关注画师作品', setting_clearFollowingCache: '清除缓存', setting_clearFollowingCacheHelp: '关注画师信息会在本地保存一天,如果希望立即更新,请点击清除缓存', setting_followingCacheCleared: '已清除缓存,请刷新页面。', setting_blank: '使用新标签页打开作品详情页', setting_turnPage: '使用键盘←→进行翻页(排序后的搜索页)', setting_save: '保存设置', setting_reset: '重置脚本', setting_resetHint: '这会删除所有设置,相当于重新安装脚本,确定要重置吗?', setting_novelSort: '小说排序', setting_novelMaxPage: '小说排序时统计的最大页数', // 搜索时过滤值太高 sort_noWork: '没有可以显示的作品', sort_getWorks: '正在获取第%1/%2页作品', sort_getBookmarkCount: '获取收藏数:%1/%2', sort_getPublicFollowing: '获取公开关注画师', sort_getPrivateFollowing: '获取私有关注画师', sort_filtering: '过滤%1收藏量低于%2的作品', sort_filteringHideFavorite: '已收藏和', sort_fullSizeThumb: '排序后展示全尺寸图片', // 小说排序 nsort_getWorks: '正在获取第1%/2%页作品', nsort_sorting: '正在按收藏量排序', nsort_hideFav: '排序时隐藏已收藏的作品', nsort_hideFollowed: '排序时隐藏已关注作者作品' }; // translate by google Texts[Lang.en_US] = { install_title: 'Welcome to PixivPreviewer v', install_body: '

Feedback questions and suggestions are welcome! >Feedback Page<


If you are using it for the first time, it is recommended to go to the Details Page to see the script introduction.

', setting_language: 'Language', setting_preview: 'Preview', setting_sort: 'Sorting (Search page)', setting_anime: 'Animation download (Preview and Artwork page)', setting_origin: 'Display original image when preview (slow)', setting_previewDelay: 'Delay of display preview image(Million seconds)', setting_maxPage: 'Maximum number of pages counted per sort', setting_hideWork: 'Hide works with bookmark count less than set value', setting_hideFav: 'Hide favorites when sorting', setting_hideFollowed: 'Hide artworks of followed artists when sorting', setting_clearFollowingCache: 'Cache', 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', setting_followingCacheCleared: 'Success, please refresh the page.', setting_blank: 'Open works\' details page in new tab', setting_turnPage: 'Use ← → to turn pages (Search page)', setting_save: 'Save', setting_reset: 'Reset', setting_resetHint: 'This will delete all settings and set it to default. Are you sure?', setting_novelSort: 'Sorting (Novel)', setting_novelMaxPage: 'Maximum number of pages counted for novel sorting', sort_noWork: 'No works to display', sort_getWorks: 'Getting artworks of page: %1 of %2', sort_getBookmarkCount: 'Getting bookmark count of artworks:%1 of %2', sort_getPublicFollowing: 'Getting public following list', sort_getPrivateFollowing: 'Getting private following list', sort_filtering: 'Filtering%1works with bookmark count less than %2', sort_filteringHideFavorite: ' favorited works and ', sort_fullSizeThumb: 'Display not cropped images.', nsort_getWorks: 'Getting novels of page: 1% of 2%', nsort_sorting: 'Sorting by bookmark cound', nsort_hideFav: 'Hide favorites when sorting', nsort_hideFollowed: 'Hide artworks of followed authors when sorting' }; // RU: перевод от vanja-san Texts[Lang.ru_RU] = { install_title: 'Добро пожаловать в PixivPreviewer v', install_body: '

Вопросы и предложения приветствуются! >Страница обратной связи<


Если вы используете это впервые, рекомендуется перейти к Странице подробностей , чтобы посмотреть введение в скрипт.

', setting_language: 'Язык', setting_preview: 'Предпросмотр', setting_sort: 'Сортировка (Страница поиска)', setting_anime: 'Анимация скачивания (Страницы предпросмотра и Artwork)', setting_origin: 'При предпросмотре, показывать изображения с оригинальным качеством (медленно)', setting_previewDelay: 'Задержка отображения предпросмотра изображения (Миллион секунд)', setting_maxPage: 'Максимальное количество страниц, подсчитанных за сортировку', setting_hideWork: 'Скрыть работы с количеством закладок меньше установленного значения', setting_hideFav: 'При сортировке, скрыть избранное', setting_hideFollowed: 'При сортировке, скрыть работы художников на которых подписаны', setting_clearFollowingCache: 'Кэш', setting_clearFollowingCacheHelp: 'Следующая информация о художниках будет сохранена локально в течение одного дня, если вы хотите обновить её немедленно, нажмите на эту кнопку, чтобы очистить кэш', setting_followingCacheCleared: 'Готово, обновите страницу.', setting_blank: 'Открывать страницу с описанием работы на новой вкладке', setting_turnPage: 'Использовать ← → для перелистывания страниц (Страница поиска)', setting_save: 'Сохранить', setting_reset: 'Сбросить', setting_resetHint: 'Это удалит все настройки и установит их по умолчанию. Продолжить?', setting_novelSort: Texts[Lang.en_US].setting_novelSort, setting_novelMaxPage: Texts[Lang.en_US].setting_novelMaxPage, sort_noWork: 'Нет работ для отображения', sort_getWorks: 'Получение иллюстраций страницы: %1 из %2', sort_getBookmarkCount: 'Получение количества закладок artworks:%1 из %2', sort_getPublicFollowing: 'Получение публичного списка подписок', sort_getPrivateFollowing: 'Получение приватного списка подписок', sort_filtering: 'Фильтрация %1 работ с количеством закладок меньше чем %2', sort_filteringHideFavorite: ' избранные работы и ', sort_fullSizeThumb: 'Показать неотредактированное изображение', nsort_getWorks: Texts[Lang.en_US].nsort_getWorks, nsort_sorting: Texts[Lang.en_US].nsort_sorting, nsort_hideFav: Texts[Lang.en_US].nsort_hideFav, nsort_hideFollowed: Texts[Lang.en_US].nsort_hideFollowed }; let LogLevel = { None: 0, Error: 1, Warning: 2, Info: 3, Elements: 4, }; function DoLog(level, msgOrElement) { if (level <= g_logLevel) { let prefix = '%c'; let param = ''; if (level == LogLevel.Error) { prefix += '[Error]'; param = 'color:#ff0000'; } else if (level == LogLevel.Warning) { prefix += '[Warning]'; param = 'color:#ffa500'; } else if (level == LogLevel.Info) { prefix += '[Info]'; param = 'color:#000000'; } else if (level == LogLevel.Elements) { prefix += 'Elements'; param = 'color:#000000'; } if (level != LogLevel.Elements) { console.log(prefix + msgOrElement, param); } else { console.log(msgOrElement); } if (++g_logCount > 512) { //console.clear(); g_logCount = 0; } } } // 语言 let g_language = Lang.zh_CN; // 版本号,第三位不需要跟脚本的版本号对上,第三位更新只有需要弹更新提示的时候才需要更新这里 let g_version = '3.6.0'; // 添加收藏需要这个 let g_csrfToken = ''; // 打的日志数量,超过一定数值清空控制台 let g_logCount = 0; // 当前页面类型 let g_pageType = -1; // 图片详情页的链接,使用时替换 #id# let g_artworkUrl = '/artworks/#id#'; // 获取图片链接的链接 let g_getArtworkUrl = '/ajax/illust/#id#/pages'; // 获取动图下载链接的链接 let g_getUgoiraUrl = '/ajax/illust/#id#/ugoira_meta'; // 获取小说列表的链接 let g_getNovelUrl = '/ajax/search/novels/#key#?word=#key#&p=#page#' // 鼠标位置 let g_mousePos = { x: 0, y: 0 }; // 加载中图片 let g_loadingImage = 'https://pp-1252089172.cos.ap-chengdu.myqcloud.com/loading.gif'; // 页面打开时的 url let initialUrl = location.href; // 默认设置,仅用于首次脚本初始化 let g_defaultSettings = { 'lang': -1, 'enablePreview': 1, 'enableSort': 1, 'enableAnimeDownload': 1, 'original': 0, 'previewDelay': 200, 'pageCount': 3, 'favFilter': 0, 'hideFavorite': 0, 'hideFollowed': 0, 'linkBlank': 1, 'pageByKey': 0, 'fullSizeThumb': 0, 'enableNovelSort': 1, 'novelPageCount': 3, 'novelHideFavorite': 0, 'novelHideFollowed': 0, 'logLevel': 1, 'version': g_version, }; // 设置 let g_settings; // 日志等级 let g_logLevel = LogLevel.Error; // 排序时同时请求收藏量的 Request 数量,没必要太多,并不会加快速度 let g_maxXhr = 64; // 排序是否完成(如果排序时页面出现了非刷新切换,强制刷新) let g_sortComplete = true; // 页面相关的一些预定义,包括处理页面元素等 let PageType = { // 搜索(不包含小说搜索) Search: 0, // 关注的新作品 BookMarkNew: 1, // 发现 Discovery: 2, // 用户主页 Member: 3, // 首页 Home: 4, // 排行榜 Ranking: 5, // 大家的新作品 NewIllust: 6, // R18 R18: 7, // 自己的收藏页 BookMark: 8, // 动态 Stacc: 9, // 作品详情页(处理动图预览及下载) Artwork: 10, // 小说页 NovelSearch: 11, // 总数 PageTypeCount: 12, }; let Pages = {}; /* Pages 必须实现的函数 * PageTypeString: string,字符串形式的 PageType * bool CheckUrl: function(string url),用于检查一个 url 是否是当前页面的目标 url * ReturnMap ProcessPageElements: function(),处理页面(寻找图片元素、添加属性等),返回 ReturnMap * ReturnMap GetProcessedPageElements: function(), 返回上一次 ProcessPageElements 的返回值(如果没有上次调用则调用一次) * Object GetToolBar: function(), 返回工具栏元素(右下角那个,用来放设置按钮) * HasAutoLoad: bool,表示这个页面是否有自动加载功能 */ let ReturnMapSample = { // 页面是否加载完成,false 意味着后面的成员无效 loadingComplete: false, // 控制元素,每个图片的鼠标响应元素 controlElements: [], // 可有可无,如果为 true,强制重新刷新预览功能 forceUpdate: false, }; let ControlElementsAttributesSample = { // 图片信息,内容如下: // [必需] 图片 id illustId: 0, // [必需] 图片类型(0:普通图片,2:动图) illustType: 0, // [必需] 页数 pageCount: 1, // [可选] 标题 title: '', // [可选] 作者 id userId: 0, // [可选] 作者昵称 userName: '', // [可选] 收藏数 bookmarkCount: 0, }; function findToolbarCommon() { // 目前第三级div,除了目标div外,子元素都是div return $('#root>div>div>ul').get(0); } function findToolbarOld() { return $('._toolmenu').get(0); } function convertThumbUrlToSmall(thumbUrl) { // 目前发现有以下两种格式的缩略图 // https://i.pximg.net/c/128x128/custom-thumb/img/2021/01/31/20/35/53/87426718_p0_custom1200.jpg // https://i.pximg.net/c/128x128/img-master/img/2021/01/31/10/57/06/87425082_p0_square1200.jpg let replace1 = 'c/540x540_70/img-master'; //let replace1 = 'img-master'; // 这个是转到regular的,比small的大多了,会很慢 let replace2 = '_master'; return thumbUrl.replace(/c\/.*\/custom-thumb/, replace1).replace('_custom', replace2) .replace(/c\/.*\/img-master/, replace1).replace('_square', replace2); } function processElementListCommon(lis) { lis.each(function (i, e) { let li = $(e); // 只填充必须的几个,其他的目前用不着 let ctlAttrs = { illustId: 0, illustType: 0, pageCount: 1, }; let img = $(li.find('img').get(0)); let imageLink = img.parent().parent(); let additionDiv = img.parent().prev(); let animationSvg = img.parent().find('svg'); let pageCountSpan = additionDiv.find('span'); if (img == null || imageLink == null) { DoLog(LogLevel.Warning, 'Can not found img or imageLink, skip this.'); return; } let link = imageLink.attr('href'); if (link == null) { DoLog(LogLevel.Warning, 'Invalid href, skip this.'); return; } let linkMatched = link.match(/artworks\/(\d+)/); let illustId = ''; if (linkMatched) { ctlAttrs.illustId = linkMatched[1]; } else { DoLog(LogLevel.Error, 'Get illustId failed, skip this list item!'); return; } if (animationSvg.length > 0) { ctlAttrs.illustType = 2; } if (pageCountSpan.length > 0) { ctlAttrs.pageCount = parseInt(pageCountSpan.text()); } // 添加 attr let control = li.children('div:first').children('div:first'); control.attr({ 'illustId': ctlAttrs.illustId, 'illustType': ctlAttrs.illustType, 'pageCount': ctlAttrs.pageCount }); control.addClass('pp-control'); }); } Pages[PageType.Search] = { PageTypeString: 'SearchPage', CheckUrl: function (url) { // 没有 /artworks 的页面不支持 return /^https?:\/\/www.pixiv.net\/tags\/.*\/(artworks|illustrations|manga)/.test(url) || /^https?:\/\/www.pixiv.net\/en\/tags\/.*\/(artworks|illustrations|manga)/.test(url); }, ProcessPageElements: function () { let returnMap = { loadingComplete: false, controlElements: [], }; let sections = $('section'); DoLog(LogLevel.Info, 'Page has ' + sections.length + '
.'); DoLog(LogLevel.Elements, sections); // 先对 section 进行评分 let sectionIndex = -1; let bestScore = -99; sections.each(function (i, e) { let section = $(e); let score = 0; if (section.find('ul').length > 0) { let childrenCount = section.children().length; if (childrenCount != 2) { DoLog(LogLevel.Warning, '