<?php
// Enable error reporting for debugging (disable display in production)
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', 'error_log.txt');
ini_set('memory_limit', '256M');
ini_set('max_execution_time', 60);

// Set JSON header
header('Content-Type: application/json');

// Function to fetch HTML content using cURL, with user's IP forwarded in headers
function fetchHtml($pageUrl, $userIp) {
    if (!extension_loaded('curl')) {
        return ['error' => 'cURL extension is not enabled on the server.'];
    }
    if (!extension_loaded('libxml')) {
        return ['error' => 'libxml extension is not enabled on the server.'];
    }

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $pageUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36');
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language: en-US,en;q=0.5',
        'Connection: keep-alive',
        'DNT: 1',
        'X-Forwarded-For: ' . $userIp,  // Forward user's IP to mimic request from user
        'X-Real-IP: ' . $userIp         // Additional header for some proxies/CDNs
    ]);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    
    $html = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    curl_close($ch);
    
    if ($html === false || $httpCode != 200) {
        return [
            'error' => "Error fetching webpage: HTTP $httpCode",
            'curl_error' => $curlError
        ];
    }
    
    return ['html' => $html];
}

// Function to parse video URL for joporn
function parseJoporn($html) {
    $doc = new DOMDocument();
    libxml_use_internal_errors(true);
    if (!$doc->loadHTML('<?xml encoding="UTF-8">' . $html)) {
        return ['error' => 'Failed to parse HTML.'];
    }
    libxml_clear_errors();
    
    $xpath = new DOMXPath($doc);
    
    $sourceTags = $xpath->query("//video/source[@src[contains(., '720p')]]");
    if ($sourceTags->length > 0) {
        $videoUrl = $sourceTags->item(0)->getAttribute('src');
        if (!empty($videoUrl)) {
            return ['video_url' => trim($videoUrl)];
        }
    }
    
    $videoTags = $xpath->query("//video[@src[contains(., '720p')]]");
    if ($videoTags->length > 0) {
        $videoUrl = $videoTags->item(0)->getAttribute('src');
        if (!empty($videoUrl)) {
            return ['video_url' => trim($videoUrl)];
        }
    }
    
    $settingsTags = $xpath->query("//pjsdiv[@id='videoplayer_settings']//pjsdiv[contains(., '720p')]");
    if ($settingsTags->length > 0) {
        $settingsContent = $settingsTags->item(0)->nodeValue;
        if (preg_match('/https?:\/\/[^\s"]+\.mp4/', $settingsContent, $matches)) {
            return ['video_url' => trim($matches[0])];
        }
    }
    
    $allSourceTags = $xpath->query("//video/source[@src]");
    if ($allSourceTags->length > 0) {
        $videoUrl = $allSourceTags->item(0)->getAttribute('src');
        if (!empty($videoUrl)) {
            return [
                'video_url' => trim($videoUrl),
                'debug' => 'Found a video URL, but it may not be 720p.'
            ];
        }
    }
    
    $allVideoTags = $xpath->query("//video[@src]");
    if ($allVideoTags->length > 0) {
        $videoUrl = $allVideoTags->item(0)->getAttribute('src');
        if (!empty($videoUrl)) {
            return [
                'video_url' => trim($videoUrl),
                'debug' => 'Found a video URL, but it may not be 720p.'
            ];
        }
    }
    
    $dataTags = $xpath->query("//*[@data-src[contains(., '.mp4')]]");
    if ($dataTags->length > 0) {
        $videoUrl = $dataTags->item(0)->getAttribute('data-src');
        if (!empty($videoUrl)) {
            return ['video_url' => trim($videoUrl)];
        }
    }
    
    $scriptTags = $xpath->query("//script[contains(., '720p')]");
    foreach ($scriptTags as $script) {
        $content = $script->nodeValue;
        if (preg_match('/https?:\/\/[^\s"]+720p\.mp4/', $content, $matches)) {
            return ['video_url' => trim($matches[0])];
        }
    }
    
    return [
        'error' => 'No 720p video URL found.',
        'debug' => 'Checked video[@src], video/source[@src], player settings, data-src, and script tags for 720p.'
    ];
}

