// ==UserScript==
// @name Pixiv快速隐私收藏
// @description 右键点任意位置的收藏按钮可以快速隐私收藏作品
// @namespace https://github.com/journey-ad
// @version 1.0.1
// @author journey-ad
// @license WTFPL
// @match *://www.pixiv.net/*
// @icon https://www.google.com/s2/favicons?domain=pixiv.net
// @require https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js
// @run-at document-start
// @grant none
// @downloadURL https://update.greasyfork.icu/scripts/425832/Pixiv%E5%BF%AB%E9%80%9F%E9%9A%90%E7%A7%81%E6%94%B6%E8%97%8F.user.js
// @updateURL https://update.greasyfork.icu/scripts/425832/Pixiv%E5%BF%AB%E9%80%9F%E9%9A%90%E7%A7%81%E6%94%B6%E8%97%8F.meta.js
// ==/UserScript==
(function () {
'use strict';
// 配合document-start使用observe监控global data标签存在,第一时间取到csrf token
(new MutationObserver(check)).observe(document, { childList: true, subtree: true });
function check(changes, observer) {
if (document.querySelector('#meta-global-data')) {
observer.disconnect();
init()
}
};
function init() {
let globalData = null
try {
const content = $('#meta-global-data').attr('content')
globalData = JSON.parse(content)
} catch (ex) {
console.error('global data 解析失败')
return false
}
const BUTTON_CLASSNAME = 'button.sc-kgq5hw-0.fgVkZi'
const ICON_CSS = `.jyafz {
box-sizing: border-box;
line-height: 0;
font-size: 0px;
vertical-align: top;
transition: color 0.2s ease 0s, fill 0.2s ease 0s;
color: rgb(255, 64, 96);
fill: currentcolor;
}
.jyafz .j89e3c-0 {
transition: fill 0.2s ease 0s;
fill: rgb(255, 64, 96);
}
.jyafz mask .j89e3c-0 {
fill: white;
}
.iGPkEj {
fill: rgba(0, 0, 0, 0.88);
fill-rule: evenodd;
clip-rule: evenodd;
}
.fsBRJQ {
fill: rgb(255, 255, 255);
fill-rule: evenodd;
clip-rule: evenodd;
}`
const ICON_SVG_BASE = ``
const ICON_SVG = ``
addStyle(ICON_CSS)
$(document).on('contextmenu', BUTTON_CLASSNAME, function (e) {
const $this = $(this)
const state = $this.attr('data-state')
const url = $this.closest('div[type="illust"]').find('a').attr('href') || location.pathname
const illust_id = url.match(/\d+$/)?.[0]
if (!illust_id) return true
if (state !== 'liked') {
addFav(illust_id, 1, (res) => {
if (res.error) return
if (res) {
const { last_bookmark_id } = res.body
$this
.attr('data-state', 'liked')
.attr('data-bookmark-id', last_bookmark_id)
.html(ICON_SVG)
console.log(`作品 ${illust_id} 添加隐私收藏`)
}
})
} else {
const bookmark_id = $this.attr('data-bookmark-id')
delFav(bookmark_id, (res) => {
if (res.error) return
if (state) {
$this
.attr('data-state', null)
.attr('data-bookmark-id', null)
.html(ICON_SVG_BASE)
console.log(`作品 ${illust_id} 解除收藏`)
}
})
}
return false;
})
function addFav(illust_id, restrict, cb) {
fetch("https://www.pixiv.net/ajax/illusts/bookmarks/add", {
"headers": {
"accept": "application/json",
"content-type": "application/json; charset=utf-8",
"x-csrf-token": globalData.token
},
"referrer": "https://www.pixiv.net",
"body": JSON.stringify({ illust_id, restrict, comment: "", tags: [] }),
"method": "POST",
"mode": "cors",
"credentials": "include"
})
.then(res => res.json())
.then(res => {
cb && cb(res)
})
}
function delFav(illust_id, cb) {
fetch("https://www.pixiv.net/rpc/index.php", {
"headers": {
"accept": "application/json",
"content-type": "application/x-www-form-urlencoded; charset=utf-8",
"x-csrf-token": globalData.token
},
"referrer": "https://www.pixiv.net",
"body": `mode=delete_illust_bookmark&bookmark_id=${illust_id}`,
"method": "POST",
"mode": "cors",
"credentials": "include"
})
.then(res => res.json())
.then(res => {
cb && cb(res)
})
}
function addStyle(css) {
if (typeof GM_addStyle != "undefined") {
GM_addStyle(css);
} else if (typeof PRO_addStyle != "undefined") {
PRO_addStyle(css);
} else {
var node = document.createElement("style");
node.type = "text/css";
node.appendChild(document.createTextNode(css));
var heads = document.getElementsByTagName("head");
if (heads.length > 0) {
heads[0].appendChild(node);
} else {
// no head yet, stick it whereever
document.documentElement.appendChild(node);
}
}
}
}
})();