// ==UserScript== // @name Pixiv收藏夹自动标签 // @name:en Label Pixiv Bookmarks // @namespace http://tampermonkey.net/ // @version 2.1 // @description 自动为Pixiv收藏夹内图片打上已有的标签 // @description:en Automatically add existing labels for images in the bookmarks // @author Ziqing19 // @match https://www.pixiv.net/*users/*/bookmarks/artworks* // @match https://www.pixiv.net/bookmark.php* // @icon https://www.google.com/s2/favicons?domain=pixiv.net // @resource bootstrapCSS https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css // @grant GM_getResourceURL // @downloadURL none // ==/UserScript== function cssElement(url) { const link = document.createElement("link"); link.href = url; link.rel="stylesheet"; link.type="text/css"; return link; } const delay = ms => new Promise(res => setTimeout(res, ms)); async function handleUpdate(token, illust_id, tags, retainComment, restricted) { const PIXIV_API_URL = "https://www.pixiv.net/rpc/index.php"; const mode = "save_illust_bookmark"; let comment; // get comment from the detailed page if (retainComment) { const commentRaw = await fetch("https://www.pixiv.net/bookmark_add.php?type=illust&illust_id=" + illust_id); const commentRes = await commentRaw.text(); const parser = new DOMParser(); const doc = parser.parseFromString(commentRes, "text/html"); comment = doc.querySelector("div.input-box.ui-counter").firstElementChild.value; } else { comment = ""; } await fetch(PIXIV_API_URL, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" }, credentials: "same-origin", body: [ `mode=${mode}`, `illust_id=${illust_id}`, `restrict=${!!restricted? 1 : 0}`, 'comment'+(!!comment ? `=${comment}` : ''), 'tags'+(!!tags ? `=${tags}` : ''), `tt=${token}`, ].join('&'), }); } async function handleStart(addFirst, addSAFE, tag, retainComment, publicationType) { window.runFlag = true; document.querySelector("#prompt").innerText = `处理中,请勿关闭窗口 Processing. Please do not close the window. `; // get token const userRaw = await fetch("https://www.pixiv.net/bookmark_add.php?type=illust&illust_id=83540927"); if (!userRaw.ok) { return alert(`获取身份信息失败 Fail to fetch user information`); } const userRes = await userRaw.text(); const tokenPos = userRes.indexOf("pixiv.context.token"); const tokenEnd = userRes.indexOf(";", tokenPos); const token = userRes.slice(tokenPos, tokenEnd).split("\"")[1]; console.log("token:", token); // get user uid const uidPos = userRes.indexOf("pixiv.user.id"); const uidEnd = userRes.indexOf(";", uidPos); const uid = userRes.slice(uidPos, uidEnd).split("\"")[1]; console.log("uid:", uid); if (!token) { console.log(`获取token失败 Fail to fetch token`); } if (!uid) { console.log(`获取uid失败 Fail to fetch uid`); } // get user tags const tagsRaw = await fetch("https://www.pixiv.net/ajax/user/" + uid + "/illusts/bookmark/tags"); const tagsObj = await tagsRaw.json(); if (!tagsRaw.ok || tagsObj.error === true) { return alert(`获取tags失败 Fail to fetch user tags` + "\n" + decodeURI(tagsObj.message)); } const userTagsSet = new Set(); for (let obj of tagsObj.body.public) { userTagsSet.add(decodeURI(obj.tag)); } for (let obj of tagsObj.body.private) { userTagsSet.add(decodeURI(obj.tag)); } const userTags = Array.from(userTagsSet); console.log("userTags:", userTags); // fetch bookmarks let total, index = 0, offset = 0; // update progress bar const progressBar = document.querySelector("#progress_bar"); const intervalId = setInterval(() => { if (total) { progressBar.innerText = index + "/" + total; const ratio = (index / total * 100).toFixed(2); progressBar.style.width = ratio + "%"; if (!window.runFlag || index === total) { clearInterval(intervalId); } } }, 1000); do { const real_offset = tag === "未分類" ? offset : index; const bookmarksRaw = await fetch("https://www.pixiv.net/ajax/user/" + uid + "/illusts/bookmarks?tag=" + tag + "&offset="+ real_offset +"&limit=100&rest=" + publicationType); const bookmarksRes = await bookmarksRaw.json(); if (!bookmarksRaw.ok || bookmarksRes.error === true) { return alert(`获取用户收藏夹列表失败 Fail to fetch user bookmarks` + "\n" + decodeURI(bookmarksRes.message)); } const bookmarks = bookmarksRes.body; // TODO // console.log(bookmarks); if (!total) { total = bookmarks.total; } for (let work of bookmarks.works) { console.log(index, work.title, work.id); if (work.title !== "-----") { const illust_id = work.id; const work_tags = work.tags; let intersection = userTags.filter(tag => { if (work_tags.includes(tag)) return true; const stripped = tag.split("(")[0]; return work_tags.includes(stripped); }); if (intersection.length > 10) { intersection = intersection.slice(0, 10); } if (addFirst === "true") { if (intersection.length === 0) { intersection.push(work_tags[0]); userTags.push(work_tags[0]); } } if (addSAFE === "true") { if (!work_tags.includes("R-18") && !work_tags.includes("R-18G")) { intersection.push("SAFE"); } } // only if the tags need to be modified // skip those unavailable links if (intersection.length !== 0) { await handleUpdate(token, illust_id, intersection.join("+"), retainComment === "true", publicationType === "show" ? 0 : 1); } else { offset++; } } // work is not available now, skip else { offset++; } // in case that runs too fast delay(500).catch(console.log); index++; if (!window.runFlag) return; } if (bookmarks.works.length === 0) { return window.runFlag = false; } } while (index < total); if (total === 0) { document.querySelector("#prompt").innerText = `指定分类下暂无符合要求的作品,请关闭窗口 Works needed to be labeled not found. Please close the window. ` } else { document.querySelector("#prompt").innerText = `自动添加标签已完成,请关闭窗口并刷新网页 Auto labeling finished successfully. Please close the window and refresh. ` } } (function() { 'use strict'; document.head.appendChild(cssElement(GM_getResourceURL ("bootstrapCSS"))); if (window.location.href.includes("https://www.pixiv.net/bookmark.php")) { const h1Elements = document.querySelectorAll("h1"); for (let el of h1Elements) { el.style.fontSize = "1rem"; } } const popup = document.createElement("div"); popup.style.width = "38rem"; popup.style.position = "fixed"; popup.style.left = "calc(50vw - 19rem)"; if (window.matchMedia("(min-height: 60rem)").matches) { popup.style.minHeight = "50rem"; popup.style.maxHeight = "90vh"; popup.style.top = "calc(50vh - 35rem)"; } else { popup.style.height = "100vh - 2rem"; popup.style.top = "1rem"; } popup.style.overflowX = "hidden"; popup.style.background = "rgb(245,245,245)"; popup.style.display = "none"; popup.classList = "py-3 px-4 rounded border border-secondary flex-column"; popup.id = "popup"; const inner = document.createElement("div"); inner.style.width = "39rem"; inner.style.paddingRight = "2.5rem"; inner.style.overflowY = "scroll"; const closeDiv = document.createElement("div"); closeDiv.classList = "d-flex justify-content-end mb-3"; const close = document.createElement("button"); close.classList = "btn btn-close"; close.addEventListener("click", () => { document.querySelector("#popup").style.display = "none"; }) closeDiv.appendChild(close); const promptDiv = document.createElement("div"); promptDiv.id = "prompt"; promptDiv.classList = "flex-grow-1 text-center mb-4"; promptDiv.innerHTML = `