(源码更新)频道识别台标
https://nbhg.537224.xyz/udpxy/

<?php/****/$web_root = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');define('FFMPEG_PATH', '/www/server/ffmpeg/ffmpeg-6.1/ffmpeg');define('SCREENSHOT_DIR', __DIR__ . '/screenshots');if (!is_dir(SCREENSHOT_DIR)) mkdir(SCREENSHOT_DIR, 0777, true);$action = $_GET['action'] ?? '';// --- 1. 物理清空 ---if ($action === 'clear') {$files = glob(SCREENSHOT_DIR . '/*.jpg');foreach ($files as $file) if (is_file($file)) unlink($file);echo json_encode(['status' => 'ok']);exit;}// --- 2. 增强版 OCR (高精度+区域切片) ---function get_ocr_result($imagePath, $apiKey, $secretKey) {if (empty($apiKey) || empty($secretKey)) return "未命名频道";$auth_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={$apiKey}&client_secret={$secretKey}";$auth_data = json_decode(@file_get_contents($auth_url), true);$token = $auth_data['access_token'] ?? '';if (!$token) return "鉴权失败";$src = imagecreatefromjpeg($imagePath);if($src) {$crop_w = imagesx($src) * 0.25;$crop_h = imagesy($src) * 0.20;$dest = imagecreatetruecolor($crop_w, $crop_h);imagecopy($dest, $src, 0, 0, 10, 10, $crop_w, $crop_h);ob_start();imagejpeg($dest);$img_64 = base64_encode(ob_get_clean());imagedestroy($src);imagedestroy($dest);} else {$img_64 = base64_encode(file_get_contents($imagePath));}$url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=' . $token;$options = ['http' => ['method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n", 'content' => http_build_query(['image' => $img_64])]];$json = json_decode(@file_get_contents($url, false, stream_context_create($options)), true);return !empty($json['words_result']) ? $json['words_result'][0]['words'] : "识别重试";}// --- 3. 核心扫描 ---if ($action === 'scan') {header('Content-Type: application/json');$input = json_decode(file_get_contents("php://input"), true);$targetUrl = $input['url'];$filename = md5($targetUrl) . '.jpg';$savePath = SCREENSHOT_DIR . '/' . $filename;$webPath = $web_root . '/screenshots/' . $filename . '?t=' . time();$cmd = sprintf('%s -y -timeout 5000000 -i %s -ss 00:00:05 -frames:v 1 -q:v 2 %s 2>&1',escapeshellcmd(FFMPEG_PATH), escapeshellarg($targetUrl), escapeshellarg($savePath));exec($cmd);if (file_exists($savePath)) {$ocrName = get_ocr_result($savePath, $input['apiKey'], $input['secretKey']);echo json_encode(['status' => 'ok', 'img' => $webPath, 'url' => $targetUrl, 'name' => $ocrName]);} else {echo json_encode(['status' => 'error']);}exit;}?><!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>火锅版IPTV频道识别器</title><style>:root { --bg: #050505; --card: #111; --cyan: #00f2ff; --gray: #222; --green: #28a745; --orange: #fd7e14; }body { background: var(--bg); color: #ccc; font-family: system-ui, -apple-system, sans-serif; margin: 0; padding-bottom: 90px; }.container { max-width: 1200px; margin: 0 auto; padding: 15px; }.panel { background: var(--card); border: 1px solid var(--gray); border-radius: 12px; padding: 20px; margin-bottom: 20px; }.row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 12px; }input { background: #1a1a1a; border: 1px solid #333; color: #fff; padding: 12px; border-radius: 6px; width: 100%; box-sizing: border-box; }/* 顶部等长等宽按钮组 */.top-btns { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }button { padding: 14px; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; transition: 0.2s; font-size: 14px; }.btn-run { background: var(--cyan); color: #000; }.btn-clear { background: #333; color: #ff4d4d; border: 1px solid #444; }#results { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 15px; }.card { background: var(--card); border: 1px solid var(--gray); border-radius: 8px; overflow: hidden; }.card img { width: 100%; height: 150px; object-fit: cover; background: #000; display: block; }.card-edit { padding: 10px; border-top: 1px solid #222; }.name-edit { background: transparent; border: none; color: var(--cyan); font-size: 16px; font-weight: bold; width: 100%; text-align: center; outline: none; }/* 底部工具栏 - 取消状态文字,保持纯净 */.footer-tools { position: fixed; bottom: 0; left: 0; right: 0; background: rgba(5,5,5,0.9); padding: 15px 20px; border-top: 1px solid #333; backdrop-filter: blur(10px); z-index: 1000; }.export-group { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; max-width: 800px; margin: 0 auto; }.btn-m3u { background: var(--green); color: #fff; }.btn-txt { background: var(--orange); color: #fff; }button:active { opacity: 0.8; transform: scale(0.98); }</style></head><body><divclass="container"><divclass="panel"><divclass="row"><inputtype="text"id="ak"placeholder="百度 API Key"><inputtype="password"id="sk"placeholder="百度 Secret Key"></div><inputtype="text"id="urlTpl"placeholder="URL模板: http://host/live/{ID}.m3u8"style="margin-bottom:12px;"><divclass="row"><inputtype="number"id="sid"value="1"placeholder="Start"><inputtype="number"id="eid"value="10"placeholder="End"></div><divclass="top-btns"><buttonclass="btn-run"id="runBtn"onclick="startScan()">▶ 开始识别</button><buttonclass="btn-clear"onclick="clearServer()">🗑 清空缓存</button></div></div><divid="results"></div></div><divclass="footer-tools"><divclass="export-group"><buttonclass="btn-m3u"onclick="exportFile('m3u')">一键下载 M3U</button><buttonclass="btn-txt"onclick="exportFile('txt')">一键下载 TXT</button></div></div><script>let scanning = false;async function startScan() {if(scanning) return;const tpl = document.getElementById('urlTpl').value;const sid = parseInt(document.getElementById('sid').value);const eid = parseInt(document.getElementById('eid').value);if(!tpl.includes('{ID}')) return alert("模板需含{ID}");scanning = true;const runBtn = document.getElementById('runBtn');runBtn.innerText = "识别中...";for(let i = sid; i <= eid; i++) {if(!scanning) break;const target = tpl.replace('{ID}', i);try {const res = await fetch('?action=scan', {method: 'POST',body: JSON.stringify({url: target,apiKey: document.getElementById('ak').value,secretKey: document.getElementById('sk').value})});const data = await res.json();if(data.status === 'ok') {const div = document.createElement('div');div.className = 'card';div.dataset.url = data.url;div.innerHTML = `<img src="${data.img}"><div class="card-edit"><input type="text" class="name-edit" value="${data.name}"></div>`;document.getElementById('results').prepend(div);}} catch(e) {}}scanning = false;runBtn.innerText = "▶ 开始识别";}function exportFile(type) {const cards = document.querySelectorAll('.card');if(cards.length === 0) return alert("无数据可导出");let content = "";if(type === 'm3u') {content = "#EXTM3U\n";cards.forEach(card => {const name = card.querySelector('.name-edit').value;content += `#EXTINF:-1,${name}\n${card.dataset.url}\n`;});} else {cards.forEach(card => {const name = card.querySelector('.name-edit').value;content += `${name},${card.dataset.url}\n`;});}const blob = new Blob([content], { type: 'text/plain' });const a = document.createElement('a');a.href = URL.createObjectURL(blob);a.download = `playlist.${type}`;a.click();}async function clearServer() {if(!confirm("确定物理删除所有缓存图片吗?")) return;await fetch('?action=clear');document.getElementById('results').innerHTML = '';}</script></body></html>
夜雨聆风