// ==UserScript== // @name Patchouli // @name:ja パチュリー // @name:zh-TW 帕秋莉 // @name:zh-CN 帕秋莉 // @description An image searching/browsing tool on Pixiv // @description:ja Pixiv 検索機能強化 // @description:zh-TW Pixiv 搜尋/瀏覽 工具 // @description:zh-CN Pixiv 搜尋/瀏覽 工具 // @namespace https://github.com/FlandreDaisuki // @include *://www.pixiv.net/* // @require https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.min.js // @version 2017.08.18 // @icon http://i.imgur.com/VwoYc5w.png // @grant none // @noframes // // Meta keys for Greasy Fork // @author FlandreDaisuki // @license The MIT License (MIT) Copyright (c) 2016-2017 FlandreDaisuki // @compatible firefox 52+ // @compatible chrome 55+ // @downloadURL none // ==/UserScript== 'use strict'; console.log(`[${GM_info.script.name}] version: ${GM_info.script.version}`); class L10N { constructor() { this.lang = document.documentElement.lang; this.following = this._following(); this.bookmark = this._bookmark(); this.tag = this._tag(); this.koakumaGo = this._koakumaGo(); this.koakumaPause = this._koakumaPause(); this.koakumaEnd = this._koakumaEnd(); this.koakumaFullwidth = this._koakumaFullwidth(); this.koakumaSort = this._koakumaSort(); } _following() { switch (this.lang) { case 'ja': return 'フォロー中'; case 'zh-tw': return '關注中'; case 'zh': return '关注中'; default: return 'following'; } } _bookmark() { switch (this.lang) { case 'ja': return 'ブックマーク'; case 'zh-tw': case 'zh': return '收藏'; default: return 'Bookmark'; } } _tag() { switch (this.lang) { case 'ja': return 'タグフィルター'; case 'zh-tw': return '標籤過濾器'; case 'zh': return '标签过滤器'; default: return 'Tag filter'; } } _koakumaGo() { switch (this.lang) { case 'ja': return '捜す'; case 'zh-tw': case 'zh': return '找'; default: return 'Go'; } } _koakumaPause() { switch (this.lang) { case 'ja': return '中断'; case 'zh-tw': case 'zh': return '停'; default: return 'Pause'; } } _koakumaEnd() { switch (this.lang) { case 'ja': return '終了'; case 'zh-tw': case 'zh': return '完'; default: return 'End'; } } koakumaProcessed(n) { switch (this.lang) { case 'ja': return `${n} 件が処理された`; case 'zh-tw': return `已處理 ${n} 張`; case 'zh': return `已处理 ${n} 张`; default: return `${n} pics processed`; } } _koakumaFullwidth() { switch (this.lang) { case 'ja': return '全幅'; case 'zh-tw': return '全寬'; case 'zh': return '全宽'; default: return 'fullwidth'; } } _koakumaSort() { switch (this.lang) { case 'ja': return 'ソート'; case 'zh-tw': case 'zh': return '排序'; default: return 'sorted'; } } bookmarkTooltip(n) { switch (this.lang) { case 'ja': return `${n}件のブックマーク`; case 'zh-tw': return `${n}個收藏`; case 'zh': return `${n}个收藏`; default: return `${n} bookmarks`; } } } class PageType { constructor() { const path = location.pathname; const search = new URLSearchParams(location.search); const hasid = search.has('id'); this.DEFAULT = false; this.RECOMMEND = false; this.MEMBERILLIST = false; this.MYBOOKMARK = false; this.NOSUP = false; switch (path) { case '/search.php': case '/bookmark_new_illust.php': case '/new_illust.php': case '/mypixiv_new_illust.php': case '/new_illust_r18.php': case '/bookmark_new_illust_r18.php': this.DEFAULT = true; break; case '/recommended.php': this.RECOMMEND = true; break; case '/member_illust.php': this.MEMBERILLIST = hasid; this.NOSUP = !hasid; break; case '/bookmark.php': const t = search.get('type'); if (hasid) { this.DEFAULT = true; } else if (!t || t === 'illust_all') { this.MYBOOKMARK = true; } else { // e.g. http://www.pixiv.net/bookmark.php?type=reg_user this.NOSUP = true; } break; default: this.NOSUP = true; } } } class Pixiv { constructor() { this.tt = document.querySelector('input[name="tt"]').value; } static storageGet() { const storage = localStorage.getItem('むきゅー'); if (!storage || storage.version < GM_info.script.version) { Pixiv.storageSet({ version: GM_info.script.version, }); } return JSON.parse(localStorage.getItem('むきゅー')); } static storageSet(obj) { localStorage.setItem('むきゅー', JSON.stringify(obj)); } static rmAnnoyance(doc = document) { [ 'iframe', //Ad '.ad', '.ads_area', '.ad-footer', '.ads_anchor', '.ads-top-info', '.comic-hot-works', '.user-ad-container', '.ads_area_no_margin', //Premium '.hover-item', '.ad-printservice', '.bookmark-ranges', '.require-premium', '.showcase-reminder', '.sample-user-search', '.popular-introduction', ].forEach(cl => [...doc.querySelectorAll(cl)].forEach(el => el.remove())); } async fetch(url) { try { if (url) { const res = await axios.get(url); if (res.statusText !== 'OK') { throw res; } else { return res.data; } } else { console.trace('Fetch has no url'); } } catch (e) { console.error(e); } } async getDetail(illust_ids, f) { const iids = []; for (let iid of illust_ids) { iids.push(f(iid)); } const processed = await Promise.all(iids); const ret = {}; for (let p of processed) { ret[p.illust_id] = p; } return ret; } async getBookmarkCountAndTags(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(/