// Function to parse video URL for xxxbold
function parseXxxbold($html) {
    $doc = new DOMDocument();
    libxml_use_internal_errors(true);
    if (!$doc->loadHTML('<?xml encoding="UTF-8">' . $html)) {
        return ['error' => 'Failed to parse HTML.'];
    }
    libxml_clear_errors();
    
    $xpath = new DOMXPath($doc);
    
    // Try to find video URL in meta tag with itemprop="contentURL"
    $metaTags = $xpath->query("//meta[@itemprop='contentURL']");
    if ($metaTags->length > 0) {
        $videoUrl = $metaTags->item(0)->getAttribute('content');
        if (!empty($videoUrl) && strpos($videoUrl, '.mp4') !== false) {
            return ['video_url' => trim($videoUrl)];
        }
    }
    
    // Try to find video URL in iframe's decoded video source
    $iframeTags = $xpath->query("//div[@class='responsive-player']/iframe");
    if ($iframeTags->length > 0) {
        $iframeSrc = $iframeTags->item(0)->getAttribute('src');
        // Decode the base64-encoded query parameter
        if (preg_match('/q=([^&]+)/', $iframeSrc, $matches)) {
            $decoded = base64_decode($matches[1]);
            // Create a new DOMDocument for the decoded HTML
            $iframeDoc = new DOMDocument();
            libxml_use_internal_errors(true);
            if ($iframeDoc->loadHTML('<?xml encoding="UTF-8">' . $decoded)) {
                $iframeXpath = new DOMXPath($iframeDoc);
                $sourceTags = $iframeXpath->query("//video/source[@src]");
                if ($sourceTags->length > 0) {
                    $videoUrl = $sourceTags->item(0)->getAttribute('src');
                    if (!empty($videoUrl) && strpos($videoUrl, '.mp4') !== false) {
                        return ['video_url' => trim($videoUrl)];
                    }
                }
            }
            libxml_clear_errors();
        }
    }
    
    // Fallback: Check for any video/source tags
    $sourceTags = $xpath->query("//video/source[@src[contains(., '.mp4')]]");
    if ($sourceTags->length > 0) {
        $videoUrl = $sourceTags->item(0)->getAttribute('src');
        if (!empty($videoUrl)) {
            return ['video_url' => trim($videoUrl)];
        }
    }
    
    // Fallback: Check for any video tags
    $videoTags = $xpath->query("//video[@src[contains(., '.mp4')]]");
    if ($videoTags->length > 0) {
        $videoUrl = $videoTags->item(0)->getAttribute('src');
        if (!empty($videoUrl)) {
            return ['video_url' => trim($videoUrl)];
        }
    }
    
    // Fallback: Check script tags for .mp4 URLs
    $scriptTags = $xpath->query("//script");
    foreach ($scriptTags as $script) {
        $content = $script->nodeValue;
        if (preg_match('/https?:\/\/[^\s"]+\.mp4/', $content, $matches)) {
            return ['video_url' => trim($matches[0])];
        }
    }
    
    return [
        'error' => 'No video URL found.',
        'debug' => 'Checked meta[@itemprop="contentURL"], iframe video source, video[@src], video/source[@src], and script tags for .mp4.'
    ];
}

// Main function to get video URL
function getVideoUrl($pageUrl, $userIp) {
    if (strpos($pageUrl, 'joporn') !== false) {
        $fetchResult = fetchHtml($pageUrl, $userIp);
        if (isset($fetchResult['error'])) {
            return $fetchResult;
        }
        return parseJoporn($fetchResult['html']);
    } elseif (strpos($pageUrl, 'xxxbold') !== false) {
        $fetchResult = fetchHtml($pageUrl, $userIp);
        if (isset($fetchResult['error'])) {
            return $fetchResult;
        }
        return parseXxxbold($fetchResult['html']);
    } else {
        return ['error' => 'Unsupported site. Only joporn and xxxbold are supported.'];
    }
}

// Handle API request
try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        http_response_code(405);
        echo json_encode(['error' => 'Method not allowed. Use POST.']);
        exit;
    }

    $inputRaw = file_get_contents('php://input');
    if (empty($inputRaw)) {
        http_response_code(400);
        echo json_encode(['error' => 'No input data provided.']);
        exit;
    }

    $input = json_decode($inputRaw, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid JSON: ' . json_last_error_msg()]);
        exit;
    }
    
    if (!isset($input['url']) || empty($input['url']) || !filter_var($input['url'], FILTER_VALIDATE_URL)) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid or missing URL in request body.']);
        exit;
    }
    
    // Get the user's real IP address (handles some proxy cases)
    $userIp = $_SERVER['REMOTE_ADDR'];
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ipAddresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $userIp = trim(end($ipAddresses));  // Use the last IP in the chain as the original user IP
    } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
        $userIp = $_SERVER['HTTP_CLIENT_IP'];
    }
    
    $result = getVideoUrl($input['url'], $userIp);
    
    if (isset($result['error'])) {
        http_response_code(404);
        echo json_encode($result);
    } else {
        http_response_code(200);
        echo json_encode($result);
    }
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode([
        'error' => 'Internal server error.',
        'debug' => 'Check error_log.txt for details.'
    ]);
}
?>

is code me user ke ip through parse request bhej raha hu qyuki same ip se bar bar request bheju to direct link nahi aa rahi hai. mere app me jyada user live rahte hai is liye ye ip wala scenerio kiya hai but ye ip wala work nahi kar raha hai. shayad same ip se hi request jaa rahi hai. jab jyada user live ho tab