// ==UserScript== // @name Patchouli // @description An image searching/browsing tool on Pixiv // @namespace https://github.com/FlandreDaisuki // @include http://www.pixiv.net/* // @require https://cdnjs.cloudflare.com/ajax/libs/URI.js/1.18.1/URI.min.js // @version 2016.09.02 // @author FlandreDaisuki // @grant none // @noframes // @downloadURL none // ==/UserScript== /* jshint esnext: true */ const baseURI = document.baseURI; console.log('jQuery version:', $.fn.jquery); console.log('URI version:', URI.version); console.log('baseURI:', baseURI); function getBaseInfo() { const retval = { supported: true, imgitemConf: { selector: 'li.image-item', hasAuthor: true, hasBookmark: false, needFillwidth: true, }, }; retval.$container = $(retval.imgitemConf.selector).parent(); const pbu = new URI(baseURI); const pn = pbu.pathname(); const ss = URI.parseQuery(pbu.query()); if (pn === '/member_illust.php' && ss.id) { //作品一覧 retval.imgitemConf.hasAuthor = false; retval.imgitemConf.needFillwidth = false; } else if (pn === '/search.php') { //作品の検索 retval.imgitemConf.hasBookmark = true; } else if (pn === '/bookmark.php' && !ss.type) { //ブックマーク retval.imgitemConf.hasBookmark = true; retval.imgitemConf.needFillwidth = false; } else if (pn === '/bookmark_new_illust.php') { //フォロー新着作品 } else if (pn === '/new_illust.php') { //みんなの新着作品 } else if (pn === '/mypixiv_new_illust.php') { //マイピク新着イラスト } else if (pn === '/new_illust_r18.php') { //みんなのR-18新着作品 } else if (pn === '/bookmark_new_illust_r18.php') { //フォローユーザーR-18新着イラスト } else { //Not Support Pages retval.supported = false; } return retval; } function removeJama($doc = $(document)) { [ 'iframe', //Ad '.ad', '.ads_area', '.ad-footer', '.ads_anchor', '.comic-hot-works', '.user-ad-container', '.ads_area_no_margin', //Premium '.ad-printservice', '.bookmark-ranges', '.require-premium', '.showcase-reminder', '.sample-user-search', '.popular-introduction', ].forEach((e) => { $doc.find(e).remove(); }); } function getThumbPageInfo(tpageURI) { // complete URI String return fetch(tpageURI, { credentials: 'same-origin' // with cookies }) .then(response => response.text()) .then(html => new DOMParser().parseFromString(html, 'text/html')) .then(doc => $(doc)) .then(($doc) => { removeJama($doc); const tpage = {}; tpage.followed = $doc.find('#favorite-button').hasClass('following'); tpage.tags = $doc.find('li.tag .text').toArray().map(e => e.innerText); tpage.type = (function($wd) { if ($wd.find('._work.multiple').length > 0) { return 'manga'; } else if ($wd.find('._ugoku-illust-player-container').length > 0) { return 'ugoira'; } else { return 'illust'; } })($doc.find('.works_display')); tpage.rating = ~~$doc.find('dd.score-count').text(); return tpage; }) .catch((err) => { console.error(err); }); } // Class Thumb function Thumb(imgitem) { const workURI = new URI(imgitem.querySelector('a.work').getAttribute('href')); const bk = imgitem.querySelector('.bookmark-count'); this.elem = imgitem; this.elem.removeAttribute('style'); this.URI = workURI.absoluteTo(baseURI); this.workId = URI.parseQuery(this.URI.query()).illust_id; this.autherId = Patchouli.conf.hasAuthor ? imgitem.querySelector('.user').dataset.user_id : null; this.bookmark = bk ? ~~bk.innerText : 0; this.hide = false; } //Main Class const Patchouli = { init: function() { this.Tbooks = []; const BI = getBaseInfo(); this.conf = BI.imgitemConf; this.supported = BI.supported; this.$container = BI.$container; this.koakuma = { ratingStep: 1000, bookmarkStep: 50, keywords: '', rating: 0, bookmark: 0, autosort: false, markfollowed: true, }; this.intervalFetcherId = null; console.log('Patchouli', this); }, getPageInfo: function(pageURI) { // complete URI String console.log(URI.decode(pageURI)); return new Promise((resolve, reject) => { if (pageURI) { resolve(); } else { reject('pageURI is null'); } }) .then(() => { return fetch(pageURI.toString(), { credentials: 'same-origin' // with cookies }) .then(response => response.text()) .then(html => new DOMParser().parseFromString(html, 'text/html')) .then(doc => $(doc)); }) .then(($doc) => { removeJama($doc); const page = {}; page.URI = pageURI; const next = $doc.find('.next a').attr('href'); page.nextURI = (next) ? new URI(baseURI).query(next).toString() : null; page.thumbs = $doc.find(this.conf.selector) .toArray() .filter((elem) => elem.querySelector('a.work')) .map((elem) => new Thumb(elem)) .filter((elem) => { // Pixiv inner error, like image been deleted return elem.workId; }); return page; }) .then((page) => { // valid imgitems let innerp = page.thumbs.map((thumb) => { return Promise.resolve(getThumbPageInfo(thumb.URI)) .then((tpi)=> { for(let k in tpi) { thumb[k] = tpi[k]; } return thumb; }); }); return Promise.all(innerp).then(() => { return page; }); }) .catch((err) => { console.error(err); }); }, pageGenerator: function* () { let next = baseURI; while(true) { next = yield this.getPageInfo(next) .then((p)=> { const filtered = this.koakumaFilter(p.thumbs); [].push.apply(this.Tbooks, filtered); filtered.forEach((e) => { //append elem reference, Do NOT use jQuery this.$container[0].appendChild(e.elem); }); $('#Koakuma-processed').text(this.Tbooks.length); return p.nextURI; }).catch((err) => { console.log(err); }); } }, koakumaFilter: function(thumbs) { if (this.koakuma.keywords) { const kw = this.koakuma.keywords; thumbs.forEach(e => { e.hide = true; for(let t of e.tags) { if(kw.indexOf(t) >= 0) { e.hide = false; break; } } }); } else { thumbs.forEach(e => e.hide = false); } thumbs.forEach(e => e.hide = e.hide || e.rating < this.koakuma.rating); thumbs.forEach(e => e.hide = e.hide || e.bookmark < this.koakuma.bookmark); thumbs.forEach(e => { if (e.hide) { e.elem.classList.add('filter-hidden'); } else { e.elem.classList.remove('filter-hidden'); } e.elem.style.order = (this.koakuma.autosort) ? -e.bookmark : 0; if(this.conf.hasAuthor && this.koakuma.markfollowed && e.followed) { e.elem.querySelector('a.user').style.color = 'red'; } }); return thumbs; } }; function setupHTML() { $(`
已處理 0
標籤過濾:
★評分0 以上
★書籤0 以上
標示已追蹤
滿版頁寬
書籤排序
`).appendTo('body'); $(` `).appendTo('head'); Patchouli.$container.children().remove(); Patchouli.$container.addClass('Tbooks-container'); } function setupEvent() { $('#Koakuma-config-box').hide(); $('#Koakuma-stop').hide(); if (!Patchouli.conf.hasAuthor) { $('#Koakuma-config-markfollowed').parent().remove(); } else { $('#Koakuma-config-markfollowed').attr('checked', true); } if (!Patchouli.conf.hasBookmark) { $('#Koakuma-config-autosort').parent().remove(); $('#Koakuma-main-box > .bookmark').remove(); } if (!Patchouli.conf.needFillwidth) { $('#Koakuma-config-fillwidth').parent().remove(); } $('#Koakuma-processed-box').on('click', function(event) { $('#Koakuma-main-box').toggle(300); $('#Koakuma-config-box').hide(300); }); $('#Koakuma-config').on('click', function(event) { $('#Koakuma-config-box').toggle(300); }); $('#Koakuma-rating').on('click', function(event) { if (!Patchouli.intervalFetcherId) { $('#Koakuma-rating').toggleClass('filter-editing'); } $('#Koakuma-bookmark').removeClass('filter-editing'); }); $('#Koakuma-bookmark').on('click', function(event) { if (!Patchouli.intervalFetcherId) { $('#Koakuma-bookmark').toggleClass('filter-editing'); } $('#Koakuma-rating').removeClass('filter-editing'); }); $('#Koakuma-stop').on('click', function(event) { $('#Koakuma-stop').hide(); $('#Koakuma-fetcher').show(); $('#Koakuma-main-box > div:not(.func)').show(); clearInterval(Patchouli.intervalFetcherId); Patchouli.intervalFetcherId = null; }); $('#Koakuma-fetcher').on('click', function(event) { $('#Koakuma-fetcher').hide(); $('#Koakuma-stop').show(); $('.filter-editing').removeClass('filter-editing'); $('#Koakuma-main-box > div:not(.func)').hide(); $('#Koakuma-config-box').hide(); Patchouli.koakuma.keywords = $('#Koakuma-keyword').val(); Patchouli.koakumaFilter(Patchouli.Tbooks); Patchouli.intervalFetcherId = setInterval(function() { Patchouli.np = Patchouli.np.then((n) => Patchouli.page.next(n).value); }, 1000); }); $('#Koakuma-config-markfollowed').on('click', function(event) { if (event.target.checked) { Patchouli.koakuma.markfollowed = true; Patchouli.Tbooks.forEach((e) => { if (e.followed) { e.elem.querySelector('a.user').style.color = 'red'; } }); } else { Patchouli.koakuma.markfollowed = false; Patchouli.Tbooks.forEach((e) => { e.elem.querySelector('a.user').style.color = ''; }); } }); $('#Koakuma-config-autosort').on('click', function(event) { if (event.target.checked) { Patchouli.koakuma.autosort = true; } else { Patchouli.koakuma.autosort = false; } }); $('#Koakuma-config-fillwidth').on('click', function(event) { if (event.target.checked) { $('.layout-body').addClass('fillwidth'); } else { $('.layout-body').removeClass('fillwidth'); } }); $('#Koakuma').on('wheel', function(event) { const t = event.originalEvent.deltaY < 0 ? 1 : -1; const fe = $('.filter-editing'); if(fe.length > 0) { const feid = fe[0].id; if (feid === 'Koakuma-rating') { const tt = Patchouli.koakuma.ratingStep * t; fe.text(Math.max(0, ~~fe.text() + tt)); Patchouli.koakuma.rating = ~~fe.text(); } else if (feid === 'Koakuma-bookmark') { const tt = Patchouli.koakuma.bookmarkStep * t; fe.text(Math.max(0, ~~fe.text() + tt)); Patchouli.koakuma.bookmark = ~~fe.text(); } else { console.log(feid); } } else { return; } }); } //for debugging // window.Patchouli = Patchouli; // window.URI = URI; // Program Entry Point Patchouli.init(); removeJama(); if (Patchouli.supported) { setupHTML(); setupEvent(); Patchouli.page = Patchouli.pageGenerator(); Patchouli.np = Patchouli.page.next().value; }