<?php
if (!function_exists('ugfx_normalize_mount')) {
function ugfx_normalize_mount(string $mount): string {
    $mount = '/' . ltrim(trim($mount), '/');
    return $mount === '/' ? '' : $mount;
}
}

if (!function_exists('ugfx_get_stream_config')) {
function ugfx_get_stream_config(): array {
    $cfg = [
        'server_ip' => 'cr2.broadcasturself.com',
        'server_port' => '9000',
        'admin_user' => 'UndergroundFx',
        'admin_password' => 'TxHL7RqdSjQbSB',
        'mount_main' => '/stream',
        'mount_auto' => '/autodj',
        'mount_backup' => '/stream2',
        'listen_url' => 'http://radio.undergroundfxradio.com:9000/stream',
        'stats_url' => 'http://cr2.broadcasturself.com:9000/admin/stats',
        'stats_xml_url' => 'http://cr2.broadcasturself.com:9000/admin/stats.xml',
        'stats_xsl_url' => 'http://cr2.broadcasturself.com:9000/admin/stats.xsl?showall=true',
        'public_status_url' => 'http://cr2.broadcasturself.com:9000/status.xsl',
    ];

    $settingsFile = dirname(__DIR__) . '/data/settings.json';
    if (is_file($settingsFile)) {
        $settings = json_decode((string)file_get_contents($settingsFile), true);
        if (is_array($settings)) {
            foreach (['server_ip','server_port','stats_user','stats_password','stats_url','stats_xml_url','stats_xsl_url','public_status_url','public_stream_url','stream_url'] as $key) {
                if (!empty($settings[$key])) {
                    switch ($key) {
                        case 'stats_user': $cfg['admin_user'] = trim((string)$settings[$key]); break;
                        case 'stats_password': $cfg['admin_password'] = trim((string)$settings[$key]); break;
                        case 'public_stream_url':
                        case 'stream_url':
                            $cfg['listen_url'] = trim((string)$settings[$key]);
                            break;
                        default:
                            $cfg[$key] = trim((string)$settings[$key]);
                    }
                }
            }
            if (!empty($settings['mount_main'])) $cfg['mount_main'] = ugfx_normalize_mount((string)$settings['mount_main']);
            if (!empty($settings['mount_auto'])) $cfg['mount_auto'] = ugfx_normalize_mount((string)$settings['mount_auto']);
            if (!empty($settings['mount_backup'])) $cfg['mount_backup'] = ugfx_normalize_mount((string)$settings['mount_backup']);
        }
    }

    $cfg['mount_main'] = ugfx_normalize_mount((string)$cfg['mount_main']);
    $cfg['mount_auto'] = ugfx_normalize_mount((string)$cfg['mount_auto']);
    $cfg['mount_backup'] = ugfx_normalize_mount((string)$cfg['mount_backup']);

    if (trim((string)$cfg['stats_url']) === '') {
        $cfg['stats_url'] = sprintf('http://%s:%s/admin/stats', $cfg['server_ip'], $cfg['server_port']);
    }
    if (trim((string)$cfg['stats_xml_url']) === '') {
        $cfg['stats_xml_url'] = sprintf('http://%s:%s/admin/stats.xml', $cfg['server_ip'], $cfg['server_port']);
    }
    if (trim((string)$cfg['stats_xsl_url']) === '') {
        $cfg['stats_xsl_url'] = sprintf('http://%s:%s/admin/stats.xsl?showall=true', $cfg['server_ip'], $cfg['server_port']);
    }
    if (trim((string)$cfg['public_status_url']) === '') {
        $cfg['public_status_url'] = sprintf('http://%s:%s/status.xsl', $cfg['server_ip'], $cfg['server_port']);
    }

    return $cfg;
}
}

if (!function_exists('ugfx_get_player_urls')) {
function ugfx_get_player_urls(): array {
    $cfg = ugfx_get_stream_config();
    $rawUrl = trim((string)($cfg['listen_url'] ?? ''));
    return [
        'raw' => $rawUrl,
        'public' => $rawUrl,
        'direct' => $rawUrl,
        'proxy' => '/stream-proxy.php',
        'preferred' => $rawUrl !== '' ? $rawUrl : '/stream-proxy.php',
        'using_proxy' => false,
    ];
}
}

