// ==UserScript== // @name TMDB 影视资源查询 // @namespace http://tampermonkey.net/ // @version 0.0.4 // @description 获取页面影视名称,查询TMDB ID并获取资源链接 // @author goukey // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @connect api.themoviedb.org // @connect api.nullbr.com // @license MIT // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 用户设置,使用GM_getValue获取存储的设置,如果没有则使用默认值 const userSettings = { enableSelectionSearch: GM_getValue('enableSelectionSearch', true), tmdbApiKey: GM_getValue('tmdbApiKey', ''), appId: GM_getValue('appId', ''), apiKey: GM_getValue('apiKey', '') }; // 获取API密钥(兼容旧配置) function getTmdbApiKey() { return userSettings.tmdbApiKey || ''; } function getAppId() { return userSettings.appId || ''; } function getApiKey() { return userSettings.apiKey || ''; } // 保存设置 function saveSettings() { GM_setValue('enableSelectionSearch', userSettings.enableSelectionSearch); GM_setValue('tmdbApiKey', userSettings.tmdbApiKey); GM_setValue('appId', userSettings.appId); GM_setValue('apiKey', userSettings.apiKey); } // 添加样式 GM_addStyle(` :root { --primary-color: #3b82f6; --primary-hover: #2563eb; --bg-color: #ffffff; --text-color: #1f2937; --text-secondary: #6b7280; --border-color: #e5e7eb; --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); --radius-md: 0.5rem; --radius-lg: 0.75rem; } #tmdb-magnet-container { position: fixed; top: 20px; right: 20px; width: 380px; background-color: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); z-index: 10000; font-family: 'Inter', system-ui, -apple-system, sans-serif; display: none; overflow: hidden; border: 1px solid var(--border-color); transition: all 0.3s ease; } /* 顶部 Tab 栏 */ .tmdb-tabs { display: flex; border-bottom: 1px solid var(--border-color); background: #f9fafb; } .tmdb-tab { flex: 1; padding: 12px; text-align: center; cursor: pointer; font-size: 14px; font-weight: 500; color: var(--text-secondary); transition: all 0.2s; border-bottom: 2px solid transparent; } .tmdb-tab:hover { color: var(--primary-color); background: #f3f4f6; } .tmdb-tab.active { color: var(--primary-color); border-bottom-color: var(--primary-color); background: #fff; } .tmdb-close-btn { position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 50%; cursor: pointer; color: #9ca3af; font-size: 18px; line-height: 1; z-index: 10; } .tmdb-close-btn:hover { background: #e5e7eb; color: #4b5563; } /* 内容区域 */ .tmdb-content-area { padding: 16px; height: 500px; overflow-y: auto; display: none; } .tmdb-content-area.active { display: block; } /* 输入框组 */ .input-group { display: flex; gap: 8px; margin-bottom: 16px; } #tmdb-magnet-input { flex: 1; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-md); font-size: 14px; outline: none; transition: border-color 0.2s; } #tmdb-magnet-input:focus { border-color: var(--primary-color); box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); } .search-btn { padding: 8px 16px; background-color: var(--primary-color); color: white; border: none; border-radius: var(--radius-md); font-size: 14px; font-weight: 500; cursor: pointer; transition: background-color 0.2s; } .search-btn:hover { background-color: var(--primary-hover); } /* 筛选按钮 */ .filter-group { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; } .filter-btn { padding: 4px 10px; background: #f3f4f6; border: 1px solid transparent; border-radius: 100px; font-size: 12px; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; } .filter-btn:hover { background: #e5e7eb; color: var(--text-color); } .filter-btn.active { background: #eff6ff; color: var(--primary-color); border-color: var(--primary-color); } /* 结果列表 */ .media-item { background: white; border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 12px; margin-bottom: 12px; display: flex; gap: 12px; transition: transform 0.2s, box-shadow 0.2s; } .media-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: #bfdbfe; } .media-poster { width: 68px; height: 102px; border-radius: 4px; object-fit: cover; background-color: #f3f4f6; flex-shrink: 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .media-details { flex: 1; min-width: 0; } .media-title { font-size: 15px; font-weight: 600; color: var(--text-color); margin-bottom: 6px; display: inline-block; text-decoration: none; } .media-title:hover { color: var(--primary-color); } .media-info { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; } .media-tag { font-size: 11px; padding: 2px 6px; border-radius: 4px; background: #f3f4f6; color: var(--text-secondary); } .media-tag.movie { background: #e0f2fe; color: #0284c7; } .media-tag.tv { background: #f0f9ff; color: #0369a1; } .media-tag.link { cursor: pointer; text-decoration: none; transition: all 0.2s; } .media-tag.link:hover { background: var(--primary-color); color: white; } /* 链接列表 */ .magnet-list { border-top: 1px dashed var(--border-color); padding-top: 8px; margin-top: 8px; } .magnet-link { display: block; padding: 8px; background: #f9fafb; border-radius: var(--radius-md); margin-bottom: 6px; font-size: 12px; text-decoration: none; color: var(--text-color); transition: all 0.2s; border: 1px solid transparent; } .magnet-link:hover { background: #fff; border-color: var(--primary-color); box-shadow: var(--shadow-sm); } .magnet-link a { color: var(--text-color); text-decoration: none; font-weight: 500; display: block; margin-bottom: 2px; } .magnet-link a:hover { color: var(--primary-color); } .loading, .no-results, .error { text-align: center; padding: 20px; font-size: 13px; color: var(--text-secondary); } .error { color: #ef4444; } /* 设置页样式 */ .setting-item { margin-bottom: 16px; } .setting-label { font-size: 13px; font-weight: 500; color: var(--text-color); margin-bottom: 6px; display: block; } .setting-input { width: 100%; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-md); font-size: 13px; outline: none; box-sizing: border-box; transition: border-color 0.2s; } .setting-input:focus { border-color: var(--primary-color); } .toggle-switch { position: relative; display: inline-block; width: 40px; height: 22px; } .toggle-switch input { opacity: 0; width: 0; height: 0; } .toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #e5e7eb; transition: .4s; border-radius: 22px; } .toggle-slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; box-shadow: 0 1px 2px rgba(0,0,0,0.1); } input:checked + .toggle-slider { background-color: var(--primary-color); } input:checked + .toggle-slider:before { transform: translateX(18px); } .save-btn { width: 100%; padding: 10px; background-color: var(--primary-color); color: white; border: none; border-radius: var(--radius-md); font-weight: 500; cursor: pointer; margin-top: 12px; transition: opacity 0.2s; } .save-btn:hover { opacity: 0.9; } /* 悬浮球美化 */ .tmdb-icon { position: fixed; bottom: 30px; right: 30px; width: 48px; height: 48px; background: linear-gradient(135deg, #3b82f6, #2563eb); border-radius: 50%; display: flex; justify-content: center; align-items: center; color: white; font-weight: 700; cursor: pointer; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); z-index: 9998; transition: transform 0.2s; font-size: 14px; } .tmdb-icon:hover { transform: scale(1.1); } /* 滚动条 */ .tmdb-content-area::-webkit-scrollbar { width: 5px; } .tmdb-content-area::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 10px; } .tmdb-content-area::-webkit-scrollbar-thumb:hover { background: #9ca3af; } `); // 创建设置项输入框 function createApiKeyInput(label, key, value, placeholder) { const item = document.createElement('div'); item.style.marginBottom = '12px'; const labelDiv = document.createElement('div'); labelDiv.textContent = label; labelDiv.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 4px;'; const input = document.createElement('input'); input.type = 'text'; input.value = value || ''; input.placeholder = placeholder; input.style.cssText = 'width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 13px; box-sizing: border-box;'; input.addEventListener('input', (e) => { userSettings[key] = e.target.value.trim(); }); item.appendChild(labelDiv); item.appendChild(input); return item; } // 创建UI function createUI() { // 创建主容器 const container = document.createElement('div'); container.id = 'tmdb-magnet-container'; // 1. 关闭按钮 const closeBtn = document.createElement('div'); closeBtn.className = 'tmdb-close-btn'; closeBtn.innerHTML = '×'; closeBtn.title = '关闭'; closeBtn.addEventListener('click', () => { container.style.display = 'none'; }); container.appendChild(closeBtn); // 2. Tab 栏 const tabsContainer = document.createElement('div'); tabsContainer.className = 'tmdb-tabs'; const searchTab = document.createElement('div'); searchTab.className = 'tmdb-tab active'; searchTab.textContent = '影视搜索'; const settingsTab = document.createElement('div'); settingsTab.className = 'tmdb-tab'; settingsTab.textContent = '配置设置'; tabsContainer.appendChild(searchTab); tabsContainer.appendChild(settingsTab); container.appendChild(tabsContainer); // 3. 搜索面板 const searchPanel = document.createElement('div'); searchPanel.className = 'tmdb-content-area active'; searchPanel.id = 'tmdb-search-panel'; // 输入组 const inputGroup = document.createElement('div'); inputGroup.className = 'input-group'; const input = document.createElement('input'); input.id = 'tmdb-magnet-input'; input.type = 'text'; input.placeholder = '输入电影或剧集名称...'; const searchBtn = document.createElement('button'); searchBtn.className = 'search-btn'; searchBtn.textContent = '搜索'; inputGroup.appendChild(input); inputGroup.appendChild(searchBtn); searchPanel.appendChild(inputGroup); // 资源类型切换 const sourceGroup = document.createElement('div'); sourceGroup.className = 'filter-group'; const sourceTypes = [ { label: '🧲 磁力', value: 'magnet' }, { label: '🌐 115', value: '115' }, { label: '⚡ ED2K', value: 'ed2k' }, { label: '▶️ 在线', value: 'm3u8' } ]; const sourceBtns = {}; sourceTypes.forEach(st => { const btn = document.createElement('button'); btn.textContent = st.label; btn.className = 'filter-btn'; if (st.value === 'magnet') btn.classList.add('active'); btn.addEventListener('click', () => { if (currentSource === st.value) return; currentSource = st.value; Object.values(sourceBtns).forEach(b => b.classList.remove('active')); btn.classList.add('active'); // 重新显示结果 if (window._tmdbLastResults) { displayResults(window._tmdbLastResults, false); } }); sourceBtns[st.value] = btn; sourceGroup.appendChild(btn); }); searchPanel.appendChild(sourceGroup); // 类型筛选 const filterGroup = document.createElement('div'); filterGroup.className = 'filter-group'; const filterTypes = [ { label: '全部', value: 'all' }, { label: '电影', value: 'movie' }, { label: '剧集', value: 'tv' } ]; const filterBtns = {}; filterTypes.forEach(ft => { const btn = document.createElement('button'); btn.textContent = ft.label; btn.className = 'filter-btn'; if (ft.value === 'all') btn.classList.add('active'); btn.addEventListener('click', () => { currentFilter = ft.value; Object.values(filterBtns).forEach(b => b.classList.remove('active')); btn.classList.add('active'); if (window._tmdbLastResults) { const magnetCache = saveMagnetCache(); // 保存现有磁链 displayResults(window._tmdbLastResults, false); restoreMagnetCache(magnetCache); // 恢复磁链 } }); filterBtns[ft.value] = btn; filterGroup.appendChild(btn); }); searchPanel.appendChild(filterGroup); // 结果容器 const resultsContainer = document.createElement('div'); resultsContainer.id = 'tmdb-magnet-results'; searchPanel.appendChild(resultsContainer); container.appendChild(searchPanel); // 4. 设置面板 const settingsPanel = document.createElement('div'); settingsPanel.className = 'tmdb-content-area'; settingsPanel.id = 'tmdb-settings-panel'; // 选中搜索开关 const selectionSearchSetting = document.createElement('div'); selectionSearchSetting.className = 'setting-item'; const selectionLabel = document.createElement('span'); selectionLabel.className = 'setting-label'; selectionLabel.textContent = '启用划词搜索 (选中文字弹出搜索按钮)'; selectionLabel.style.marginBottom = '8px'; selectionLabel.style.display = 'inline-block'; const toggleWrapper = document.createElement('div'); const selectionToggle = document.createElement('label'); selectionToggle.className = 'toggle-switch'; const selectionInput = document.createElement('input'); selectionInput.type = 'checkbox'; selectionInput.checked = userSettings.enableSelectionSearch; selectionInput.addEventListener('change', function () { userSettings.enableSelectionSearch = this.checked; saveSettings(); }); const slider = document.createElement('span'); slider.className = 'toggle-slider'; selectionToggle.appendChild(selectionInput); selectionToggle.appendChild(slider); toggleWrapper.appendChild(selectionToggle); selectionSearchSetting.appendChild(selectionLabel); selectionSearchSetting.appendChild(toggleWrapper); settingsPanel.appendChild(selectionSearchSetting); // 分隔线 const divider = document.createElement('hr'); divider.style.cssText = 'border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;'; settingsPanel.appendChild(divider); // API 设置 settingsPanel.appendChild(createApiKeyInput('TMDB API Key', 'tmdbApiKey', userSettings.tmdbApiKey, '请输入 TMDB API Key')); settingsPanel.appendChild(createApiKeyInput('nullbr APP ID', 'appId', userSettings.appId, '请输入 APP ID')); settingsPanel.appendChild(createApiKeyInput('nullbr API Key', 'apiKey', userSettings.apiKey, '请输入 API Key')); // 保存按钮 const saveBtn = document.createElement('button'); saveBtn.className = 'save-btn'; saveBtn.textContent = '保存配置'; saveBtn.addEventListener('click', () => { saveSettings(); const originalText = saveBtn.textContent; saveBtn.textContent = '已保存!'; saveBtn.style.backgroundColor = '#10b981'; setTimeout(() => { saveBtn.textContent = originalText; saveBtn.style.backgroundColor = ''; }, 2000); }); settingsPanel.appendChild(saveBtn); container.appendChild(settingsPanel); // 5. Tab 切换逻辑 searchTab.addEventListener('click', () => { searchTab.classList.add('active'); settingsTab.classList.remove('active'); searchPanel.classList.add('active'); settingsPanel.classList.remove('active'); }); settingsTab.addEventListener('click', () => { settingsTab.classList.add('active'); searchTab.classList.remove('active'); settingsPanel.classList.add('active'); searchPanel.classList.remove('active'); }); // 6. 添加到页面 document.body.appendChild(container); // 悬浮球 const iconBtn = document.createElement('div'); iconBtn.className = 'tmdb-icon'; iconBtn.textContent = '搜源'; iconBtn.title = '打开资源搜索'; iconBtn.addEventListener('click', () => { const display = container.style.display; container.style.display = (display === 'none' || !display) ? 'block' : 'none'; }); document.body.appendChild(iconBtn); // 搜索事件绑定 const triggerSearch = () => { const val = input.value.trim(); if (val) searchTmdb(val); }; searchBtn.addEventListener('click', triggerSearch); input.addEventListener('keypress', (e) => { if (e.key === 'Enter') triggerSearch(); }); } // 保存当前已获取的磁链信息 function saveMagnetCache() { const cache = {}; const movieItems = document.querySelectorAll('.media-item'); movieItems.forEach(item => { const info = item.querySelector('.media-info'); if (info) { const infoText = info.textContent; const idMatch = infoText.match(/TMDB ID: (\d+)/); if (idMatch && idMatch[1]) { const id = idMatch[1]; const type = infoText.includes('电影') ? 'movie' : 'tv'; const magnetList = item.querySelector('.magnet-list'); if (magnetList && !magnetList.querySelector('.loading')) { // 区分来源缓存 const key = `${type}-${id}-${currentSource}`; cache[key] = magnetList.innerHTML; } } } }); return cache; } // 恢复之前已获取的磁链信息 function restoreMagnetCache(cache) { const movieItems = document.querySelectorAll('.media-item'); movieItems.forEach(item => { const info = item.querySelector('.media-info'); if (info) { const infoText = info.textContent; const idMatch = infoText.match(/TMDB ID: (\d+)/); if (idMatch && idMatch[1]) { const id = idMatch[1]; const type = infoText.includes('电影') ? 'movie' : 'tv'; const magnetList = item.querySelector('.magnet-list'); // 获取 magnetList const key = `${type}-${id}-${currentSource}`; // 构建缓存key if (magnetList && cache[key]) { magnetList.innerHTML = cache[key]; } else if (magnetList) { // 如果没有缓存内容或者是新的来源,重新请求 if (currentSource === '115') { get115Links(id, type, magnetList); } else if (currentSource === 'ed2k') { getEd2kLinks(id, type, magnetList); } else if (currentSource === 'm3u8') { getM3u8Links(id, type, magnetList); } else { getMagnetLinks(id, type, magnetList); } } } } }); } // 搜索TMDB API function searchTmdb(query) { const resultsContainer = document.getElementById('tmdb-magnet-results'); resultsContainer.innerHTML = '
正在搜索TMDB...
'; // 构建URL,搜索电影和电视剧 const tmdbKey = getTmdbApiKey(); const movieUrl = `https://api.themoviedb.org/3/search/movie?api_key=${tmdbKey}&query=${encodeURIComponent(query)}&language=zh-CN`; const tvUrl = `https://api.themoviedb.org/3/search/tv?api_key=${tmdbKey}&query=${encodeURIComponent(query)}&language=zh-CN`; // 先搜索电影 GM_xmlhttpRequest({ method: 'GET', url: movieUrl, headers: { 'Accept': 'application/json' }, onload: function (response) { try { const movieData = JSON.parse(response.responseText); // 然后搜索电视剧 GM_xmlhttpRequest({ method: 'GET', url: tvUrl, headers: { 'Accept': 'application/json' }, onload: function (tvResponse) { try { const tvData = JSON.parse(tvResponse.responseText); // 合并结果 const results = [ ...movieData.results.map(item => ({ ...item, type: 'movie' })), ...tvData.results.map(item => ({ ...item, type: 'tv' })) ]; // 显示结果 displayResults(results); } catch (error) { showError('解析电视剧数据失败: ' + error.message); } }, onerror: function () { showError('获取电视剧数据失败'); } }); } catch (error) { showError('解析电影数据失败: ' + error.message); } }, onerror: function () { showError('获取电影数据失败'); } }); } // 显示搜索结果 function displayResults(results, skipMagnet) { const resultsContainer = document.getElementById('tmdb-magnet-results'); window._tmdbLastResults = results; // 用于筛选切换时重渲染 if (!results || results.length === 0) { resultsContainer.innerHTML = '
未找到相关影视作品
'; return; } // 清空容器 resultsContainer.innerHTML = ''; // 根据筛选类型过滤 let filteredResults = results; if (typeof currentFilter !== 'undefined' && currentFilter !== 'all') { filteredResults = results.filter(item => item.type === currentFilter); } if (filteredResults.length === 0) { resultsContainer.innerHTML = '
筛选后无结果
'; return; } // 展示全部结果(不再限制5条) for (const item of filteredResults) { const resultItem = document.createElement('div'); resultItem.className = 'media-item'; // TMDB 详情链接基础 URL const tmdbDetailUrl = `https://www.themoviedb.org/${item.type}/${item.id}`; // 左侧封面图 const posterLink = document.createElement('a'); posterLink.href = tmdbDetailUrl; posterLink.target = '_blank'; const poster = document.createElement('img'); poster.className = 'media-poster'; poster.src = item.poster_path ? `https://image.tmdb.org/t/p/w92${item.poster_path}` : 'https://via.placeholder.com/68x102?text=No+Poster'; poster.alt = item.type === 'movie' ? item.title : item.name; posterLink.appendChild(poster); resultItem.appendChild(posterLink); // 右侧详情区 const details = document.createElement('div'); details.className = 'media-details'; // 标题 (也是链接) const title = document.createElement('a'); title.className = 'media-title'; title.href = tmdbDetailUrl; title.target = '_blank'; title.textContent = item.type === 'movie' ? item.title : item.name; // 信息 const info = document.createElement('div'); info.className = 'media-info'; // 添加年份 let year = ''; if (item.type === 'movie' && item.release_date) { year = new Date(item.release_date).getFullYear(); } else if (item.type === 'tv' && item.first_air_date) { year = new Date(item.first_air_date).getFullYear(); } // 创建类型标签 const typeSpan = document.createElement('span'); typeSpan.textContent = item.type === 'movie' ? '电影' : '剧集'; typeSpan.className = `media-tag ${item.type}`; // 创建年份标签 const yearSpan = document.createElement('span'); yearSpan.textContent = year || '未知年份'; yearSpan.className = 'media-tag'; yearSpan.style.background = '#f3f4f6'; // 创建TMDB ID标签 (也是链接) const idLink = document.createElement('a'); idLink.href = tmdbDetailUrl; idLink.target = '_blank'; idLink.className = 'media-tag link'; idLink.textContent = `TMDB ID: ${item.id}`; idLink.style.background = '#f3f4f6'; // 添加标签到信息区 info.appendChild(typeSpan); info.appendChild(yearSpan); info.appendChild(idLink); // 磁力链接区域 const magnetList = document.createElement('div'); magnetList.className = 'magnet-list'; magnetList.innerHTML = `
获取${getSourceName(currentSource)}中...
`; // 组装内容到详情区 details.appendChild(title); details.appendChild(info); details.appendChild(magnetList); // 添加详情区到主容器 resultItem.appendChild(details); // 添加到结果容器 resultsContainer.appendChild(resultItem); // 获取资源 if (!skipMagnet) { if (currentSource === '115') { get115Links(item.id, item.type, magnetList); } else if (currentSource === 'ed2k') { getEd2kLinks(item.id, item.type, magnetList); } else if (currentSource === 'm3u8') { getM3u8Links(item.id, item.type, magnetList); } else { getMagnetLinks(item.id, item.type, magnetList); } } } } // 获取磁力链接 function getMagnetLinks(tmdbId, type, container) { if (type === 'movie') { // 电影:用movie接口 const url = `https://api.nullbr.com/movie/${tmdbId}`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId() }, onload: function (response) { try { const data = JSON.parse(response.responseText); if (data['magnet-flg'] === 1) { getMovieMagnets(tmdbId, container); } else { container.innerHTML = '
未找到磁力链接
'; } } catch (error) { container.innerHTML = `
解析电影信息失败: ${error.message}`; } }, onerror: function () { container.innerHTML = '
获取电影信息失败
'; } }); } else if (type === 'tv') { // 剧集:用tv接口,自动获取所有季和集的magnet标志 const url = `https://api.nullbr.com/tv/${tmdbId}`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId() }, onload: function (response) { try { const data = JSON.parse(response.responseText); if (!data.number_of_seasons || data.number_of_seasons < 1) { container.innerHTML = '
未找到季信息
'; return; } // 展示所有季 container.innerHTML = ''; for (let season = 1; season <= data.number_of_seasons; season++) { getSeasonMagnets(tmdbId, season, container); } } catch (error) { container.innerHTML = `
解析剧集信息失败: ${error.message}`; } }, onerror: function () { container.innerHTML = '
获取剧集信息失败
'; } }); } } // 获取115网盘资源 function get115Links(tmdbId, type, container) { const url = `https://api.nullbr.com/${type}/${tmdbId}/115`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId(), 'X-API-KEY': getApiKey() }, onload: function (response) { try { const data = JSON.parse(response.responseText); if (data && data['115'] && Array.isArray(data['115']) && data['115'].length > 0) { container.innerHTML = ''; data['115'].forEach(item => { const linkItem = document.createElement('div'); linkItem.className = 'magnet-link'; // 创建链接 const link = document.createElement('a'); link.href = item.share_link; link.target = '_blank'; link.title = item.title; link.textContent = item.title; link.style.color = '#2ecc71'; // 115链接使用绿色区分 // 创建信息标签 const infoSpan = document.createElement('div'); infoSpan.style.fontSize = '12px'; infoSpan.style.color = '#888'; infoSpan.style.marginTop = '3px'; // 添加文件大小 if (item.size) { const sizeSpan = document.createElement('span'); sizeSpan.textContent = item.size; sizeSpan.style.marginRight = '8px'; infoSpan.appendChild(sizeSpan); } // 添加分辨率 if (item.resolution) { const resSpan = document.createElement('span'); resSpan.textContent = item.resolution; resSpan.style.backgroundColor = '#f0f0f0'; resSpan.style.padding = '1px 5px'; resSpan.style.borderRadius = '3px'; resSpan.style.marginRight = '5px'; infoSpan.appendChild(resSpan); } // 添加质量 if (item.quality) { const qualitySpan = document.createElement('span'); qualitySpan.textContent = item.quality; qualitySpan.style.backgroundColor = '#f0f0f0'; qualitySpan.style.padding = '1px 5px'; qualitySpan.style.borderRadius = '3px'; qualitySpan.style.marginRight = '5px'; infoSpan.appendChild(qualitySpan); } // 剧集显示季列表 if (item.season_list && Array.isArray(item.season_list) && item.season_list.length > 0) { const seasonSpan = document.createElement('span'); seasonSpan.textContent = item.season_list.join(', '); seasonSpan.style.backgroundColor = '#e8f5e9'; seasonSpan.style.color = '#2e7d32'; seasonSpan.style.padding = '1px 5px'; seasonSpan.style.borderRadius = '3px'; infoSpan.appendChild(seasonSpan); } linkItem.appendChild(link); linkItem.appendChild(infoSpan); container.appendChild(linkItem); }); } else { container.innerHTML = '
未找到115资源
'; } } catch (error) { container.innerHTML = `
解析115资源失败: ${error.message}
`; } }, onerror: function () { container.innerHTML = '
获取115资源失败
'; } }); } // 获取电影磁力资源 function getMovieMagnets(tmdbId, container) { const url = `https://api.nullbr.com/movie/${tmdbId}/magnet`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId(), 'X-API-KEY': getApiKey() }, onload: function (response) { try { const data = JSON.parse(response.responseText); if (Array.isArray(data.magnet) && data.magnet.length > 0) { container.innerHTML = ''; data.magnet.forEach(item => { const magnetItem = document.createElement('div'); magnetItem.className = 'magnet-link'; // 创建链接 const link = document.createElement('a'); link.href = item.magnet; link.target = '_blank'; link.title = item.magnet; link.textContent = item.name; // 创建信息标签 const infoSpan = document.createElement('div'); infoSpan.style.fontSize = '12px'; infoSpan.style.color = '#888'; infoSpan.style.marginTop = '3px'; // 添加文件大小 const sizeSpan = document.createElement('span'); sizeSpan.textContent = item.size; sizeSpan.style.marginRight = '8px'; infoSpan.appendChild(sizeSpan); // 添加分辨率 if (item.resolution) { const resSpan = document.createElement('span'); resSpan.textContent = item.resolution; resSpan.style.backgroundColor = '#f0f0f0'; resSpan.style.padding = '1px 5px'; resSpan.style.borderRadius = '3px'; resSpan.style.marginRight = '5px'; infoSpan.appendChild(resSpan); } // 添加来源 if (item.source) { const sourceSpan = document.createElement('span'); sourceSpan.textContent = item.source; sourceSpan.style.backgroundColor = '#f0f0f0'; sourceSpan.style.padding = '1px 5px'; sourceSpan.style.borderRadius = '3px'; sourceSpan.style.marginRight = '5px'; infoSpan.appendChild(sourceSpan); } // 添加质量 if (item.quality) { const qualityText = Array.isArray(item.quality) ? item.quality.join(',') : item.quality; if (qualityText) { const qualitySpan = document.createElement('span'); qualitySpan.textContent = qualityText; qualitySpan.style.backgroundColor = '#f0f0f0'; qualitySpan.style.padding = '1px 5px'; qualitySpan.style.borderRadius = '3px'; infoSpan.appendChild(qualitySpan); } } // 添加中文字幕标记 if (item.zh_sub === 1) { const zhSpan = document.createElement('span'); zhSpan.textContent = '中字'; zhSpan.style.backgroundColor = '#4caf50'; zhSpan.style.color = 'white'; zhSpan.style.padding = '1px 5px'; zhSpan.style.borderRadius = '3px'; zhSpan.style.marginLeft = '5px'; infoSpan.appendChild(zhSpan); } // 组装磁力项 magnetItem.appendChild(link); magnetItem.appendChild(infoSpan); container.appendChild(magnetItem); }); } else { container.innerHTML = '
未找到磁力资源
'; } } catch (error) { container.innerHTML = `
解析磁力资源失败: ${error.message}
`; } }, onerror: function () { container.innerHTML = '
获取磁力资源失败
'; } }); } // 获取某一季的磁力资源(不再请求单集磁力) function getSeasonMagnets(tmdbId, season, container) { const url = `https://api.nullbr.com/tv/${tmdbId}/season/${season}/magnet`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId(), 'X-API-KEY': getApiKey() }, onload: function (response) { try { const data = JSON.parse(response.responseText); // 创建季标题 const seasonHeader = document.createElement('div'); seasonHeader.style.marginTop = '12px'; seasonHeader.style.marginBottom = '8px'; seasonHeader.style.fontWeight = '600'; seasonHeader.style.display = 'flex'; seasonHeader.style.alignItems = 'center'; const seasonBadge = document.createElement('span'); seasonBadge.textContent = `第${season}季`; seasonBadge.style.backgroundColor = '#0d253f'; seasonBadge.style.color = 'white'; seasonBadge.style.padding = '2px 8px'; seasonBadge.style.borderRadius = '4px'; seasonBadge.style.fontSize = '13px'; seasonHeader.appendChild(seasonBadge); container.appendChild(seasonHeader); // 创建磁力链接列表 const magnetContainer = document.createElement('div'); magnetContainer.style.marginLeft = '10px'; if (Array.isArray(data.magnet) && data.magnet.length > 0) { data.magnet.forEach(item => { const magnetItem = document.createElement('div'); magnetItem.className = 'magnet-link'; // 创建链接 const link = document.createElement('a'); link.href = item.magnet; link.target = '_blank'; link.title = item.magnet; link.textContent = item.name; // 创建信息标签 const infoSpan = document.createElement('div'); infoSpan.style.fontSize = '12px'; infoSpan.style.color = '#888'; infoSpan.style.marginTop = '3px'; // 添加文件大小 const sizeSpan = document.createElement('span'); sizeSpan.textContent = item.size; sizeSpan.style.marginRight = '8px'; infoSpan.appendChild(sizeSpan); // 添加分辨率 if (item.resolution) { const resSpan = document.createElement('span'); resSpan.textContent = item.resolution; resSpan.style.backgroundColor = '#f0f0f0'; resSpan.style.padding = '1px 5px'; resSpan.style.borderRadius = '3px'; resSpan.style.marginRight = '5px'; infoSpan.appendChild(resSpan); } // 添加来源 if (item.source) { const sourceSpan = document.createElement('span'); sourceSpan.textContent = item.source; sourceSpan.style.backgroundColor = '#f0f0f0'; sourceSpan.style.padding = '1px 5px'; sourceSpan.style.borderRadius = '3px'; sourceSpan.style.marginRight = '5px'; infoSpan.appendChild(sourceSpan); } // 添加质量 if (item.quality) { const qualityText = Array.isArray(item.quality) ? item.quality.join(',') : item.quality; if (qualityText) { const qualitySpan = document.createElement('span'); qualitySpan.textContent = qualityText; qualitySpan.style.backgroundColor = '#f0f0f0'; qualitySpan.style.padding = '1px 5px'; qualitySpan.style.borderRadius = '3px'; infoSpan.appendChild(qualitySpan); } } // 添加中文字幕标记 if (item.zh_sub === 1) { const zhSpan = document.createElement('span'); zhSpan.textContent = '中字'; zhSpan.style.backgroundColor = '#4caf50'; zhSpan.style.color = 'white'; zhSpan.style.padding = '1px 5px'; zhSpan.style.borderRadius = '3px'; zhSpan.style.marginLeft = '5px'; infoSpan.appendChild(zhSpan); } // 组装磁力项 magnetItem.appendChild(link); magnetItem.appendChild(infoSpan); magnetContainer.appendChild(magnetItem); }); } else { const noResults = document.createElement('div'); noResults.className = 'no-results'; noResults.style.margin = '5px 0'; noResults.textContent = '未找到磁力资源'; magnetContainer.appendChild(noResults); } container.appendChild(magnetContainer); } catch (error) { const errDiv = document.createElement('div'); errDiv.className = 'error'; errDiv.textContent = `解析第${season}季磁力资源失败: ${error.message}`; container.appendChild(errDiv); } }, onerror: function () { const errDiv = document.createElement('div'); errDiv.className = 'error'; errDiv.textContent = `获取第${season}季磁力资源失败`; container.appendChild(errDiv); } }); } // 获取ED2K资源 function getEd2kLinks(tmdbId, type, container) { if (type === 'tv') { container.innerHTML = '
剧集暂不支持ED2K批量获取,请使用磁力或115
'; return; } const url = `https://api.nullbr.com/${type}/${tmdbId}/ed2k`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId(), 'X-API-KEY': getApiKey() }, onload: function (response) { try { const data = JSON.parse(response.responseText); if (data && data.ed2k && Array.isArray(data.ed2k) && data.ed2k.length > 0) { container.innerHTML = ''; // 排序:有中文字幕的优先 data.ed2k.sort((a, b) => (b.zh_sub || 0) - (a.zh_sub || 0)); data.ed2k.forEach(item => { const linkItem = document.createElement('div'); linkItem.className = 'magnet-link'; const link = document.createElement('a'); link.href = item.ed2k; link.textContent = item.name; link.style.color = '#e67e22'; // ED2K使用橙色 const infoSpan = document.createElement('div'); infoSpan.style.fontSize = '12px'; infoSpan.style.color = '#888'; infoSpan.style.marginTop = '3px'; if (item.size) { const sizeSpan = document.createElement('span'); sizeSpan.textContent = item.size; sizeSpan.style.marginRight = '8px'; infoSpan.appendChild(sizeSpan); } if (item.resolution) { const resSpan = document.createElement('span'); resSpan.textContent = item.resolution; resSpan.style.backgroundColor = '#f0f0f0'; resSpan.style.padding = '1px 5px'; resSpan.style.borderRadius = '3px'; resSpan.style.marginRight = '5px'; infoSpan.appendChild(resSpan); } if (item.zh_sub === 1) { const zhSpan = document.createElement('span'); zhSpan.textContent = '中字'; zhSpan.style.backgroundColor = '#4caf50'; zhSpan.style.color = 'white'; zhSpan.style.padding = '1px 5px'; zhSpan.style.borderRadius = '3px'; infoSpan.appendChild(zhSpan); } linkItem.appendChild(link); linkItem.appendChild(infoSpan); container.appendChild(linkItem); }); } else { container.innerHTML = '
未找到ED2K资源
'; } } catch (error) { container.innerHTML = `
解析ED2K失败: ${error.message}
`; } }, onerror: function () { container.innerHTML = '
获取ED2K资源失败
'; } }); } // 获取M3U8/在线资源 function getM3u8Links(tmdbId, type, container) { if (type === 'tv') { container.innerHTML = '
剧集暂不支持在线资源批量获取,请使用磁力或115
'; return; } const url = `https://api.nullbr.com/${type}/${tmdbId}/video`; GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json', 'X-APP-ID': getAppId(), 'X-API-KEY': getApiKey() }, onload: function (response) { try { const data = JSON.parse(response.responseText); if (data && data.video && Array.isArray(data.video) && data.video.length > 0) { container.innerHTML = ''; data.video.forEach(item => { const linkItem = document.createElement('div'); linkItem.className = 'magnet-link'; const link = document.createElement('a'); link.href = item.link; link.target = '_blank'; link.textContent = `[${item.name}] ${item.source}`; link.style.color = '#e74c3c'; // M3U8使用红色 const infoSpan = document.createElement('div'); infoSpan.style.fontSize = '12px'; infoSpan.style.color = '#888'; infoSpan.style.marginTop = '3px'; const typeSpan = document.createElement('span'); typeSpan.textContent = item.type.toUpperCase(); typeSpan.style.backgroundColor = '#f0f0f0'; typeSpan.style.padding = '1px 5px'; typeSpan.style.borderRadius = '3px'; infoSpan.appendChild(typeSpan); linkItem.appendChild(link); linkItem.appendChild(infoSpan); container.appendChild(linkItem); }); } else { container.innerHTML = '
未找到在线资源
'; } } catch (error) { container.innerHTML = `
解析在线资源失败: ${error.message}
`; } }, onerror: function () { container.innerHTML = '
获取在线资源失败
'; } }); } // 获取资源名称辅助函数 function getSourceName(source) { switch (source) { case '115': return '115资源'; case 'ed2k': return 'ED2K资源'; case 'm3u8': return '在线资源'; default: return '磁力链接'; } } // 显示错误信息 function showError(message) { const resultsContainer = document.getElementById('tmdb-magnet-results'); resultsContainer.innerHTML = `
${message}
`; } // 当页面加载完成后创建UI window.addEventListener('load', function () { // 延迟1秒加载UI,确保页面已完全加载 setTimeout(createUI, 1000); }); // 选中弹出悬浮搜索按钮 let searchBtn = null; let lastSelection = ''; let currentFilter = 'all'; // 提升为全局变量 let currentSource = 'magnet'; // 当前资源来源,默认为磁力 function removeSearchBtn() { if (searchBtn && searchBtn.parentNode) { searchBtn.parentNode.removeChild(searchBtn); searchBtn = null; } } document.addEventListener('selectionchange', function () { // 如果用户关闭了选中搜索功能,则不显示搜索按钮 if (!userSettings.enableSelectionSearch) { removeSearchBtn(); return; } removeSearchBtn(); const sel = window.getSelection(); if (!sel || sel.isCollapsed) return; const text = sel.toString().trim(); if (!text) return; lastSelection = text; const range = sel.getRangeAt(0); const rect = range.getBoundingClientRect(); // 创建按钮 searchBtn = document.createElement('button'); searchBtn.textContent = '🔍 搜索资源'; searchBtn.style.position = 'fixed'; searchBtn.style.zIndex = 99999; searchBtn.style.left = (rect.right + 10) + 'px'; searchBtn.style.top = (rect.top - 10) + 'px'; searchBtn.style.background = 'linear-gradient(120deg, #00C6FF 0%, #0072FF 100%)'; searchBtn.style.color = '#fff'; searchBtn.style.border = 'none'; searchBtn.style.borderRadius = '50px'; searchBtn.style.padding = '8px 16px'; searchBtn.style.cursor = 'pointer'; searchBtn.style.boxShadow = '0 4px 15px rgba(0, 114, 255, 0.4)'; searchBtn.style.fontSize = '14px'; searchBtn.style.fontWeight = '600'; searchBtn.style.transition = 'all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)'; searchBtn.style.backdropFilter = 'blur(4px)'; searchBtn.onmousedown = e => e.preventDefault(); // 防止失去选区 searchBtn.onmouseover = function () { this.style.transform = 'scale(1.05)'; this.style.boxShadow = '0 4px 12px rgba(0,0,0,0.25)'; }; searchBtn.onmouseout = function () { this.style.transform = 'scale(1)'; this.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)'; }; searchBtn.onclick = function (e) { e.stopPropagation(); removeSearchBtn(); showTmdbPanelWithText(lastSelection); }; document.body.appendChild(searchBtn); }); document.addEventListener('mousedown', function (e) { if (searchBtn && !searchBtn.contains(e.target)) { removeSearchBtn(); } }); // 自动填入并弹出面板 function showTmdbPanelWithText(text) { const container = document.getElementById('tmdb-magnet-container'); if (container) container.style.display = 'block'; const input = document.getElementById('tmdb-magnet-input'); if (input) { input.value = text; // 自动搜索 searchTmdb(text); } } })();