// 改进的API请求处理函数 async function handleApiRequest(url) { const customApi = url.searchParams.get('customApi') || ''; const source = url.searchParams.get('source') || 'heimuer'; try { if (url.pathname === '/api/search') { const searchQuery = url.searchParams.get('wd'); if (!searchQuery) { throw new Error('缺少搜索参数'); } // 验证API和source的有效性 if (source === 'custom' && !customApi) { throw new Error('使用自定义API时必须提供API地址'); } if (!API_SITES[source] && source !== 'custom') { throw new Error('无效的API来源'); } const apiUrl = customApi ? `${customApi}${API_CONFIG.search.path}${encodeURIComponent(searchQuery)}` : `${API_SITES[source].api}${API_CONFIG.search.path}${encodeURIComponent(searchQuery)}`; // 添加超时处理 const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); try { const response = await fetch(PROXY_URL + encodeURIComponent(apiUrl), { headers: API_CONFIG.search.headers, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`API请求失败: ${response.status}`); } const data = await response.json(); // 检查JSON格式的有效性 if (!data || !Array.isArray(data.list)) { throw new Error('API返回的数据格式无效'); } // 添加源信息到每个结果 data.list.forEach(item => { item.source_name = source === 'custom' ? '自定义源' : API_SITES[source].name; item.source_code = source; // 对于自定义源,添加API URL信息 if (source === 'custom') { item.api_url = customApi; } }); return JSON.stringify({ code: 200, list: data.list || [], }); } catch (fetchError) { clearTimeout(timeoutId); throw fetchError; } } // 详情处理 if (url.pathname === '/api/detail') { const id = url.searchParams.get('id'); const sourceCode = url.searchParams.get('source') || 'heimuer'; // 获取源代码 if (!id) { throw new Error('缺少视频ID参数'); } // 验证ID格式 - 只允许数字和有限的特殊字符 if (!/^[\w-]+$/.test(id)) { throw new Error('无效的视频ID格式'); } // 验证API和source的有效性 if (sourceCode === 'custom' && !customApi) { throw new Error('使用自定义API时必须提供API地址'); } if (!API_SITES[sourceCode] && sourceCode !== 'custom') { throw new Error('无效的API来源'); } // 对于特殊源,使用特殊处理方式 if ((sourceCode === 'ffzy' || sourceCode === 'jisu' || sourceCode === 'huangcang') && API_SITES[sourceCode].detail) { return await handleSpecialSourceDetail(id, sourceCode); } // 如果是自定义API,并且传递了detail参数,尝试特殊处理 if (sourceCode === 'custom' && url.searchParams.get('useDetail') === 'true') { return await handleCustomApiSpecialDetail(id, customApi); } const detailUrl = customApi ? `${customApi}${API_CONFIG.detail.path}${id}` : `${API_SITES[sourceCode].api}${API_CONFIG.detail.path}${id}`; // 添加超时处理 const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); try { const response = await fetch(PROXY_URL + encodeURIComponent(detailUrl), { headers: API_CONFIG.detail.headers, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`详情请求失败: ${response.status}`); } // 解析JSON const data = await response.json(); // 检查返回的数据是否有效 if (!data || !data.list || !Array.isArray(data.list) || data.list.length === 0) { throw new Error('获取到的详情内容无效'); } // 获取第一个匹配的视频详情 const videoDetail = data.list[0]; // 提取播放地址 let episodes = []; if (videoDetail.vod_play_url) { // 分割不同播放源 const playSources = videoDetail.vod_play_url.split('$$$'); // 提取第一个播放源的集数(通常为主要源) if (playSources.length > 0) { const mainSource = playSources[0]; const episodeList = mainSource.split('#'); // 从每个集数中提取URL episodes = episodeList.map(ep => { const parts = ep.split('$'); // 返回URL部分(通常是第二部分,如果有的话) return parts.length > 1 ? parts[1] : ''; }).filter(url => url && (url.startsWith('http://') || url.startsWith('https://'))); } } // 如果没有找到播放地址,尝试使用正则表达式查找m3u8链接 if (episodes.length === 0 && videoDetail.vod_content) { const matches = videoDetail.vod_content.match(M3U8_PATTERN) || []; episodes = matches.map(link => link.replace(/^\$/, '')); } return JSON.stringify({ code: 200, episodes: episodes, detailUrl: detailUrl, videoInfo: { title: videoDetail.vod_name, cover: videoDetail.vod_pic, desc: videoDetail.vod_content, type: videoDetail.type_name, year: videoDetail.vod_year, area: videoDetail.vod_area, director: videoDetail.vod_director, actor: videoDetail.vod_actor, remarks: videoDetail.vod_remarks, // 添加源信息 source_name: sourceCode === 'custom' ? '自定义源' : API_SITES[sourceCode].name, source_code: sourceCode } }); } catch (fetchError) { clearTimeout(timeoutId); throw fetchError; } } throw new Error('未知的API路径'); } catch (error) { console.error('API处理错误:', error); return JSON.stringify({ code: 400, msg: error.message || '请求处理失败', list: [], episodes: [], }); } } // 处理自定义API的特殊详情页 async function handleCustomApiSpecialDetail(id, customApi) { try { // 构建详情页URL const detailUrl = `${customApi}/index.php/vod/detail/id/${id}.html`; // 添加超时处理 const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 获取详情页HTML const response = await fetch(PROXY_URL + encodeURIComponent(detailUrl), { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36', }, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`自定义API详情页请求失败: ${response.status}`); } // 获取HTML内容 const html = await response.text(); // 使用通用模式提取m3u8链接 const generalPattern = /\$(https?:\/\/[^"'\s]+?\.m3u8)/g; let matches = html.match(generalPattern) || []; // 处理链接 matches = matches.map(link => { link = link.substring(1, link.length); const parenIndex = link.indexOf('('); return parenIndex > 0 ? link.substring(0, parenIndex) : link; }); // 提取基本信息 const titleMatch = html.match(/