// ==UserScript== // @name 豆瓣电影 PanSou 资源搜索助手 // @namespace https://toolsdar.cn/ // @version 2.1 // @description UI 美化 + Tab 分组 + 修复列表滚动 + 顶部Tab显性滚动条 // @author Toolsdar.cn // @match https://movie.douban.com/subject/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_setClipboard // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @connect * // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/558219/%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1%20PanSou%20%E8%B5%84%E6%BA%90%E6%90%9C%E7%B4%A2%E5%8A%A9%E6%89%8B.user.js // @updateURL https://update.greasyfork.icu/scripts/558219/%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1%20PanSou%20%E8%B5%84%E6%BA%90%E6%90%9C%E7%B4%A2%E5%8A%A9%E6%89%8B.meta.js // ==/UserScript== (function() { 'use strict'; // ================= 配置与常量 ================= const STORAGE_KEY_API = "pansou_full_api_url"; const STORAGE_KEY_TOKEN = "pansou_api_token"; // ================= 菜单管理 ================= GM_registerMenuCommand("⚙️ 设置 API 地址", () => { const currentUrl = GM_getValue(STORAGE_KEY_API, ""); const newUrl = prompt("请输入完整 API 地址 (如 https://api.example.com/search):", currentUrl); if (newUrl !== null) { GM_setValue(STORAGE_KEY_API, newUrl.trim()); location.reload(); } }); GM_registerMenuCommand("🔑 设置 API Token", () => { const t = prompt("Token (可选):", GM_getValue(STORAGE_KEY_TOKEN, "")); if (t !== null) GM_setValue(STORAGE_KEY_TOKEN, t.trim()); }); // ================= 🎨 UI 样式 (保持 V2.0 样式) ================= GM_addStyle(` .pansou-btn { display: inline-flex; align-items: center; justify-content: center; margin-left: 10px; cursor: pointer; vertical-align: middle; background-color: #eef7fe; color: #37a; border: 1px solid #bn; padding: 2px 8px; border-radius: 4px; font-size: 13px; font-weight: normal; transition: all 0.2s; } .pansou-btn:hover { background-color: #37a; color: white; } #pansou-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.4); z-index: 9999; display: none; justify-content: center; align-items: center; backdrop-filter: blur(2px); } #pansou-modal { background: #fff; width: 620px; max-width: 90%; height: 70vh; max-height: 85vh; border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.12); display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; overflow: hidden; border: 1px solid #eee; } .pm-header { padding: 16px 24px; border-bottom: 1px solid #f0f0f0; background: #fff; display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; } .pm-title { font-weight: 600; font-size: 16px; color: #1f1f1f; display:flex; align-items:center; gap: 8px; } .pm-close { cursor: pointer; font-size: 22px; color: #999; line-height: 1; } .pm-close:hover { color: #333; } #pm-container { display: flex; flex-direction: column; flex: 1; min-height: 0; background: #f9f9f9; } .pm-tabs { display: flex; gap: 10px; padding: 10px 20px 14px 20px; border-bottom: 1px solid #f0f0f0; background: #fff; overflow-x: auto; flex-shrink: 0; } .pm-tabs::-webkit-scrollbar { height: 6px; display: block; } .pm-tabs::-webkit-scrollbar-track { background: transparent; } .pm-tabs::-webkit-scrollbar-thumb { background: #e5e7eb; border-radius: 3px; } .pm-tabs::-webkit-scrollbar-thumb:hover { background: #d1d5db; } .pm-tab-item { padding: 6px 14px; border-radius: 20px; font-size: 13px; cursor: pointer; color: #666; background: #f5f5f5; white-space: nowrap; transition: all 0.2s; border: 1px solid transparent; flex-shrink: 0; } .pm-tab-item:hover { background: #eef2ff; color: #3b82f6; } .pm-tab-item.active { background: #3b82f6; color: white; box-shadow: 0 2px 6px rgba(59,130,246,0.3); } .pm-body { padding: 0; flex: 1; overflow-y: auto; overscroll-behavior: contain; } .pm-body::-webkit-scrollbar { width: 6px; } .pm-body::-webkit-scrollbar-track { background: transparent; } .pm-body::-webkit-scrollbar-thumb { background: #e5e7eb; border-radius: 3px; } .pm-body::-webkit-scrollbar-thumb:hover { background: #d1d5db; } .pm-group-title { padding: 10px 20px; background: #eef2f6; color: #4b5563; font-weight: 600; font-size: 13px; border-top: 1px solid #e5e7eb; border-bottom: 1px solid #e5e7eb; position: sticky; top: 0; z-index: 1; } .pm-item { padding: 12px 20px; border-bottom: 1px solid #f0f0f0; display: flex; align-items: center; gap: 12px; background: #fff; transition: background 0.2s; } .pm-item:hover { background-color: #f8fbff; } .pm-icon { font-size: 20px; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; background: #f3f4f6; border-radius: 8px; flex-shrink: 0; } .pm-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; } .pm-link-title { color: #111827; text-decoration: none; font-weight: 500; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .pm-link-title:hover { color: #2563eb; } .pm-meta { font-size: 12px; color: #9ca3af; display: flex; align-items: center; gap: 10px; } .pm-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; } .pm-pwd-badge { background: #fff1f2; color: #e11d48; border: 1px solid #ffe4e6; border-radius: 99px; padding: 2px 8px; font-size: 12px; font-family: monospace; cursor: pointer; } .pm-go-btn { padding: 6px 14px; background: #3b82f6; color: white; border: none; border-radius: 6px; font-size: 13px; cursor: pointer; } .pm-go-btn:hover { background: #2563eb; } .pm-go-btn.copied { background: #10b981; } .pm-status { padding: 60px 20px; text-align: center; color: #6b7280; display: flex; flex-direction: column; align-items: center; gap: 10px; } .pm-status-icon { font-size: 32px; margin-bottom: 5px; } .pm-error-box { color: #dc2626; background: #fef2f2; border: 1px solid #fee2e2; padding: 15px; border-radius: 8px; font-size: 12px; text-align: left; width: 90%; word-break: break-all; } `); // ================= 核心逻辑 ================= function getCleanTitle() { let text = document.title; if (!text) return null; text = text.replace('(豆瓣)', '').trim(); text = text.replace(/\s\(\d{4}\)$/, ''); return text; } function init() { const movieName = getCleanTitle(); if (!movieName) return; const titleH1 = document.querySelector('h1'); if (!titleH1) return; const btn = document.createElement('span'); btn.className = 'pansou-btn'; btn.innerHTML = '⚡ 搜网盘'; btn.title = `搜索《${movieName}》`; btn.onclick = () => { const url = GM_getValue(STORAGE_KEY_API, ""); if (!url) return alert("请先在油猴菜单中设置 API 地址!"); openModal(movieName); searchResources(movieName, url); }; titleH1.appendChild(btn); createModal(); } function createModal() { if (document.getElementById('pansou-modal-overlay')) return; const div = document.createElement('div'); div.id = 'pansou-modal-overlay'; div.innerHTML = `