网页版tvheadend查询源代码
- 2026-09-24 08:49:30
网页版tvheadend查询源代码此次更新,在网页版查询后直接出频道节目。数量是可以自行填写,可以写12, 10都可以,可选的省份栏,不选就是查全国的,选择就根据自己填写,广西,广东等 

<?php/*** Tvheadend 扫描器 V9.5 - 手动输入省份版* 修复:1. 下拉菜单改为手动输入;2. 自动解决中文乱码;3. 直接输出 M3U 源码*/set_time_limit(0);ini_set('memory_limit', '512M');if (isset($_GET['action']) && $_GET['action'] == 'scan') {header('Content-Type: text/event-stream');header('Cache-Control: no-cache');header('X-Accel-Buffering: no');$data = json_decode(file_get_contents('php://input'), true);$apiKey = $data['key'] ?? '';$query = $data['query'] ?? '';$size = (int)($data['size'] ?? 10);// 1. 请求 Quake 接口$ch = curl_init("https://quake.360.net/api/v3/search/quake_service");curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-QuakeToken: $apiKey", "Content-Type: application/json"]);curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["query" => $query, "start" => 0, "size" => $size]));$response = curl_exec($ch);$result = json_decode($response, true);curl_close($ch);$items = $result['data'] ?? [];$targets = [];foreach ($items as $item) {if (isset($item['ip']) && isset($item['port'])) {$targets[] = $item['ip'] . ":" . $item['port'];}}$targets = array_unique($targets);// 2. 并发探测$mh = curl_multi_init();$ch_list = [];foreach ($targets as $addr) {$url = "http://$addr/playlist/channels";$ch = curl_init($url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_TIMEOUT, 12);curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);curl_multi_add_handle($mh, $ch);$ch_list[$addr] = $ch;}$active = null;do {$mrc = curl_multi_exec($mh, $active);while ($done = curl_multi_info_read($mh)) {$ch = $done['handle'];$addr = array_search($ch, $ch_list);$content = curl_multi_getcontent($ch);$info = curl_getinfo($ch);if ($info['http_code'] == 200 && stripos($content, '#EXTM3U') !== false) {// 处理编码防止乱码$encode = mb_detect_encoding($content, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));if ($encode !== "UTF-8") {$content = mb_convert_encoding($content, "UTF-8", $encode);}echo "####URL:http://$addr/playlist/channels\n";echo "####M3U_DATA:" . base64_encode($content) . "\n";}ob_flush(); flush();curl_multi_remove_handle($mh, $ch);curl_close($ch);}} while ($active && $mrc == CURLM_OK);curl_multi_close($mh);exit;}?><!DOCTYPE html><html><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Tvheadend 源码扫描 V9.5</title><style>body { font-family: -apple-system, sans-serif; background: #f4f7f9; padding: 10px; margin: 0; }.card { background: #fff; border-radius: 12px; padding: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); max-width: 900px; margin: auto; }input, button { width: 100%; padding: 12px; margin: 5px 0; border: 1px solid #ddd; border-radius: 8px; box-sizing: border-box; font-size: 15px; }.btn-primary { background: #007bff; color: white; border: none; font-weight: bold; cursor: pointer; height: 50px; margin-top: 10px; }.btn-copy { background: #28a745; color: white; border: none; font-weight: bold; width: auto; padding: 6px 15px; border-radius: 6px; font-size: 13px; cursor: pointer; display: none; }.results-header { display: none; justify-content: space-between; align-items: center; margin-top: 20px; padding-bottom: 10px; border-bottom: 2px solid #eee; }.res-card { background: #fff; border: 1px solid #e0e6ed; border-left: 6px solid #007bff; border-radius: 10px; margin-bottom: 20px; padding: 12px; }.res-link { display: block; color: #007bff; text-decoration: none; font-size: 14px; font-weight: bold; word-break: break-all; margin-bottom: 10px; }.m3u-content { background: #272822; color: #f8f8f2; padding: 12px; border-radius: 6px; font-family: monospace; font-size: 11px; white-space: pre; overflow: auto; max-height: 250px; line-height: 1.4; border: 1px solid #3e3e3e; }.label-text { font-size: 12px; color: #666; margin-left: 5px; margin-top: 10px; display: block; font-weight: bold; }#status { text-align: center; color: #007bff; font-weight: bold; margin: 10px 0; font-size: 14px; }</style></head><body><divclass="card"><h3style="text-align:center; margin:0 0 15px 0; color:#333;">📺 火锅版Tvheadend扫描</h3><labelclass="label-text">Quake API KEY:</label><inputtype="text"id="key"placeholder="在此输入 API KEY"><divstyle="display:flex; gap:8px;"><divstyle="flex:1;"><labelclass="label-text">输入省份 (可选):</label><inputtype="text"id="province_input"placeholder="如: 广东 / Hong Kong"></div><divstyle="flex:1;"><labelclass="label-text">固定词:</label><inputtype="text"id="query_keyword"value='title: "Tvheadend"'></div><divstyle="width: 70px;"><labelclass="label-text">数量:</label><inputtype="number"id="size"value="10"></div></div><buttonid="btn"class="btn-primary"onclick="startScan()">立即开始抓取</button><divid="status"></div><divid="results-header"class="results-header"><bstyle="font-size:15px; color: #333;">📊 辉煌结果:</b><buttonid="copyBtn"class="btn-copy"onclick="copyAll()">复制所有有效链接</button></div><divid="results"></div></div><script>let allUrls = [];async function startScan() {const btn = document.getElementById('btn');const status = document.getElementById('status');const resultsDiv = document.getElementById('results');const header = document.getElementById('results-header');const copyBtn = document.getElementById('copyBtn');const provValue = document.getElementById('province_input').value.trim();const keyword = document.getElementById('query_keyword').value;// 构建查询语句let finalQuery = provValue ? `province: "${provValue}" AND ${keyword}` : `country: "China" AND ${keyword}`;btn.disabled = true;allUrls = [];resultsDiv.innerHTML = '';header.style.display = 'none';status.innerText = '🚀 正在检索...';try {const response = await fetch('?action=scan', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({key: document.getElementById('key').value,query: finalQuery,size: document.getElementById('size').value})});const reader = response.body.getReader();const decoder = new TextDecoder();let lastCard = null;while (true) {const {done, value} = await reader.read();if (done) break;const text = decoder.decode(value);const lines = text.split('\n');for (let line of lines) {if (line.startsWith('####URL:')) {header.style.display = 'flex';copyBtn.style.display = 'block';const url = line.replace('####URL:', '').trim();allUrls.push(url);lastCard = document.createElement('div');lastCard.className = 'res-card';lastCard.innerHTML = `<a href="${url}" target="_blank" class="res-link">🔗 播放源: ${url}</a>`;resultsDiv.appendChild(lastCard);} else if (line.startsWith('####M3U_DATA:') && lastCard) {// 使用兼容中文的 Base64 解码const m3uContent = decodeURIComponent(escape(atob(line.replace('####M3U_DATA:', '').trim())));const codeBox = document.createElement('div');codeBox.className = 'm3u-content';codeBox.innerText = m3uContent;lastCard.appendChild(codeBox);}}}} catch (e) {status.innerText = '❌ 错误: ' + e;} finally {btn.disabled = false;status.innerText = allUrls.length > 0 ? '✅ 任务结束' : '未发现匹配的地址。';}}function copyAll() {if (allUrls.length === 0) return;navigator.clipboard.writeText(allUrls.join('\n')).then(() => {const cb = document.getElementById('copyBtn');cb.innerText = '✅ 已复制';setTimeout(() => { cb.innerText = '复制所有有效链接'; }, 2000);});}</script></body></html>
本文来自网友投稿或网络内容,如有侵犯您的权益请联系我们删除,联系邮箱:wyl860211@qq.com 。