if (!function_exists('ugfx_http_socket_fetch')) {
function ugfx_http_socket_fetch(string $url, array $headers = [], int $timeout = 5): string {
    $parts = @parse_url($url);
    if (!is_array($parts) || empty($parts['host'])) {
        return '';
    }

    $scheme = strtolower((string)($parts['scheme'] ?? 'http'));
    $host = (string)$parts['host'];
    $port = (int)($parts['port'] ?? ($scheme === 'https' ? 443 : 80));
    $path = (string)($parts['path'] ?? '/');
    $query = isset($parts['query']) ? '?' . $parts['query'] : '';
    $transport = $scheme === 'https' ? 'ssl://' : '';

    $errno = 0;
    $errstr = '';
    $fp = @fsockopen($transport . $host, $port, $errno, $errstr, $timeout);
    if (!$fp) {
        return '';
    }

    stream_set_timeout($fp, $timeout);
    $headerLines = [
        'GET ' . ($path . $query) . ' HTTP/1.0',
        'Host: ' . $host,
        'Connection: close',
        'User-Agent: UGFX/1.0',
    ];
    foreach ($headers as $k => $v) {
        if (is_int($k)) {
            $headerLines[] = (string)$v;
        } else {
            $headerLines[] = $k . ': ' . $v;
        }
    }
    $headerLines[] = '';
    $headerLines[] = '';
    fwrite($fp, implode("
", $headerLines));

    $raw = '';
    while (!feof($fp)) {
        $raw .= (string)fgets($fp, 8192);
    }
    fclose($fp);
    if ($raw === '') {
        return '';
    }

    $parts = preg_split("/
?

?
/", $raw, 2);
    return isset($parts[1]) ? (string)$parts[1] : $raw;
}
}

if (!function_exists('ugfx_fetch_url')) {
function ugfx_fetch_url(array $urls, string $accept = 'text/html, application/xhtml+xml, */*'): string {
    foreach ($urls as $url) {
        $url = trim((string)$url);
        if ($url === '') continue;

        if (function_exists('curl_init')) {
            $ch = curl_init($url);
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 6,
                CURLOPT_CONNECTTIMEOUT => 4,
                CURLOPT_FAILONERROR => false,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_MAXREDIRS => 2,
                CURLOPT_HTTPHEADER => ['Accept: ' . $accept],
            ]);
            $raw = curl_exec($ch);
            $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if (is_string($raw) && trim($raw) !== '' && $code < 400) {
                return $raw;
            }
        }

        $context = stream_context_create([
            'http' => [
                'timeout' => 6,
                'ignore_errors' => true,
                'header' => "Accept: {$accept}
",
            ]
        ]);
        $raw = @file_get_contents($url, false, $context);
        if (is_string($raw) && trim($raw) !== '') {
            return $raw;
        }

        $raw = ugfx_http_socket_fetch($url, ['Accept' => $accept], 6);
        if (is_string($raw) && trim($raw) !== '') {
            return $raw;
        }
    }
    return '';
}
}

if (!function_exists('ugfx_fetch_public_status_xsl')) {
function ugfx_fetch_public_status_xsl(): string {
    $cfg = ugfx_get_stream_config();
    return ugfx_fetch_url([
        (string)($cfg['public_status_url'] ?? ''),
        sprintf('http://%s:%s/status.xsl', $cfg['server_ip'], $cfg['server_port']),
    ], 'text/html, application/xhtml+xml, */*');
}
}

if (!function_exists('ugfx_fetch_with_basic_auth')) {
function ugfx_fetch_with_basic_auth(array $urls, string $user, string $pass, string $accept = 'application/xml, text/xml, text/html, */*'): string {
    foreach ($urls as $url) {
        $url = trim((string)$url);
        if ($url === '') continue;

        if (function_exists('curl_init')) {
            $ch = curl_init($url);
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
                CURLOPT_USERPWD => $user . ':' . $pass,
                CURLOPT_TIMEOUT => 6,
                CURLOPT_CONNECTTIMEOUT => 4,
                CURLOPT_FAILONERROR => false,
                CURLOPT_HTTPHEADER => ['Accept: ' . $accept],
            ]);
            $raw = curl_exec($ch);
            $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if (is_string($raw) && trim($raw) !== '' && $code < 400) {
                return $raw;
            }
        }

        $context = stream_context_create([
            'http' => [
                'timeout' => 6,
                'ignore_errors' => true,
                'header' => "Authorization: Basic " . base64_encode($user . ':' . $pass) . "\r\n" .
                            "Accept: {$accept}\r\n",
            ]
        ]);
        $raw = @file_get_contents($url, false, $context);
        if (is_string($raw) && trim($raw) !== '') {
            return $raw;
        }

        $raw = ugfx_http_socket_fetch($url, [
            'Authorization' => 'Basic ' . base64_encode($user . ':' . $pass),
            'Accept' => $accept,
        ], 6);
        if (is_string($raw) && trim($raw) !== '') {
            return $raw;
        }
    }
    return '';
}
}

