Greasy Fork

Greasy Fork is available in English.

花瓣网用户采集页信息增强

在用户采集页面显示图片分辨率、来源和画板信息,支持滚动加载

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         花瓣网用户采集页信息增强
// @namespace    https://github.com/yourname
// @version      2.0
// @description  在用户采集页面显示图片分辨率、来源和画板信息,支持滚动加载
// @match        https://huaban.com/*/pins
// @match        https://huaban.com/user/*/pins
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @connect      huaban.com
// @license      GNU GPLv3
// ==/UserScript==

(function() {
    'use strict';

    // 添加自定义样式
    GM_addStyle(`
        .huaban-pin-info {
            font-size: 14px;
            color: #333;
            background: rgba(255,255,255,0.8);
            padding: 2px 2px;
            border-radius: 2px;
            margin-top: 2px;
            display: block;
            line-height: 1.2;
        }
        .fki7oGar:hover .huaban-pin-info {
            background: rgba(0,0,0,0.7);
            color: #fff;
        }
        .pin-size {
            color: #e74c3c;
            font-weight: bold;
        }
        .pin-source {
            color: #3498db;
        }
        .pin-board {
            color: #2ecc71;
        }
    `);

    // 1. 获取用户名
    const getUsername = () => {
        const path = window.location.pathname;
        const match = path.match(/\/(?:user\/)?([^\/]+)\/pins/);
        return match ? match[1] : null;
    };
    const username = getUsername();
    if (!username) return;

    // 2. 数据存储和状态
    const pinDataMap = new Map();
    let currentMax = null;
    let isLoading = false;
    let isLastPage = false;

    // 3. 获取单页图片数据
    async function fetchPinPage() {
        if (isLoading || isLastPage) return;
        isLoading = true;

        let url = `https://huaban.com/v3/${username}/pins?limit=30&fields=pins:PIN|total,page_num,page_size`;
        if (currentMax) {
            url += `&max=${currentMax}`;
        }

        try {
            const response = await new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    onload: resolve,
                    onerror: reject
                });
            });

            const data = JSON.parse(response.responseText);
            if (data.pins && data.pins.length > 0) {
                // 更新分页参数
                currentMax = data.pins[data.pins.length - 1].pin_id;

                // 存储新获取的pin数据
                data.pins.forEach(pin => {
                    pinDataMap.set(pin.pin_id.toString(), pin);
                });

                // 检查是否是最后一页
                if (data.pins.length < 30) {
                    isLastPage = true;
                }

                return data.pins;
            } else {
                isLastPage = true;
                return [];
            }
        } catch (error) {
            console.error('获取数据失败:', error);
            return [];
        } finally {
            isLoading = false;
        }
    }

    // 4. 注入图片信息
    function injectPinInfo() {
        const pinContainers = document.querySelectorAll('.BR9Lhzqi:not(.info-enhanced)');

        pinContainers.forEach(container => {
            const pinId = container.getAttribute('data-pin-id');
            if (!pinId) return;

            const pinInfo = pinDataMap.get(pinId);
            if (!pinInfo || !pinInfo.file) {
                // 如果数据未加载,且不是正在加载中,则触发加载
                if (!isLoading && !isLastPage) {
                    fetchPinPage().then(injectPinInfo);
                }
                return;
            }

            // 标记已处理
            container.classList.add('info-enhanced');

            // 创建信息元素
            const infoElement = document.createElement('div');
            infoElement.className = 'huaban-pin-info';

            // 构建信息HTML
            let infoHTML = `
                <span class="pin-size">${pinInfo.file.width} × ${pinInfo.file.height}</span>
            `;

            // 修改这里:无论是否有来源都显示来源信息
            infoHTML += ` | <span class="pin-source">来源: ${pinInfo.source || '无'}</span>`;

            if (pinInfo.board?.title) {
                infoHTML += ` | <span class="pin-board">画板: ${pinInfo.board.title}</span>`;
            }

            infoElement.innerHTML = infoHTML;

            // 插入到图片下方
            const targetElement = container.querySelector('.hUfxKZoq') ||
                                 container.querySelector('.__0ionfaOd');
            if (targetElement) {
                targetElement.insertAdjacentElement('afterend', infoElement);
            }
        });
    }

    // 5. 滚动加载处理
    const scrollHandler = debounce(() => {
        // 当距离底部500px时加载更多
        if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 500) {
            fetchPinPage().then(injectPinInfo);
        }
    }, 300);

    // 6. DOM变化观察器
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            if (mutation.addedNodes.length > 0) {
                injectPinInfo();
            }
        });
    });

    // 7. 初始化
    async function initialize() {
        // 初始加载第一页
        await fetchPinPage();
        injectPinInfo();

        // 开始观察DOM变化
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        // 添加滚动监听
        window.addEventListener('scroll', scrollHandler);

        // 定期检查(防止某些情况下遗漏)
        setInterval(() => {
            if (!isLoading) {
                injectPinInfo();
            }
        }, 3000);
    }

    // 防抖函数
    function debounce(func, wait) {
        let timeout;
        return function() {
            clearTimeout(timeout);
            timeout = setTimeout(func, wait);
        };
    }

    initialize();
})();