<?php
error_reporting(0);
set_time_limit(0);
ob_end_clean();

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Range, Origin, Accept, Content-Type, User-Agent');
header('Access-Control-Expose-Headers: Content-Length, Content-Range, Content-Type, Location');
if (strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'OPTIONS') {
    http_response_code(204);
    exit;
}

function spandaman_proxy_bad_media_bytes($bytes) {
    if ($bytes === false || $bytes === '') {
        return true;
    }
    $prefix = substr($bytes, 0, 64);
    if (strncmp($prefix, "\x89PNG", 4) === 0 || substr($prefix, 4, 4) === 'IHDR' || strpos($prefix, 'IEND') !== false || strncmp($prefix, "\xFF\xD8\xFF", 3) === 0 || strncmp($prefix, "GIF87a", 6) === 0 || strncmp($prefix, "GIF89a", 6) === 0 || strncmp($prefix, "RIFF", 4) === 0 && substr($prefix, 8, 4) === 'WEBP') {
        return true;
    }
    $trim = ltrim($prefix);
    if (stripos($trim, '<!doctype') === 0 || stripos($trim, '<html') === 0 || stripos($trim, '<?xml') === 0 || strpos($trim, '{') === 0 || strpos($trim, '[') === 0) {
        return true;
    }
    return false;
}

function spandaman_proxy_content_type_is_bad($contentType) {
    $ct = strtolower((string)$contentType);
    return strpos($ct, 'image/') === 0 || strpos($ct, 'text/html') !== false || strpos($ct, 'application/json') !== false || strpos($ct, 'text/plain') !== false;
}

function spandaman_proxy_user_agent() {
    $ua = trim((string)($_SERVER['HTTP_USER_AGENT'] ?? ''));
    if ($ua !== '') {
        return $ua;
    }
    return 'XCIPTV/7.0 (Linux; Android 11) ExoPlayerLib/2.15.1';
}

function spandaman_proxy_origin_headers($url) {
    $headers = [
        'Accept: video/*,application/vnd.apple.mpegurl,application/x-mpegURL,application/octet-stream,*/*',
        'Connection: keep-alive',
    ];
    $scheme = parse_url($url, PHP_URL_SCHEME) ?: 'https';
    $host = parse_url($url, PHP_URL_HOST);
    if ($host) {
        $origin = $scheme . '://' . $host;
        $headers[] = 'Origin: ' . $origin;
        $headers[] = 'Referer: ' . $origin . '/';
    }
    return $headers;
}

function spandaman_proxy_media_preflight($url) {
    if (!function_exists('curl_init')) {
        return [true, 'curl unavailable'];
    }
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 8,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 16,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_RANGE => '0-1023',
        CURLOPT_USERAGENT => spandaman_proxy_user_agent(),
        CURLOPT_HTTPHEADER => spandaman_proxy_origin_headers($url),
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => 0,
    ]);
    $bytes = curl_exec($ch);
    $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    $ct = (string)curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
    $err = curl_error($ch);
    curl_close($ch);
    if ($bytes === false || $code >= 400 || $code < 200) {
        return [false, 'preflight http ' . $code . ($err ? ' ' . $err : '')];
    }
    if (spandaman_proxy_content_type_is_bad($ct) || spandaman_proxy_bad_media_bytes($bytes)) {
        return [false, 'preflight rejected non-video bytes/content-type ' . $ct];
    }
    return [true, 'ok'];
}

function spandaman_stream_url_direct($url) {
    if (!function_exists('curl_init')) {
        return false;
    }
    $headers = spandaman_proxy_origin_headers($url);
    if (isset($_SERVER['HTTP_RANGE']) && $_SERVER['HTTP_RANGE'] !== '') {
        $headers[] = 'Range: ' . $_SERVER['HTTP_RANGE'];
    }
    $sentHeaders = false;
    $pathExt = strtolower(pathinfo(parse_url($url, PHP_URL_PATH) ?: '', PATHINFO_EXTENSION));
    $mimeByExt = [
        'mp4' => 'video/mp4',
        'm4v' => 'video/mp4',
        'mkv' => 'video/x-matroska',
        'webm' => 'video/webm',
        'mov' => 'video/quicktime',
        'avi' => 'video/x-msvideo',
        'flv' => 'video/x-flv',
        'wmv' => 'video/x-ms-wmv',
        'ts' => 'video/mp2t',
    ];
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 8,
        CURLOPT_CONNECTTIMEOUT => 12,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_USERAGENT => spandaman_proxy_user_agent(),
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => 0,
        CURLOPT_HEADERFUNCTION => function($ch, $header) use (&$sentHeaders, $pathExt, $mimeByExt) {
            $len = strlen($header);
            $trim = trim($header);
            if ($trim === '') {
                return $len;
            }
            if (stripos($trim, 'HTTP/') === 0) {
                if (preg_match('{HTTP/\S+\s+(\d{3})}', $trim, $m)) {
                    http_response_code((int)$m[1]);
                }
                return $len;
            }
            if (preg_match('/^Content-Type:/i', $trim)) {
                $parts = explode(':', $trim, 2);
                $ct = strtolower(trim($parts[1] ?? ''));
                if (($ct === '' || $ct === 'application/octet-stream' || $ct === 'binary/octet-stream') && isset($mimeByExt[$pathExt])) {
                    header('Content-Type: ' . $mimeByExt[$pathExt], false);
                } else {
                    header($trim, false);
                }
            } elseif (preg_match('/^(Content-Length|Content-Range|Accept-Ranges):/i', $trim)) {
                header($trim, false);
            }
            $sentHeaders = true;
            return $len;
        },
        CURLOPT_WRITEFUNCTION => function($ch, $chunk) use (&$sentHeaders, $pathExt, $mimeByExt) {
            if (!$sentHeaders) {
                header('Content-Type: ' . ($mimeByExt[$pathExt] ?? 'application/octet-stream'));
                $sentHeaders = true;
            }
            echo $chunk;
            @flush();
            return strlen($chunk);
        },
    ]);
    $ok = curl_exec($ch);
    $err = curl_error($ch);
    $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    if ($ok === false) {
        if (!headers_sent()) {
            http_response_code(502);
            header('Content-Type: text/plain');
        }
        echo 'Proxy curl error: ' . $err;
    } elseif ($code >= 400 && !headers_sent()) {
        http_response_code($code);
    }
    return true;
}