if (!function_exists('ugfx_fetch_icecast_xml')) {
function ugfx_fetch_icecast_xml(): string {
    $cfg = ugfx_get_stream_config();
    return ugfx_fetch_with_basic_auth([
        (string)($cfg['stats_url'] ?? ''),
        (string)($cfg['stats_xml_url'] ?? ''),
        sprintf('http://%s:%s/admin/stats', $cfg['server_ip'], $cfg['server_port']),
        sprintf('http://%s:%s/admin/stats.xml', $cfg['server_ip'], $cfg['server_port']),
    ], (string)$cfg['admin_user'], (string)$cfg['admin_password'], 'application/xml, text/xml, */*');
}
}

if (!function_exists('ugfx_fetch_icecast_xsl')) {
function ugfx_fetch_icecast_xsl(): string {
    $cfg = ugfx_get_stream_config();
    return ugfx_fetch_with_basic_auth([
        (string)($cfg['stats_xsl_url'] ?? ''),
        sprintf('http://%s:%s/admin/stats.xsl?showall=true', $cfg['server_ip'], $cfg['server_port']),
    ], (string)$cfg['admin_user'], (string)$cfg['admin_password'], 'text/html, application/xhtml+xml, */*');
}
}

if (!function_exists('ugfx_parse_xml_tag')) {
function ugfx_parse_xml_tag(string $xml, string $tag): string {
    if (preg_match('/<' . preg_quote($tag, '/') . '>(.*?)<\/' . preg_quote($tag, '/') . '>/is', $xml, $m)) {
        return trim(html_entity_decode(strip_tags($m[1]), ENT_QUOTES, 'UTF-8'));
    }
    return '';
}
}

