// ==UserScript== // @name UBits 智能电影过滤器 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 可自定义过滤条件的电影过滤器,支持设置最低评分和N/A处理,可配置统计窗口 // @author Dost // @match https://ubits.club/torrents* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 默认配置 const DEFAULT_CONFIG = { minIMDbRating: 6.1, minDoubanRating: 6.5, removeNA: false, removeOnlyAllNA: true, requireBothRatings: false, showDebugInfo: true, enabled: true, showNotification: true, notificationDuration: 8 }; // 加载保存的配置 let FILTER_CONFIG; try { FILTER_CONFIG = Object.assign({}, DEFAULT_CONFIG, JSON.parse(GM_getValue('UBitsFilterConfig', '{}'))); } catch (e) { FILTER_CONFIG = Object.assign({}, DEFAULT_CONFIG); console.error('Failed to load saved config, using defaults', e); } // 注册菜单命令 GM_registerMenuCommand('配置UBits电影过滤器', showConfigUI); // 主函数 function main() { if (!FILTER_CONFIG.enabled) { console.log('UBits电影过滤器已禁用'); return; } addConfigButton(); applyFilters(); } // 应用过滤器 function applyFilters() { const stats = { totalChecked: 0, totalRemoved: 0, removedByLowIMDb: 0, removedByLowDouban: 0, removedByNA: 0, removedByMissingRating: 0 }; const rows = document.querySelectorAll('tr:has(> td > div[style*="display: flex; flex-direction: column"])'); rows.forEach(tr => { stats.totalChecked++; const ratingContainer = tr.querySelector('div[style*="display: flex; flex-direction: column"]'); if (!ratingContainer) return; const ratingSpans = ratingContainer.querySelectorAll('span'); const imdbRating = parseRating(ratingSpans[0]?.textContent); const doubanRating = ratingSpans[1] ? parseRating(ratingSpans[1]?.textContent) : null; let shouldRemove = false; const removeReasons = []; // 检查双评分要求 if (FILTER_CONFIG.requireBothRatings && (!imdbRating.valid || !doubanRating?.valid)) { shouldRemove = true; removeReasons.push('缺少有效评分'); stats.removedByMissingRating++; } // 检查N/A if (FILTER_CONFIG.removeNA) { const imdbNA = imdbRating.isNA; const doubanNA = doubanRating ? doubanRating.isNA : true; if (FILTER_CONFIG.removeOnlyAllNA) { // 仅当两个评分都是NA时才删除 if (imdbNA && doubanNA) { shouldRemove = true; removeReasons.push('双评分均为N/A'); stats.removedByNA++; } } else { // 任意一个评分为NA就删除 if (imdbNA || doubanNA) { shouldRemove = true; removeReasons.push('存在N/A评分'); stats.removedByNA++; } } } // 检查IMDb评分 if (FILTER_CONFIG.minIMDbRating > 0 && imdbRating.valid && imdbRating.value < FILTER_CONFIG.minIMDbRating) { shouldRemove = true; removeReasons.push(`IMDb ${imdbRating.value} < ${FILTER_CONFIG.minIMDbRating}`); stats.removedByLowIMDb++; } // 检查豆瓣评分 if (doubanRating && FILTER_CONFIG.minDoubanRating > 0 && doubanRating.valid && doubanRating.value < FILTER_CONFIG.minDoubanRating) { shouldRemove = true; removeReasons.push(`豆瓣 ${doubanRating.value} < ${FILTER_CONFIG.minDoubanRating}`); stats.removedByLowDouban++; } if (shouldRemove) { if (FILTER_CONFIG.showDebugInfo) { console.log(`删除项目: ${removeReasons.join('; ')}`, tr); } tr.style.display = 'none'; tr.dataset.filtered = 'true'; stats.totalRemoved++; } }); showResults(stats); } function parseRating(ratingText) { if (!ratingText) return { valid: false, isNA: true }; const text = ratingText.trim(); if (text === 'N/A' || text === '' || text === '-') { return { valid: false, isNA: true }; } const value = parseFloat(text); if (isNaN(value)) { return { valid: false, isNA: true }; } return { valid: true, isNA: false, value: value }; } function showResults(stats) { const resultLines = [ `UBits电影过滤结果 (共检查 ${stats.totalChecked} 个项目)`, `-------------------------------------`, `隐藏总数: ${stats.totalRemoved}`, ...(stats.removedByLowIMDb > 0 ? [`- IMDb评分过低: ${stats.removedByLowIMDb}`] : []), ...(stats.removedByLowDouban > 0 ? [`- 豆瓣评分过低: ${stats.removedByLowDouban}`] : []), ...(stats.removedByNA > 0 ? [`- N/A评分: ${stats.removedByNA}`] : []), ...(stats.removedByMissingRating > 0 ? [`- 缺少有效评分: ${stats.removedByMissingRating}`] : []), `-------------------------------------`, `当前过滤条件:`, `- 最低IMDb评分: ${FILTER_CONFIG.minIMDbRating > 0 ? FILTER_CONFIG.minIMDbRating : '不限制'}`, `- 最低豆瓣评分: ${FILTER_CONFIG.minDoubanRating > 0 ? FILTER_CONFIG.minDoubanRating : '不限制'}`, `- 删除N/A: ${FILTER_CONFIG.removeNA ? (FILTER_CONFIG.removeOnlyAllNA ? '仅双N/A' : '任意N/A') : '否'}`, `- 要求双评分: ${FILTER_CONFIG.requireBothRatings ? '是' : '否'}`, `- 过滤器状态: ${FILTER_CONFIG.enabled ? '启用' : '禁用'}` ]; const resultMsg = resultLines.join('\n'); console.log(resultMsg); if (FILTER_CONFIG.showNotification) { showNotification(resultMsg, FILTER_CONFIG.notificationDuration * 1000); } } function showNotification(message, duration = 8000) { const existing = document.getElementById('ubits-filter-notification'); if (existing) existing.remove(); const notification = document.createElement('div'); notification.id = 'ubits-filter-notification'; notification.style.cssText = ` position: fixed; top: 10px; right: 10px; background-color: #f8f9fa; color: #212529; padding: 12px; border-radius: 5px; z-index: 9999; box-shadow: 0 0 15px rgba(0,0,0,0.2); max-width: 320px; font-family: Arial, sans-serif; font-size: 14px; line-height: 1.5; white-space: pre-line; border-left: 4px solid #6c757d; transform: translateX(120%); transition: transform 0.3s ease-out; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.style.transform = 'translateX(0)'; }, 100); let hideTimer; const startHideTimer = () => { hideTimer = setTimeout(() => { notification.style.transition = 'opacity 1s'; notification.style.opacity = '0'; setTimeout(() => notification.remove(), 1000); }, duration); }; notification.addEventListener('mouseenter', () => { clearTimeout(hideTimer); notification.style.opacity = '1'; }); notification.addEventListener('mouseleave', startHideTimer); startHideTimer(); } function addConfigButton() { const existing = document.getElementById('ubits-filter-config-btn'); if (existing) existing.remove(); const btn = document.createElement('button'); btn.id = 'ubits-filter-config-btn'; btn.textContent = '⚙️ 过滤器配置'; btn.style.cssText = ` position: fixed; bottom: 20px; right: 20px; z-index: 9998; padding: 8px 15px; background: #6c757d; color: white; border: none; border-radius: 20px; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.2); font-family: Arial, sans-serif; `; btn.addEventListener('click', showConfigUI); document.body.appendChild(btn); } function showConfigUI() { const existing = document.getElementById('ubits-filter-config-dialog'); if (existing) existing.remove(); const dialog = document.createElement('div'); dialog.id = 'ubits-filter-config-dialog'; dialog.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; z-index: 10000; box-shadow: 0 0 20px rgba(0,0,0,0.3); border-radius: 8px; width: 350px; max-width: 90%; font-family: Arial, sans-serif; `; dialog.innerHTML = `