// ==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); } } } } })();