if (!function_exists('ugfx_parse_icecast_data')) {
function ugfx_parse_icecast_data(string $xml): array {
    $result = ['global' => [], 'sources' => []];
    if (trim($xml) === '') return $result;

    if (function_exists('simplexml_load_string')) {
        libxml_use_internal_errors(true);
        $sx = @simplexml_load_string($xml);
        if ($sx) {
            $result['global'] = [
                'listeners' => isset($sx->listeners) ? (int)$sx->listeners : 0,
                'listener_connections' => isset($sx->listener_connections) ? (int)$sx->listener_connections : 0,
                'clients' => isset($sx->clients) ? (int)$sx->clients : 0,
                'sources' => isset($sx->sources) ? (int)$sx->sources : 0,
                'host' => trim((string)($sx->host ?? '')),
                'server_id' => trim((string)($sx->server_id ?? '')),
                'server_start' => trim((string)($sx->server_start_iso8601 ?? $sx->server_start ?? '')),
            ];

            if (isset($sx->source)) {
                foreach ($sx->source as $source) {
                    $mount = ugfx_normalize_mount((string)$source['mount']);
                    $title = trim((string)$source->title);
                    if ($title === '' && isset($source->x_icy_title)) $title = trim((string)$source->x_icy_title);
                    if ($title === '' && isset($source->{'x-icy-title'})) $title = trim((string)$source->{'x-icy-title'});
                    $listeners = isset($source->listeners) ? (int)$source->listeners : 0;
                    $result['sources'][] = [
                        'mount' => $mount,
                        'title' => html_entity_decode($title, ENT_QUOTES, 'UTF-8'),
                        'listeners' => $listeners,
                        'stream_start' => trim((string)($source->stream_start_iso8601 ?? $source->stream_start ?? '')),
                        'source_ip' => trim((string)($source->source_ip ?? '')),
                        'listenurl' => trim((string)($source->listenurl ?? '')),
                        'server_name' => trim((string)($source->server_name ?? '')),
                        'server_description' => trim((string)($source->server_description ?? '')),
                        'x_icy_title' => trim((string)($source->x_icy_title ?? $source->{'x-icy-title'} ?? '')),
                        'is_active' => ($listeners > 0 || trim((string)($source->source_ip ?? '')) !== '' || trim((string)($source->stream_start_iso8601 ?? $source->stream_start ?? '')) !== '' || $title !== ''),
                    ];
                }
            }

            libxml_clear_errors();
            return $result;
        }
        libxml_clear_errors();
    }

    $result['global'] = [
        'listeners' => (int)ugfx_parse_xml_tag($xml, 'listeners'),
        'listener_connections' => (int)ugfx_parse_xml_tag($xml, 'listener_connections'),
        'clients' => (int)ugfx_parse_xml_tag($xml, 'clients'),
        'sources' => (int)ugfx_parse_xml_tag($xml, 'sources'),
        'host' => ugfx_parse_xml_tag($xml, 'host'),
        'server_id' => ugfx_parse_xml_tag($xml, 'server_id'),
        'server_start' => ugfx_parse_xml_tag($xml, 'server_start_iso8601') ?: ugfx_parse_xml_tag($xml, 'server_start'),
    ];

    if (preg_match_all('/<source\b([^>]*)>(.*?)<\/source>/is', $xml, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $attrs = $match[1];
            $body = $match[2];
            $mount = '';
            if (preg_match("/mount=[\"']([^\"']+)[\"']/i", $attrs, $mm)) {
                $mount = ugfx_normalize_mount($mm[1]);
            }
            $title = ugfx_parse_xml_tag($body, 'title');
            if ($title === '') $title = ugfx_parse_xml_tag($body, 'x_icy_title');
            if ($title === '') $title = ugfx_parse_xml_tag($body, 'x-icy-title');
            $listeners = (int)ugfx_parse_xml_tag($body, 'listeners');
            $result['sources'][] = [
                'mount' => $mount,
                'title' => $title,
                'listeners' => $listeners,
                'stream_start' => ugfx_parse_xml_tag($body, 'stream_start_iso8601') ?: ugfx_parse_xml_tag($body, 'stream_start'),
                'source_ip' => ugfx_parse_xml_tag($body, 'source_ip'),
                'listenurl' => ugfx_parse_xml_tag($body, 'listenurl'),
                'server_name' => ugfx_parse_xml_tag($body, 'server_name'),
                'server_description' => ugfx_parse_xml_tag($body, 'server_description'),
                'x_icy_title' => ugfx_parse_xml_tag($body, 'x_icy_title') ?: ugfx_parse_xml_tag($body, 'x-icy-title'),
                'is_active' => ($listeners > 0 || ugfx_parse_xml_tag($body, 'source_ip') !== '' || ugfx_parse_xml_tag($body, 'stream_start_iso8601') !== '' || $title !== ''),
            ];
        }
    }

    return $result;
}
}

