Greasy Fork

Greasy Fork is available in English.

Pinterest Ultra Assistant V6.3 (Pro Color Engine)

Bilingual UI, AI 2x Sharpen, Source Finder, and SMART Color Palette (Filters out background grays).

当前为 2025-12-30 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Pinterest Ultra Assistant V6.3 (Pro Color Engine)
// @namespace    http://tampermonkey.net/
// @version      6.3
// @description  Bilingual UI, AI 2x Sharpen, Source Finder, and SMART Color Palette (Filters out background grays).
// @author       Pi Xiao
// @match        https://*.pinterest.com/*
// @grant        GM_openInTab
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const BRIDGE_PAGE = "https://meishubiji.cn/ai-processing-center/";

    // --- 算法:颜色差异度计算 ---
    function getColorDist(hex1, hex2) {
        const r1 = parseInt(hex1.slice(1,3), 16), g1 = parseInt(hex1.slice(3,5), 16), b1 = parseInt(hex1.slice(5,7), 16);
        const r2 = parseInt(hex2.slice(1,3), 16), g2 = parseInt(hex2.slice(3,5), 16), b2 = parseInt(hex2.slice(5,7), 16);
        return Math.sqrt((r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2);
    }

    function rgbToHex(r, g, b) {
        return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
    }

    // --- 核心:智能提取鲜艳色盘 ---
    function getSmartPalette(img) {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 50; canvas.height = 50; // 小尺寸采样提速并去噪
        ctx.drawImage(img, 0, 0, 50, 50);
        
        const data = ctx.getImageData(0, 0, 50, 50).data;
        let colorMap = {};
        
        for (let i = 0; i < data.length; i += 4) {
            const r = data[i], g = data[i+1], b = data[i+2], a = data[i+3];
            if (a < 128) continue; // 忽略透明像素
            
            const hex = rgbToHex(r, g, b);
            // 计算饱和度:值越大说明颜色越鲜艳
            const saturation = Math.max(r, g, b) - Math.min(r, g, b);
            // 权重公式:基础频率 + 饱和度奖励
            colorMap[hex] = (colorMap[hex] || 0) + (1 + saturation / 20);
        }

        // 排序并过滤掉过于接近的颜色
        const sortedColors = Object.keys(colorMap).sort((a, b) => colorMap[b] - colorMap[a]);
        const finalPalette = [];
        
        for (const color of sortedColors) {
            if (finalPalette.length >= 6) break;
            // 如果这个颜色和已选颜色差异足够大(距离 > 40),才入选
            if (finalPalette.every(c => getColorDist(c, color) > 40)) {
                finalPalette.push(color);
            }
        }
        return finalPalette;
    }

    // --- 智能预览窗 ---
    async function processAndShow(imgUrl) {
        const originalUrl = imgUrl.replace(/\/(236x|474x|564x|736x|1200x)\//, '/originals/').replace(/\.webp$/, '.jpg');
        const overlay = document.createElement('div');
        overlay.id = "px-overlay";
        overlay.style = "position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.96);z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;color:white;font-family:sans-serif;cursor:zoom-out;";
        overlay.innerHTML = '<div style="text-align:center;"><div class="px-spinner"></div><div style="margin-top:15px; font-size:14px; color:#00ffcc; letter-spacing:1px;">EXTRACTING SMART PALETTE...</div></div><style>.px-spinner { width:30px; height:30px; border:2px solid rgba(0,255,204,0.1); border-top-color:#00ffcc; border-radius:50%; animation:spin .8s linear infinite; margin:0 auto; } @keyframes spin { to { transform:rotate(360deg); } } .px-color:hover { transform: scale(1.2); border-color: #fff !important; }</style>';
        overlay.onclick = () => overlay.remove();
        document.body.appendChild(overlay);

        const img = new Image();
        img.crossOrigin = "Anonymous";
        img.src = originalUrl;
        
        img.onload = function() {
            const palette = getSmartPalette(img);
            overlay.innerHTML = "";
            const container = document.createElement('div');
            container.style = "text-align:center; width:95%; height:90vh; display:flex; flex-direction:column; cursor:default;";
            container.onclick = (e) => e.stopPropagation();
            
            const scrollBox = document.createElement('div');
            scrollBox.style = "overflow:auto; border:1px solid #333; border-radius:12px; flex:1; background:#050505; display:flex; align-items:center; justify-content:center;";
            const pImg = document.createElement('img');
            pImg.src = originalUrl;
            pImg.style = "max-width:200%; image-rendering:-webkit-optimize-contrast; filter:contrast(1.05);";
            scrollBox.appendChild(pImg);

            const bar = document.createElement('div');
            bar.style = "padding:25px; display:flex; flex-direction:column; align-items:center; gap:20px; background:#111; border-top: 1px solid #222;";
            
            // 色盘生成
            let paletteHTML = `<div style="display:flex; gap:12px; align-items:center;">
                <span style="font-size:11px; color:#555; text-transform:uppercase; letter-spacing:1px;">Accents:</span>`;
            palette.forEach(color => {
                paletteHTML += `<div class="px-color" style="width:28px; height:28px; background:${color}; border-radius:6px; cursor:pointer; border:2px solid #222; transition:0.2s;" title="Copy Hex: ${color}" data-hex="${color}"></div>`;
            });
            paletteHTML += `</div>`;
            
            const actionHTML = `
                <div style="display:flex; gap:20px; align-items:center;">
                    <button id="btn-ai-go" style="background:linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); color:white; border:none; padding:14px 40px; border-radius:50px; font-size:15px; font-weight:bold; cursor:pointer; box-shadow:0 10px 30px rgba(37,117,252,0.3); transition:0.3s;">🚀 LAUNCH AI 8K ENGINE</button>
                    <span style="color:#444; cursor:pointer; font-size:12px;" onclick="document.getElementById('px-overlay').remove()">Close Preview ×</span>
                </div>
            `;

            bar.innerHTML = paletteHTML + actionHTML;
            container.appendChild(scrollBox);
            container.appendChild(bar);
            overlay.appendChild(container);

            overlay.querySelectorAll('.px-color').forEach(el => {
                el.onclick = () => {
                    const hex = el.getAttribute('data-hex');
                    GM_setClipboard(hex);
                    el.style.borderColor = "#fff";
                    setTimeout(() => el.style.borderColor = "#222", 500);
                };
            });
            overlay.querySelector('#btn-ai-go').onclick = () => window.open(`${BRIDGE_PAGE}?url=${encodeURIComponent(originalUrl)}`, '_blank');
        };
        img.onerror = () => { window.open(originalUrl, '_blank'); overlay.remove(); };
    }

    // --- 注入逻辑 ---
    function injectButtons() {
        const images = document.querySelectorAll('img');
        images.forEach(img => {
            const src = img.src;
            if (!src || !src.includes('pinimg.com') || img.width < 150 || img.closest('.px-helper-bar')) return;
            const container = img.closest('[data-test-id="pin-visual-wrapper"]') || img.closest('[data-test-id="visual-content-container"]') || img.parentElement;
            if (container) {
                if (window.getComputedStyle(container).position === 'static') container.style.position = 'relative';
                const bar = document.createElement('div');
                bar.className = 'px-helper-bar';
                bar.style = "position:absolute; top:10px; left:10px; z-index:1000; display:flex; gap:4px; opacity:0; transition:0.3s; pointer-events:auto;";
                container.addEventListener('mouseenter', () => bar.style.opacity = "1");
                container.addEventListener('mouseleave', () => bar.style.opacity = "0");
                const btnStyle = 'color:white; border:none; border-radius:4px; cursor:pointer; padding:4px 8px; font-weight:bold; font-size:9px; box-shadow:0 2px 5px rgba(0,0,0,0.3); white-space:nowrap;';
                const b1 = document.createElement('button'); b1.innerHTML = '🪄 2x HD'; b1.style = btnStyle + 'background:#00BFFF;';
                b1.onclick = (e) => { e.preventDefault(); e.stopPropagation(); processAndShow(src); };
                const b2 = document.createElement('button'); b2.innerHTML = '🖼️ Originals'; b2.style = btnStyle + 'background:#E60023;';
                b2.onclick = (e) => { e.preventDefault(); e.stopPropagation(); window.open(src.replace(/\/(236x|474x|564x|736x)\//, '/originals/'), '_blank'); };
                const b3 = document.createElement('button'); b3.innerHTML = '🔍 Source'; b3.style = btnStyle + 'background:#34a853;';
                b3.onclick = (e) => { e.preventDefault(); e.stopPropagation(); window.open(`https://lens.google.com/uploadbyurl?url=${encodeURIComponent(src.replace(/\/(236x|474x|564x|736x)\//, '/originals/'))}`, '_blank'); };
                bar.appendChild(b1); bar.appendChild(b2); bar.appendChild(b3);
                container.appendChild(bar);
            }
        });
    }

    setInterval(injectButtons, 2500);
    const observer = new MutationObserver(injectButtons);
    observer.observe(document.body, { childList: true, subtree: true });
})();