// ==UserScript== // @name Patchouli // @name:ja パチュリー // @name:zh-CN 帕秋莉 // @name:zh-TW 帕秋莉 // @namespace https://github.com/FlandreDaisuki // @description An image searching/browsing tool on Pixiv // @description:ja Pixiv 検索機能強化 // @description:zh-CN Pixiv 搜寻/浏览 工具 // @description:zh-TW Pixiv 搜尋/瀏覽 工具 // @include *://www.pixiv.net/* // @require https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.1/axios.min.js // @icon http://i.imgur.com/VwoYc5w.png // @noframes // @author FlandreDaisuki // @license The MIT License (MIT) Copyright (c) 2016-2017 FlandreDaisuki // @compatible firefox >=52 // @compatible chrome >=55 // @version 3.0.3 // @grant none // @downloadURL none // ==/UserScript== (function () { 'use strict'; function __$styleInject( css ) { if(!css) return ; if(typeof(window) == 'undefined') return ; let style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); return css; } const _msg_following = "following"; const _msg_bookmark_tooltip = "$bookmark_count$ bookmarks"; const _msg_koakuma_processed = "$processed_count$ pics processed"; const _msg_koakuma_go = "Go"; const _msg_koakuma_pause = "Pause"; const _msg_koakuma_end = "End"; const _msg_fit_browser_width = "fit browser width"; const _msg_sort_by_bookmark_count = "sort by bookmark count"; const _msg_tag_filter_placeholder = "tag filter e.g.: flandre|sister"; var en = { _msg_following: _msg_following, _msg_bookmark_tooltip: _msg_bookmark_tooltip, _msg_koakuma_processed: _msg_koakuma_processed, _msg_koakuma_go: _msg_koakuma_go, _msg_koakuma_pause: _msg_koakuma_pause, _msg_koakuma_end: _msg_koakuma_end, _msg_fit_browser_width: _msg_fit_browser_width, _msg_sort_by_bookmark_count: _msg_sort_by_bookmark_count, _msg_tag_filter_placeholder: _msg_tag_filter_placeholder }; const _msg_following$1 = "フォロー中"; const _msg_bookmark_tooltip$1 = "$bookmark_count$件のブックマーク"; const _msg_koakuma_processed$1 = "$processed_count$ 件が処理された"; const _msg_koakuma_go$1 = "捜す"; const _msg_koakuma_pause$1 = "中断"; const _msg_koakuma_end$1 = "終了"; const _msg_fit_browser_width$1 = "全幅"; const _msg_sort_by_bookmark_count$1 = "ブックマーク数順"; const _msg_tag_filter_placeholder$1 = "タグフィルター 例: フランドール|妹様"; var ja = { _msg_following: _msg_following$1, _msg_bookmark_tooltip: _msg_bookmark_tooltip$1, _msg_koakuma_processed: _msg_koakuma_processed$1, _msg_koakuma_go: _msg_koakuma_go$1, _msg_koakuma_pause: _msg_koakuma_pause$1, _msg_koakuma_end: _msg_koakuma_end$1, _msg_fit_browser_width: _msg_fit_browser_width$1, _msg_sort_by_bookmark_count: _msg_sort_by_bookmark_count$1, _msg_tag_filter_placeholder: _msg_tag_filter_placeholder$1 }; const _msg_following$2 = "关注中"; const _msg_bookmark_tooltip$2 = "$bookmark_count$个收藏"; const _msg_koakuma_processed$2 = "已处理 $processed_count$ 张"; const _msg_koakuma_go$2 = "找"; const _msg_koakuma_pause$2 = "停"; const _msg_koakuma_end$2 = "完"; const _msg_fit_browser_width$2 = "自适应浏览器宽度"; const _msg_sort_by_bookmark_count$2 = "书签数排序"; const _msg_tag_filter_placeholder$2 = "标签过滤 例: 芙兰朵露|二小姐"; var zh = { _msg_following: _msg_following$2, _msg_bookmark_tooltip: _msg_bookmark_tooltip$2, _msg_koakuma_processed: _msg_koakuma_processed$2, _msg_koakuma_go: _msg_koakuma_go$2, _msg_koakuma_pause: _msg_koakuma_pause$2, _msg_koakuma_end: _msg_koakuma_end$2, _msg_fit_browser_width: _msg_fit_browser_width$2, _msg_sort_by_bookmark_count: _msg_sort_by_bookmark_count$2, _msg_tag_filter_placeholder: _msg_tag_filter_placeholder$2 }; const _msg_following$3 = "關注中"; const _msg_bookmark_tooltip$3 = "$bookmark_count$個收藏"; const _msg_koakuma_processed$3 = "已處理 $processed_count$ 張"; const _msg_koakuma_go$3 = "找"; const _msg_koakuma_pause$3 = "停"; const _msg_koakuma_end$3 = "完"; const _msg_fit_browser_width$3 = "自適應瀏覽器寬度"; const _msg_sort_by_bookmark_count$3 = "書籤數排序"; const _msg_tag_filter_placeholder$3 = "標籤過濾 例: 芙蘭朵露|二小姐"; var tw = { _msg_following: _msg_following$3, _msg_bookmark_tooltip: _msg_bookmark_tooltip$3, _msg_koakuma_processed: _msg_koakuma_processed$3, _msg_koakuma_go: _msg_koakuma_go$3, _msg_koakuma_pause: _msg_koakuma_pause$3, _msg_koakuma_end: _msg_koakuma_end$3, _msg_fit_browser_width: _msg_fit_browser_width$3, _msg_sort_by_bookmark_count: _msg_sort_by_bookmark_count$3, _msg_tag_filter_placeholder: _msg_tag_filter_placeholder$3 }; class L10N { constructor() { this.dict = {en, ja, zh, tw}; this.lang = document.documentElement.lang; if (this.lang === 'zh-tw') { this.lang = 'tw'; } if (!this.dict[this.lang]) { this.lang = 'en'; } } get following() { return this.dict[this.lang]['_msg_following']; } bookmarkTooltip(n) { return this.dict[this.lang]['_msg_bookmark_tooltip'].replace('$bookmark_count$', n); } koakumaProcessed(n) { return this.dict[this.lang]['_msg_koakuma_processed'].replace('$processed_count$', n); } get koakumaGo() { return this.dict[this.lang]['_msg_koakuma_go']; } get koakumaPause() { return this.dict[this.lang]['_msg_koakuma_pause']; } get koakumaEnd() { return this.dict[this.lang]['_msg_koakuma_end']; } get fitBrowserWidth() { return this.dict[this.lang]['_msg_fit_browser_width']; } get sortByBookmarkCount() { return this.dict[this.lang]['_msg_sort_by_bookmark_count']; } get tagFilterPlaceholder() { return this.dict[this.lang]['_msg_tag_filter_placeholder']; } } function $(selector) { return document.querySelector(selector); } function $$(selector) { return [...document.querySelectorAll(selector)]; } function $$find(doc, selector) { return [...doc.querySelectorAll(selector)]; } function $el(tag, attr = {}, cb = () => {}) { const el = document.createElement(tag); Object.assign(el, attr); cb(el); return el; } function $log(...args) { console.log.apply(console, args); } function $error(...args) { console.error.apply(console, args); } (() => { Math.clamp = (val, min, max) => Math.min(Math.max(min, val), max); Number.toInt = (s) => (isNaN(~~s) ? 0 : ~~s); (function (arr) { arr.forEach(function (item) { if (item.hasOwnProperty('after')) { return; } Object.defineProperty(item, 'after', { configurable: true, enumerable: true, writable: true, value: function after() { var argArr = Array.prototype.slice.call(arguments), docFrag = document.createDocumentFragment(); argArr.forEach(function (argItem) { var isNode = argItem instanceof Node; docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem))); }); this.parentNode.insertBefore(docFrag, this.nextSibling); } }); }); })([Element.prototype, CharacterData.prototype, DocumentType.prototype]); })(); class Pixiv { constructor() { this.tt = $('input[name="tt"]').value; } async fetch(url) { try { if (url) { const res = await axios.get(url); if (res.statusText !== 'OK') { throw new Error(res.statusText); } else { return res.data; } } else { $error('Pixiv#fetch has no url'); } } catch (error) { $error(error); } } async getLegacyPageHTMLIllustIds(url, options = {}) { const opt = Object.assign({ needBookmarkId: false }, options); try { const html = await this.fetch(url); const next_tag = html.match(/class="next"[^\/]*/); let next_url = ''; if (next_tag) { const next_href = next_tag[0].match(/href="([^"]+)"/); if (next_href) { const query = next_href[1].replace(/&/g, '&'); if (query) { next_url = `${location.pathname}${query}`; } } } const iidHTMLs = html.match(/;illust_id=\d+"\s*class="work/g) || []; const illust_ids = []; for (const dataid of iidHTMLs) { const iid = dataid.replace(/\D+(\d+).*/, '$1'); if (!illust_ids.includes(iid) && iid !== '0') { illust_ids.push(iid); } } const ret = { next_url, illust_ids }; if (opt.needBookmarkId) { ret.bookmark_ids = {}; const bimHTMLs = html.match(/name="book_id[^;]+;illust_id=\d+/g) || []; for (const bim of bimHTMLs) { const [illust_id, bookmark_id] = bim.replace(/\D+(\d+)\D+(\d+)/, '$2 $1').split(' '); if (illust_ids.includes(illust_id)) { ret.bookmark_ids[illust_id] = {illust_id, bookmark_id}; } } } return ret; } catch (e) { $error(e); } } async getPageHTMLIllustIds(url) { try { const html = await this.fetch(url); const next_tag = html.match(/class="next"[^\/]*/); let next_url = ''; if (next_tag) { const next_href = next_tag[0].match(/href="([^"]+)"/); if (next_href) { const query = next_href[1].replace(/&/g, '&'); if (query) { next_url = `${location.pathname}${query}`; } } } const iidHTMLs = html.match(/illustId":"(\d+)"/g) || []; const illust_ids = []; for (const dataid of iidHTMLs) { const iid = dataid.replace(/\D+(\d+).*/, '$1'); if (!illust_ids.includes(iid) && iid !== '0') { illust_ids.push(iid); } } const ret = { next_url, illust_ids }; return ret; } catch (error) { $error(error); } } async getBookmarkHTMLDetail(illust_id) { const url = `/bookmark_detail.php?illust_id=${illust_id}`; try { const html = await this.fetch(url); const _a = html.match(/sprites-bookmark-badge[^\d]+(\d+)/); const bookmark_count = _a ? parseInt(_a[1]) : 0; const _b = html.match(/