if (!function_exists('ugfx_parse_stats_xsl')) {
function ugfx_parse_stats_xsl(string $html): array {
    $result = ['global' => [], 'sources' => []];
    if (trim($html) === '') return $result;

    $plain = html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8');
    $plain = preg_replace('/\x{00a0}/u', ' ', $plain);
    $plain = preg_replace('/[ \t]+/', ' ', $plain);
    $plain = preg_replace('/\s*\n\s*/', "\n", $plain);

    if (preg_match('/listener_connections\s+([0-9,]+)/i', $plain, $m)) {
        $result['global']['listener_connections'] = (int)str_replace(',', '', $m[1]);
    }
    if (preg_match('/(?:^|\n)listeners\s+([0-9,]+)/mi', $plain, $m)) {
        $result['global']['listeners'] = (int)str_replace(',', '', $m[1]);
    }
    if (preg_match('/host\s+([^\n]+)/i', $plain, $m)) {
        $result['global']['host'] = trim($m[1]);
    }
    if (preg_match('/server_id\s+([^\n]+)/i', $plain, $m)) {
        $result['global']['server_id'] = trim($m[1]);
    }

    if (preg_match_all('/Mountpoint\s+(\/[^\s]+)\n([\s\S]*?)(?=\nMountpoint\s+\/|\nSupport Icecast|\nWe Are Proudly Hosted|\z)/i', $plain, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $mount = ugfx_normalize_mount($match[1]);
            $section = $match[2];
            $title = '';
            if (preg_match('/x_icy_title\s+([^\n]+)/i', $section, $m)) {
                $title = trim($m[1]);
            } elseif (preg_match('/(?:^|\n)title\s+([^\n]+)/mi', $section, $m)) {
                $title = trim($m[1]);
            }
            $listeners = 0;
            if (preg_match('/(?:^|\n)listeners\s+([0-9,]+)/mi', $section, $m)) {
                $listeners = (int)str_replace(',', '', $m[1]);
            }
            $serverName = '';
            if (preg_match('/server_name\s+([^\n]+)/i', $section, $m)) {
                $serverName = trim($m[1]);
            }
            $listenUrl = '';
            if (preg_match('/listenurl\s+([^\n]+)/i', $section, $m)) {
                $listenUrl = trim($m[1]);
            }
            $sourceIp = '';
            if (preg_match('/source_ip\s+([^\n]+)/i', $section, $m)) {
                $sourceIp = trim($m[1]);
            }
            $streamStart = '';
            if (preg_match('/stream_start_iso8601\s+([^\n]+)/i', $section, $m)) {
                $streamStart = trim($m[1]);
            } elseif (preg_match('/stream_start\s+([^\n]+)/i', $section, $m)) {
                $streamStart = trim($m[1]);
            }
            $result['sources'][] = [
                'mount' => $mount,
                'title' => $title,
                'x_icy_title' => $title,
                'listeners' => $listeners,
                'stream_start' => $streamStart,
                'source_ip' => $sourceIp,
                'listenurl' => $listenUrl,
                'server_name' => $serverName,
                'server_description' => '',
                'is_active' => ($listeners > 0 || $title !== '' || $sourceIp !== '' || $streamStart !== ''),
            ];
        }
    }

    return $result;
}
}

if (!function_exists('ugfx_parse_public_status_xsl')) {
function ugfx_parse_public_status_xsl(string $html): array {
    $result = ['global' => [], 'sources' => []];
    if (trim($html) === '') return $result;

    $plain = html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8');
    $plain = preg_replace('/\x{00a0}/u', ' ', $plain);
    $plain = preg_replace('/[ \t]+/', ' ', $plain);
    $plain = preg_replace('/\s*\n\s*/', "\n", $plain);

    if (preg_match_all('/Mountpoint\s+(\/[^\s]+)\n([\s\S]*?)(?=\nMountpoint\s+\/|\nSupport icecast|\nSupport Icecast|\nWe Are Proudly Hosted|\z)/i', $plain, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $mount = ugfx_normalize_mount($match[1]);
            $section = trim($match[2]);
            $listeners = 0;
            $title = '';
            $listenUrl = '';
            $serverName = '';
            $serverDescription = '';
            $streamStart = '';

            if (preg_match('/Listeners \(current\):[ \t]*([^\n]*)/i', $section, $m)) {
                $listeners = (int) preg_replace('/[^0-9]/', '', $m[1]);
            } elseif (preg_match('/(?:^|\\n)listeners\\s+([0-9,]+)/mi', $section, $m)) {
                $listeners = (int) str_replace(',', '', $m[1]);
            }
            if (preg_match('/Currently playing:[ \t]*([^\n]*)/i', $section, $m)) {
                $title = trim($m[1]);
            }
            if ($title === '' && preg_match('/x_icy_title\s+([^\n]+)/i', $section, $m)) {
                $title = trim($m[1]);
            }
            if ($title === '' && preg_match('/Playlist\n(?:Album\s+Track\s+Creator\s+Title\n)?([\s\S]*)$/i', $section, $m)) {
                $playlistBlock = trim($m[1]);
                foreach (preg_split('/\r?\n/', $playlistBlock) as $line) {
                    $candidate = trim($line);
                    if ($candidate === '') continue;
                    if (preg_match('/^(Direct|M3U|XSPF|Play stream|Further information|Playlist|Album\s+Track\s+Creator\s+Title)$/i', $candidate)) continue;
                    $title = $candidate;
                    break;
                }
            }
            if (preg_match('/Stream Name:[ \t]*([^\n]+)/i', $section, $m)) {
                $serverName = trim($m[1]);
            }
            if (preg_match('/Stream Description:[ \t]*([^\n]+)/i', $section, $m)) {
                $serverDescription = trim($m[1]);
            }
            if (preg_match('/Stream URL:[ \t]*([^\n]+)/i', $section, $m)) {
                $listenUrl = trim($m[1]);
            }
            if (preg_match('/Stream started:[ \t]*([^\n]+)/i', $section, $m)) {
                $streamStart = trim($m[1]);
            }

            $result['sources'][] = [
                'mount' => $mount,
                'title' => $title,
                'x_icy_title' => $title,
                'listeners' => $listeners,
                'stream_start' => $streamStart,
                'source_ip' => '',
                'listenurl' => $listenUrl,
                'server_name' => $serverName,
                'server_description' => $serverDescription,
                'is_active' => ($listeners > 0 || $title !== '' || $serverName !== '' || $streamStart !== ''),
            ];
        }
    }

    if (!empty($result['sources'])) {
        $sum = 0;
        foreach ($result['sources'] as $src) {
            $sum += (int)($src['listeners'] ?? 0);
        }
        $result['global']['listeners'] = $sum;
    }

    return $result;
}
}

