true, CURLOPT_TIMEOUT => 30, CURLOPT_USERAGENT => $ua, CURLOPT_HTTPHEADER => ['Accept: */*'], CURLOPT_RETURNTRANSFER => false, CURLOPT_WRITEFUNCTION => function($ch, $data) { echo $data; flush(); return strlen($data); }, CURLOPT_HEADERFUNCTION => function($ch, $header) { $h = trim($header); if (preg_match('/^Content-Type:/i', $h)) { header($h); } return strlen($header); }, ]); $ok = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (!$ok || $code >= 400) { http_response_code($code ?: 502); } curl_close($ch); } else { // Playlist .m3u8 — fetch + réécriture URLs $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 15, CURLOPT_USERAGENT => $ua, CURLOPT_HTTPHEADER => ['Accept: */*'], CURLOPT_RETURNTRANSFER => true, ]); $body = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($body === false || $code >= 400) { http_response_code($code ?: 502); die("Upstream error $code"); } header('Content-Type: application/vnd.apple.mpegurl'); $proxy_base = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . strtok($_SERVER['REQUEST_URI'], '?') . '?url='; $out = []; foreach (explode("\n", $body) as $line) { $line = rtrim($line); if ($line === '' || $line[0] === '#') { $line = preg_replace_callback('/URI="([^"]+)"/', function($m) use ($base, $proxy_base) { $seg = strpos($m[1], 'http') === 0 ? $m[1] : $base . $m[1]; return 'URI="' . $proxy_base . urlencode($seg) . '"'; }, $line); $out[] = $line; } else { $seg = strpos($line, 'http') === 0 ? $line : $base . $line; $out[] = $proxy_base . urlencode($seg); } } echo implode("\n", $out); }