您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
支持用户主页、推荐和排行榜,支持识别列表类名以适应网站变动
当前为
// ==UserScript== // @name Pixiv 缩略图中显示书签数量 // @name:en Display bookmark counts in Pixiv thumbnails // @namespace http://tampermonkey.net/ // @version 1.8 // @description 支持用户主页、推荐和排行榜,支持识别列表类名以适应网站变动 // @description:en Supports user pages, recommendation lists, and ranking pages, supports identifying list class names to adapt to website changes // @author InMirrors // @license GPL-3.0-or-later // @icon data:image/png;base64,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 // @match https://www.pixiv.net/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // === Style Customization === // 您可以在这里修改以下 CSS 变量来自定义书签数量元素的样式和位置。 // 修改后请保存脚本并刷新 Pixiv 页面。 // 位置 (使用百分比相对于图片容器定位) // 例如: // --bm-pos-bottom: 5%; --bm-pos-left: 5%; /* 左下角 */ // --bm-pos-bottom: 5%; --bm-pos-right: 5%; /* 右下角 */ // --bm-pos-top: 5%; --bm-pos-left: 5%; /* 左上角 */ // --bm-pos-top: 5%; --bm-pos-right: 5%; /* 右上角 */ // 如果某个方向不想设置,请使用 auto (例如:--bm-pos-right: auto;) const customStyles = ` :root { --bm-pos-bottom: 2px; /* 位置:距离底部的距离 */ --bm-pos-left: 2px; /* 位置:距离左侧的距离 */ --bm-pos-right: auto; /* 位置:距离右侧的距离 */ --bm-pos-top: auto; /* 位置:距离顶部的距离 */ --bm-bg-color: rgba(220, 220, 220, 0.5); /* 背景颜色 (rgba 包含透明度) */ --bm-border-radius: 8px; /* 圆角弧度 */ --bm-font-family: sans-serif; /* 文本字体 */ --bm-font-size: 12px; /* 文本字号 */ --bm-font-weight: bold; /* 文本字重 */ --bm-text-color: #0069b1; /* 文本颜色 */ --bm-text-opacity: 1.0; /* 文本透明度 */ --bm-padding: 0; /* 整个元素的内边距 (通常设为 0,内边距在链接上设置) */ --bm-link-padding: 3px 6px 3px 18px; /* 链接的内边距 (用于控制文本与图标距离边框的距离) */ --bm-icon-size: 10px; /* 心形图标大小 (宽度和高度) */ --bm-icon-position: center left 6px; /* 心形图标位置 (垂直位置 靠左 距离左侧距离) */ /* 注意:心形图标的颜色在 SVG 数据中指定 (#0069B1),如需修改请修改 SVG 数据 URL */ /* 注意:心形图标的透明度由整个元素的背景透明度或文本透明度间接影响, 或者通过修改 SVG 数据中的 fill="rgba(..., alpha)" 实现更精细控制 */ } `; GM_addStyle(` ${customStyles} /* 书签数量元素本体 */ .bmcount { position: absolute !important; /* 绝对定位 */ z-index: 10; /* 确保在图片上方显示 */ /* 使用自定义的位置变量 */ bottom: var(--bm-pos-bottom, auto); left: var(--bm-pos-left, auto); right: var(--bm-pos-right, auto); top: var(--bm-pos-top, auto); /* 使用自定义的样式变量 */ background-color: var(--bm-bg-color); border-radius: var(--bm-border-radius); padding: var(--bm-padding); /* 通常为 0 */ /* 移除旧的布局样式 */ text-align: initial !important; /* 取消居中 */ padding-bottom: 0 !important; /* 移除底部填充 */ } /* 书签数量链接和文本 */ .bmcount a { display: block; /* 使 padding 生效 */ height: initial !important; width: initial !important; border-radius: inherit !important; /* 继承父元素的圆角 */ /* 使用自定义的文本和链接内边距变量 */ padding: var(--bm-link-padding); /* 使用自定义的文本样式变量 */ font-family: var(--bm-font-family); font-size: var(--bm-font-size) !important; font-weight: var(--bm-font-weight) !important; color: var(--bm-text-color) !important; opacity: var(--bm-text-opacity); /* 文本透明度 */ text-decoration: none !important; /* 图标样式 */ background-image: url("data:image/svg+xml;charset=utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2210%22 height=%2210%22 viewBox=%220 0 12 12%22><path fill=%22%230069B1%22 d=%22M9,1 C10.6568542,1 12,2.34314575 12,4 C12,6.70659075 10.1749287,9.18504759 6.52478604,11.4353705 L6.52478518,11.4353691 C6.20304221,11.6337245 5.79695454,11.6337245 5.4752116,11.4353691 C1.82507053,9.18504652 0,6.70659017 0,4 C1.1324993e-16,2.34314575 1.34314575,1 3,1 C4.12649824,1 5.33911281,1.85202454 6,2.91822994 C6.66088719,1.85202454 7.87350176,1 9,1 Z%22/></svg>") !important; background-position: var(--bm-icon-position) !important; background-size: var(--bm-icon-size) !important; background-repeat: no-repeat !important; } /* 移除针对特定类名的旧样式 */ .JoCpVnw .bmcount { padding-bottom: initial !important; } `); // === Storage and Selector Management === const STORAGE_KEY = 'pixiv_bookmark_selectors'; // Selectors that seem relatively stable or cover specific cases const ALWAYS_INCLUDED_SELECTORS = [ '.ranking-item', // 排行榜 '.gtm-illust-recommend-zone[data-gtm-recommend-zone="discovery"] li', // 插图页面下方的推荐 ]; let dynamicArtworkSelectors = loadSelectors(); let currentCombinedSelector = buildSelectorString(); // Load selectors from storage function loadSelectors() { const stored = GM_getValue(STORAGE_KEY, '[]'); try { const selectors = JSON.parse(stored); if (Array.isArray(selectors) && selectors.every(s => typeof s === 'string')) { return selectors.filter(s => s.trim() !== ''); } console.error("Failed to parse stored selectors, returning empty array.", stored); return []; } catch (e) { console.error("Error loading selectors from storage:", e); return []; } } // Save selectors to storage function saveSelectors(selectors) { GM_setValue(STORAGE_KEY, JSON.stringify(selectors)); dynamicArtworkSelectors = selectors; // Update in-memory variable currentCombinedSelector = buildSelectorString(); // Rebuild selector string // Note: The MutationObserver will pick up the new currentCombinedSelector // on its next execution cycle after a DOM change. } // Build the full CSS selector string for querySelectorAll function buildSelectorString() { // Note: .ranking-item (appears in the ranking page) is an item selector, not a container selector const containerSelectors = dynamicArtworkSelectors.filter(s => !s.endsWith(' li') && s !== '.ranking-item'); // Exclude .ranking-item from containers const itemSelectors = dynamicArtworkSelectors.filter(s => s.endsWith(' li') || s === '.ranking-item'); // Include .ranking-item as an item const alwaysIncludedContainerSelectors = ALWAYS_INCLUDED_SELECTORS.filter(s => !s.endsWith(' li') && s !== '.ranking-item'); const alwaysIncludedItemSelectors = ALWAYS_INCLUDED_SELECTORS.filter(s => s.endsWith(' li') || s === '.ranking-item'); const finalContainerSelectors = [...new Set([...containerSelectors, ...alwaysIncludedContainerSelectors])]; const finalItemSelectors = [...new Set([...itemSelectors, ...alwaysIncludedItemSelectors])]; // Build the query: all items + li descendants of all containers const queryParts = [ ...finalItemSelectors, // Items already selected (.ranking-item is here) ...finalContainerSelectors.map(s => s + ' li') // li inside containers ]; // Add the :not([data-dummybmc]) exclusion to each part const finalQuery = queryParts.map(s => s + ':not([data-dummybmc])').join(','); console.log("Built selector string:", finalQuery); return finalQuery; } // Find potential new container selectors on the current page // 基本只有用户主页会用到这个功能,排行榜和推荐都是固定类名 function findPotentialSelectors() { const allPotentialOnPage = new Set(); // 记录在页面上找到的所有潜在选择器 const existingSelectors = new Set([...dynamicArtworkSelectors, ...ALWAYS_INCLUDED_SELECTORS]); const newFound = new Set(); // 记录在页面上找到且是新的选择器 const artworkLinks = document.querySelectorAll('a[href*="/artworks/"]'); artworkLinks.forEach(link => { const li = link.closest('li'); if (!li) return; const ul = li.parentElement; if (!ul || ul.tagName !== 'UL') return; const container = ul.parentElement; if (container && (container.tagName === 'DIV' || container.tagName === 'SECTION')) { if (container.classList.length > 0) { const selector = '.' + Array.from(container.classList).join('.'); allPotentialOnPage.add(selector); // 添加到所有找到的集合 // 如果这个选择器不在现有列表中,则添加到新找到的集合 if (!existingSelectors.has(selector)) { newFound.add(selector); } } } }); // 返回包含详细信息的对象 return { totalFound: Array.from(allPotentialOnPage), // 页面上找到的所有潜在选择器 newFound: Array.from(newFound) // 页面上找到且是新的选择器 }; } // === Context Menu Commands === GM_registerMenuCommand("添加 (Add) 当前页面的 Pixiv 书签选择器", async () => { const result = findPotentialSelectors(); if (result.totalFound.length === 0) { // 情况 1: 页面上没有找到任何潜在的选择器 alert("未能在当前页面找到任何潜在的书签列表容器结构。请确保当前页面显示有插图列表。"); } else { // 页面上找到了潜在的选择器 if (result.newFound.length === 0) { // 情况 2: 找到了,但都是已存在的 alert("在当前页面找到了潜在的书签列表容器结构,但所有找到的选择器都已存在于列表中,无需添加新的。"); console.log("Found existing potential selectors:", result.totalFound.join(', ')); } else { // 情况 3: 找到了新的选择器 const currentSelectors = loadSelectors(); // 再次加载最新状态 const updatedSelectors = [...new Set([...currentSelectors, ...result.newFound])]; // 合并并去重 // 理论上 newFound 不为空时,updatedSelectors 长度应该大于 currentSelectors 长度,但为了严谨还是检查一下 if (updatedSelectors.length > currentSelectors.length) { saveSelectors(updatedSelectors); const addedList = result.newFound.join('\n'); alert(`成功添加了 ${result.newFound.length} 个新的书签列表容器选择器:\n\n${addedList}\n\n脚本将尝试使用这些新的选择器,请刷新页面使变更生效。`); console.log("Added new selectors:", result.newFound.join(', ')); } else { // 这通常不应该发生,除非 findPotentialSelectors 或 saveSelectors 逻辑有误 alert("找到了新的选择器,但在保存时未能实际增加列表项。请检查控制台输出。"); console.error("Logic error: newFound is not empty, but list size did not increase."); console.log("New found:", result.newFound); console.log("Current selectors:", currentSelectors); console.log("Updated selectors (after merge):", updatedSelectors); } } } }); GM_registerMenuCommand("清除 (Clear) 已添加的 Pixiv 书签选择器", () => { if (confirm("确定要清除所有动态学习到的 Pixiv 书签列表容器选择器吗?这可能导致脚本失效,直到重新添加。")) { saveSelectors([]); alert("已清除所有动态书签选择器。"); } }); // === Mutation Observer === const doneCheckSelectors = '.bmcount , .bookmark-count , a[href*="/bookmark_detail.php?illust_id="]'; // 辅助函数:根据ID获取书签数并插入到元素中 async function fetchAndInsertBookmarkCount(listItem, id, insertionParent) { //console.log(`Attempting to fetch for ID: ${id}`); // 再次检查,防止在等待过程中或观察器触发后元素被处理 if (listItem.querySelectorAll(doneCheckSelectors).length > 0 || listItem.hasAttribute("data-bmcount")) { //console.log(`Item ${id} already processed when fetchAndInsertBookmarkCount was called.`); if (listItem.hasAttribute("data-dummybmc")) { delete listItem.dataset.dummybmc; // 清理临时标记 } listItem.dataset.bmcount = listItem.dataset.bmcount || 'exists'; // Set bmcount if not already set by a successful run return; } try { const response = await fetch("https://www.pixiv.net/ajax/illust/" + id, { credentials: "omit" }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); const bmcount = data?.body?.bookmarkCount; if (bmcount !== undefined && bmcount !== null) { // 将元素插入到图片容器内 if (listItem.querySelectorAll(doneCheckSelectors).length === 0) { // Final check before insert insertionParent.insertAdjacentHTML("beforeend", '<div class="bmcount"><a href="/bookmark_detail.php?illust_id=' + id + '">' + bmcount + "</a></div>"); } listItem.dataset.bmcount = bmcount; // 标记处理成功并保存书签数 } else { listItem.dataset.bmcount = '0'; // 标记处理成功但书签数为 0 } } catch (error) { console.error("Error fetching bookmark count for artwork ID", id, ":", error); listItem.dataset.bmcount = 'error'; // 标记处理失败 } finally { // 无论成功或失败,处理流程结束,移除临时标记 if (listItem.hasAttribute("data-dummybmc")) { delete listItem.dataset.dummybmc; } } } // fetchAndInsertBookmarkCount // 处理元素,添加书签数 async function processSingleArtworkElement(Each) { // Each could be an LI or a SECTION.ranking-item const listItem = (Each.tagName === 'LI' || Each.tagName === 'SECTION') ? Each : Each.closest('li, section'); // Check if it's a valid item and hasn't been processed or is currently being processed if (!listItem || listItem.hasAttribute("data-dummybmc") || listItem.hasAttribute("data-bmcount")) { return; } // Mark as being processed temporarily listItem.dataset.dummybmc = ""; // Check if bookmark count element already exists within this item if (listItem.querySelectorAll(doneCheckSelectors).length > 0) { delete listItem.dataset.dummybmc; // Clean up dummy mark listItem.dataset.bmcount = 'exists'; // Mark as already has the element return; } let id = null; const artworkLink = listItem.querySelector('a[href*="/artworks/"]'); // If artworkLink not found, cannot proceed if (!artworkLink) { delete listItem.dataset.dummybmc; // Clean up dummy mark return; } // Extract ID from the href attribute // Format: "/artworks/ID" or "/lang/artworks/ID" id = /\d+$/.exec(artworkLink.href)?.[0]; // If ID not found, skip if (!id) { delete listItem.dataset.dummybmc; // Clean up dummy mark return; } fetchAndInsertBookmarkCount(listItem, id, artworkLink); } // processSingleArtworkElement() // MutationObserver 回调函数调用处理函数 const observer = new MutationObserver((mutations) => { // On any mutation, re-query all matching elements and process them. // processSingleArtworkElement handles checking if an element needs processing. document.querySelectorAll(currentCombinedSelector).forEach(processSingleArtworkElement); }); // Start observing the body for changes observer.observe(document.body, { childList: true, subtree: true }); console.log("Pixiv Bookmark Count script started."); console.log("Initial selectors:", dynamicArtworkSelectors); console.log("Always included selectors:", ALWAYS_INCLUDED_SELECTORS); console.log("Combined query selector:", currentCombinedSelector); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址