if (!function_exists('ugfx_merge_icecast_sources')) {
function ugfx_merge_icecast_sources(array $primary, array $secondary): array {
    $merged = [];
    foreach ([$primary, $secondary] as $sourceList) {
        foreach ($sourceList as $source) {
            $mount = ugfx_normalize_mount((string)($source['mount'] ?? ''));
            if ($mount === '') continue;
            if (!isset($merged[$mount])) {
                $merged[$mount] = [
                    'mount' => $mount,
                    'title' => '',
                    'x_icy_title' => '',
                    'listeners' => 0,
                    'stream_start' => '',
                    'source_ip' => '',
                    'listenurl' => '',
                    'server_name' => '',
                    'server_description' => '',
                    'is_active' => false,
                ];
            }
            foreach (['title','x_icy_title','stream_start','source_ip','listenurl','server_name','server_description'] as $field) {
                if (trim((string)($source[$field] ?? '')) !== '') {
                    $merged[$mount][$field] = trim((string)$source[$field]);
                }
            }
            if (isset($source['listeners']) && (int)$source['listeners'] >= 0) {
                $merged[$mount]['listeners'] = max((int)$merged[$mount]['listeners'], (int)$source['listeners']);
            }
            $merged[$mount]['is_active'] = !empty($merged[$mount]['is_active']) || !empty($source['is_active']) || (int)($merged[$mount]['listeners'] ?? 0) > 0 || trim((string)($merged[$mount]['title'] ?? '')) !== '';
        }
    }
    return array_values($merged);
}
}

if (!function_exists('ugfx_pick_preferred_source')) {
function ugfx_pick_preferred_source(array $sources): ?array {
    if (!$sources) return null;
    $cfg = ugfx_get_stream_config();
    $streamMount = ugfx_normalize_mount((string)($cfg['mount_main'] ?? '/stream'));
    $autoMount = ugfx_normalize_mount((string)($cfg['mount_auto'] ?? '/autodj'));
    $backupMount = ugfx_normalize_mount((string)($cfg['mount_backup'] ?? '/stream2'));

    $byMount = [];
    foreach ($sources as $source) {
        $byMount[ugfx_normalize_mount((string)($source['mount'] ?? ''))] = $source;
    }

    $live = $byMount[$streamMount] ?? null;
    if ($live && (int)($live['listeners'] ?? 0) > 0) {
        $live['is_live'] = true;
        return $live;
    }

    $auto = $byMount[$autoMount] ?? null;
    if ($auto && (!empty($auto['is_active']) || trim((string)($auto['title'] ?? '')) !== '' || (int)($auto['listeners'] ?? 0) > 0)) {
        $auto['is_live'] = false;
        return $auto;
    }

    if ($live) {
        $live['is_live'] = ((int)($live['listeners'] ?? 0) > 0);
        return $live;
    }

    if (isset($byMount[$backupMount])) {
        $byMount[$backupMount]['is_live'] = false;
        return $byMount[$backupMount];
    }

    $first = $sources[0] ?? null;
    if ($first) $first['is_live'] = false;
    return $first;
}
}