if ((isset($_GET['data']) && !empty($_GET['data'])) || (isset($_GET['url']) && !empty($_GET['url']))) {
    $decodedData = isset($_GET['data']) ? base64_decode($_GET['data']) : '';
    $parts = $decodedData !== '' ? explode('|', $decodedData) : [];

    // If 'url' param is set, use it; otherwise, use first part of $parts
    if (isset($_GET['url']) && !empty($_GET['url'])) {
        $url = $_GET['url'];
        $auto = isset($_GET['auto']) && (strtolower($_GET['auto']) == '1' || strtolower($_GET['auto']) === 'true');
        if ($decodedData === '' && !$auto) {
            spandaman_stream_url_direct($url);
            exit;
        }
        // All $parts are headers (no URL in parts)
    } else {
        $url = array_shift($parts); // first part is URL (old way)
    }

    $httpOptions = [
        'http' => [
            'method' => 'GET',
            'header' => []
        ]
    ];

    // Loop through remaining parts and add as headers
    foreach ($parts as $headerData) {
        if (strpos($headerData, '=') !== false) {
            list($header, $value) = explode('=', $headerData, 2);
            $value = trim($value, "'\"");
            $httpOptions['http']['header'][] = "$header: $value";
        }
    }

    if (isset($_SERVER['HTTP_RANGE'])) {
        $httpOptions['http']['header'][] = "Range: " . $_SERVER['HTTP_RANGE'];
    }

    // Check for auto redirect flag
    $auto = isset($_GET['auto']) && (strtolower($_GET['auto']) == '1' || strtolower($_GET['auto']) === 'true');

    // ---- AUTO MODE: Let PHP handle redirects ----
    if ($auto) {
        [$preflightOk, $preflightReason] = spandaman_proxy_media_preflight($url);
        if (!$preflightOk) {
            http_response_code(415);
            header('Content-Type: text/plain');
            header('X-SPANDAMAN-Proxy-Rejected: byte-signature');
            echo $preflightReason;
            exit;
        }
        spandaman_stream_url_direct($url);
        exit;
    }
    // ---- END AUTO MODE ----

    // ---- MANUAL REDIRECT MODE (Default/Old Style) ----
    $context = stream_context_create($httpOptions);
    $maxRedirects = 10;
    $statusCode = null;
    $contentType = null;
    for ($i = 0; $i < $maxRedirects; $i++) {
        $headers = get_headers($url, 1, $context);
        if ($headers === false) {
            http_response_code(500);
            header('Content-Type: text/plain');
            echo "Failed to fetch headers.";
            exit;
        }

        $statusLine = $headers[0];
        preg_match('{HTTP/\S+ (\d{3})}', $statusLine, $match);
        $statusCode = $match[1];

        if (isset($headers['Content-Type'])) {
            $contentType = is_array($headers['Content-Type']) ? end($headers['Content-Type']) : $headers['Content-Type'];
        }

        if (in_array($statusCode, ['301', '302'])) {
            $url = $headers['Location'];
            if (is_array($url)) {
                $url = end($url);
            }
        } else {
            break;
        }
    }

    if (!in_array($statusCode, ['200', '206'])) {
        
        // --- FIX: Override status code if Content-Type is video ---
        $ct = isset($headers['Content-Type']) ? (is_array($headers['Content-Type']) ? end($headers['Content-Type']) : $headers['Content-Type']) : '';
        if (stripos($ct, 'video/') === 0) {
            if (isset($_SERVER['HTTP_RANGE'])) {
                http_response_code(206);
            } else {
                http_response_code(200);
            }
        } else {
            http_response_code($statusCode);
        }

        header('Content-Type: ' . ($contentType ?: 'text/plain'));
        echo "Failed with status code: $statusCode";
        exit;
    }

    $headers = get_headers($url, 1, $context);

    [$preflightOk, $preflightReason] = spandaman_proxy_media_preflight($url);
    if (!$preflightOk) {
        http_response_code(415);
        header('Content-Type: text/plain');
        header('X-SPANDAMAN-Proxy-Rejected: byte-signature');
        echo $preflightReason;
        exit;
    }

    header($headers[0]);
    if (isset($headers['Content-Type'])) {
        header('Content-Type: ' . $headers['Content-Type']);
    }
    if (isset($headers['Content-Length'])) {
        header('Content-Length: ' . $headers['Content-Length']);
    }
    if (isset($headers['Accept-Ranges'])) {
        header('Accept-Ranges: ' . $headers['Accept-Ranges']);
    }
    if (isset($headers['Content-Range'])) {
        header('Content-Range: ' . $headers['Content-Range']);
    }

    if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
        exit;
    }

    $fp = fopen($url, 'rb', false, $context);
    if ($fp === false) {
        http_response_code(500);
        header('Content-Type: text/plain');
        echo "Failed to open URL.";
        exit;
    }

    while (!feof($fp)) {
        echo fread($fp, 1024 * 256);
        flush();
    }
    fclose($fp);
} else {
    http_response_code(400);
    header('Content-Type: text/plain');
    echo "Missing the data or url parameter.";
}
?>
