// ==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/vue/1.0.25/vue.js
// @require https://cdnjs.cloudflare.com/ajax/libs/URI.js/1.18.1/URI.min.js
// @version 2017.02.06
// @author FlandreDaisuki
// @grant none
// @noframes
// @downloadURL none
// ==/UserScript==
/* jshint esnext: true */
function fetchWithcookie(url) {
return fetch(url, {credentials: 'same-origin'})
.then(response => response.text())
.catch(err => { console.error(err); });
}
function getBookmarkCountAndTags(illust_id) {
const url = `http://www.pixiv.net/bookmark_detail.php?illust_id=${illust_id}`;
return fetchWithcookie(url)
.then(html => parseToDOM(html))
.then(doc => $(doc))
.then($doc => {
let m = $doc.find('a.bookmark-count').text();
const bookmark_count = m ? parseInt(m) : 0;
const tags = Array.from($doc.find('ul.tags:first a')).map(x => x.innerText);
return {
bookmark_count,
illust_id,
tags,
};
})
.catch(err => { console.error(err); });
}
function getBatch(url) {
return fetchWithcookie(url)
.then(html => parseToDOM(html))
.then(doc => $(doc))
.then($doc => {
removeAnnoyance($doc);
const next = $doc.find('.next a').attr('href');
const nextLink = (next) ? new URI(BASE.baseURI).query(next).toString() : null;
const illust_ids = $doc
.find('li.image-item > a.work')
.toArray()
.map(x => URI.parseQuery($(x).attr('href')).illust_id);
return {
nextLink,
illust_ids,
};
})
.catch(err => { console.error(err); });
}
/**
* return object which key is illust_id
*/
function getIllustsDetails(illust_ids) {
const api = `http://www.pixiv.net/rpc/index.php?mode=get_illust_detail_by_ids&illust_ids=${illust_ids.join(',')}&tt=${BASE.tt}`;
return fetchWithcookie(api).then(json => JSON.parse(json).body).catch(err => { console.error(err); });
}
/**
* return an array
*/
function getUsersDetails(user_ids) {
const api = `http://www.pixiv.net/rpc/get_profile.php?user_ids=${user_ids.join(',')}&tt=${BASE.tt}`;
return fetchWithcookie(api).then(json => JSON.parse(json).body).catch(err => { console.error(err); });
}
function parseDataFromBatch(batch) {
const illust_d = batch.illust_d;
const user_d = batch.user_d;
const bookmark_d = batch.bookmark_d;
return batch.illust_ids
.filter(x => x)
.map(x => {
const iinfo = illust_d[x];
const uinfo = user_d[iinfo.user_id];
const binfo = bookmark_d[x];
const is_ugoira = iinfo.illust_type === '2';
const is_manga = iinfo.illust_type === '1';
const src150 = (is_ugoira) ?
iinfo.url.big.replace(/([^-]+)(?:-original)([^_]+)(?:[^\.]+)(.+)/,'$1-inf$2_s$3') :
iinfo.url.m.replace(/600x600/,'150x150');
return {
is_ugoira,
is_manga,
src150,
srcbig: iinfo.url.big,
is_multiple: iinfo.is_multiple,
illust_id: iinfo.illust_id,
illust_title: iinfo.illust_title,
user_id: uinfo.user_id,
user_name: uinfo.user_name,
is_follow: uinfo.is_follow,
tags: binfo.tags,
bookmark_count: binfo.bookmark_count,
};
});
}
function parseToDOM(html) {
return (new DOMParser()).parseFromString(html, 'text/html');
}
function removeAnnoyance($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
'.ad-printservice',
'.bookmark-ranges',
'.require-premium',
'.showcase-reminder',
'.sample-user-search',
'.popular-introduction',
].forEach((e) => {
$doc.find(e).remove();
});
}
const BASE = (() => {
const bu = new URI(document.baseURI);
const pn = bu.pathname();
const ss = URI.parseQuery(bu.query());
const baseURI = bu.toString();
const tt = $('input[name="tt"]').val();
const container = $('li.image-item').parent()[0];
const $fullwidthElement = $('#wrapper div:first');
let supported = true;
let li_type = 'search';
/** li_type - the DOM type to show li.image-item
*
* 'search'(default) : illust_150 + illust_title + user_name + bookmark_count
* 'member-illust' : illust_150 + illust_title + + bookmark_count
* 'mybookmark' : illust_150 + illust_title + user_name + bookmark_count + checkbox + editlink
*/
if (pn === '/member_illust.php' && ss.id) {
li_type = 'member-illust';
} else if (pn === '/search.php') {
} else if (pn === '/bookmark.php' && !ss.type) {
if (!ss.id) {
li_type = 'mybookmark';
}
} 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') {
} else if (pn === '/bookmark_new_illust_r18.php') {
} else {
supported = false;
}
return {
tt,
baseURI,
li_type,
supported,
container,
$fullwidthElement,
};
})();
Vue.filter('illust_href', function(illust_id) {
return 'http://www.pixiv.net/member_illust.php?mode=medium&illust_id='+illust_id;
});
Vue.component('img150', {
props:['thd'],
template: `
{{thd.illust_title}}
',
});
Vue.component('user-name', {
props:['thd'],
template: ` {{thd.user_name}}`,
filters: {
user_href: function(user_id) {
return 'http://www.pixiv.net/member_illust.php?id='+user_id;
},
},
});
Vue.component('count-list', {
props:['thd'],
template: `