<?php
// Generated by SPANDAMAN. Validates and publishes Live, TMDB, Series, and Adult additions.
error_reporting(0);
ini_set('memory_limit', '1024M');
set_time_limit(0);
header('Content-Type: application/json; charset=utf-8');
@include_once __DIR__ . '/config.php';
$fullMetadata = filter_var($_GET['full_metadata'] ?? $_GET['full'] ?? false, FILTER_VALIDATE_BOOLEAN);
$enrichStatic = filter_var($_GET['enrich_static'] ?? $_GET['enrich'] ?? false, FILTER_VALIDATE_BOOLEAN);

if (filter_var($_GET['dry_run'] ?? $_GET['dryrun'] ?? false, FILTER_VALIDATE_BOOLEAN)) {
    $channels = __DIR__ . '/channels';
    $files = array(
        'live_playlist' => __DIR__ . '/channels/live_playlist.json',
        'playlist' => __DIR__ . '/playlist.json',
        'adult_movies' => __DIR__ . '/adult-movies.json',
        'tv_playlist' => __DIR__ . '/tv_playlist.json',
        'xtream_live' => $channels . '/spandaman_xtream_live_streams.json',
        'xtream_vod' => $channels . '/spandaman_xtream_vod_streams.json',
        'xtream_series' => $channels . '/spandaman_xtream_series_streams.json',
        'playable_cache' => __DIR__ . '/spandaman_playable_tmdb_cache.json',
    );
    $summary = array();
    foreach ($files as $name => $path) {
        $summary[$name] = array(
            'exists' => is_file($path),
            'bytes' => is_file($path) ? filesize($path) : 0,
            'mtime' => is_file($path) ? gmdate('c', filemtime($path)) : null,
        );
    }
    echo json_encode(array(
        'ok' => true,
        'dry_run' => true,
        'finalizer_ready' => true,
        'memory_limit' => ini_get('memory_limit'),
        'files' => $summary,
    ), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

if (filter_var($_GET['quick'] ?? $_GET['fast'] ?? false, FILTER_VALIDATE_BOOLEAN)) {
    $channels = __DIR__ . '/channels';
    if (!is_dir($channels)) mkdir($channels, 0755, true);
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    if (strtolower($host) === 'www.apps.spandaman.co.uk') $host = 'apps.spandaman.co.uk';
    $dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/')), '/');
    if ($dir === '/' || $dir === '.') $dir = '';
    $base = $scheme . '://' . $host . $dir;
    $countNeedle = function($path, $needle) {
        if (!is_file($path)) return 0;
        $count = 0;
        $handle = fopen($path, 'rb');
        if (!$handle) return 0;
        while (!feof($handle)) {
            $chunk = fread($handle, 1048576);
            if ($chunk === false || $chunk === '') continue;
            $count += substr_count($chunk, $needle);
        }
        fclose($handle);
        return $count;
    };
    $merged = fopen(__DIR__ . '/spandaman_playlist.m3u8', 'wb');
    fwrite($merged, '#EXTM3U x-tvg-url="' . $base . '/spandaman_epg.xml.gz" url-tvg="' . $base . '/spandaman_epg.xml.gz"' . "\n");
    foreach (array($channels . '/spandaman_xtream_all.m3u8', $channels . '/spandaman_tmdb_vod.m3u8') as $path) {
        if (!is_file($path)) continue;
        $handle = fopen($path, 'rb');
        if (!$handle) continue;
        while (($line = fgets($handle)) !== false) {
            if (stripos(trim($line), '#EXTM3U') === 0) continue;
            fwrite($merged, str_replace('[[SERVER_URL]]', $base, $line));
        }
        fclose($handle);
    }
    fclose($merged);
    copy(__DIR__ . '/spandaman_playlist.m3u8', __DIR__ . '/spandaman_playlist.m3u');
    $liveCount = $countNeedle($channels . '/spandaman_xtream_live_streams.json', '"stream_id"');
    $vodCount = $countNeedle($channels . '/spandaman_xtream_vod_streams.json', '"stream_id"') + $countNeedle($channels . '/spandaman_tmdb_vod_streams.json', '"stream_id"');
    $seriesCount = $countNeedle($channels . '/spandaman_xtream_series_streams.json', '"series_id"');
    $status = array(
        'ok' => true,
        'quick' => true,
        'updated_at' => gmdate('c'),
        'live' => $liveCount,
        'vod' => $vodCount,
        'series' => $seriesCount,
        'adult_enabled' => true,
        'public_counts' => array('live' => $liveCount, 'vod' => $vodCount, 'series' => $seriesCount),
        'playlist' => $base . '/get.php?username=anything&password=anything&type=m3u_plus&output=ts',
        'player_api' => $base . '/player_api.php?username=anything&password=anything',
    );
    file_put_contents($channels . '/spandaman_tmdb_status.json', json_encode($status, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    echo json_encode($status, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

function spandaman_load_array($path) {
    global $fullMetadata;
    if (!is_file($path)) return array();
    if (!$fullMetadata) {
        $base = basename((string)$path);
        if ($base === 'playlist.json' || $base === 'tv_playlist.json') return array();
    }
    $data = json_decode(file_get_contents($path), true);
    return is_array($data) ? array_values(array_filter($data, 'is_array')) : array();
}
function spandaman_json_array_file_count($path, $needle = '') {
    if (!is_file($path)) return 0;
    $size = filesize($path);
    if ($size === 2) return 0;
    if ($needle !== '' && $size > 8000000) {
        $count = 0;
        $handle = fopen($path, 'rb');
        if (!$handle) return 0;
        while (!feof($handle)) {
            $chunk = fread($handle, 1048576);
            if ($chunk === false || $chunk === '') continue;
            $count += substr_count($chunk, $needle);
        }
        fclose($handle);
        return $count;
    }
    $data = json_decode(file_get_contents($path), true);
    return is_array($data) ? count($data) : 0;
}
function spandaman_title_key($name) {
    $name = strtolower((string)$name);
    $name = preg_replace('/\([^)]*\b(19|20)\d{2}\b[^)]*\)/', ' ', $name);
    $name = preg_replace('/\b(alt|alternate|copy|backup|hd|fhd|uhd|4k|vod|movie)\b/i', ' ', $name);
    $name = html_entity_decode($name, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    $name = preg_replace('/[^a-z0-9]+/', '', $name);
    return (string)$name;
}
function spandaman_url_title_key($url) {
    $path = parse_url((string)$url, PHP_URL_PATH);
    if (!is_string($path) || $path === '') return '';
    $base = basename($path);
    $base = preg_replace('/\.[a-z0-9]{2,5}$/i', '', $base);
    $base = preg_replace('/([a-z])([A-Z])/', '$1 $2', $base);
    return spandaman_title_key($base);
}
function spandaman_url_title_query($url) {
    $path = parse_url((string)$url, PHP_URL_PATH);
    if (!is_string($path) || $path === '') return '';
    $base = basename($path);
    $base = preg_replace('/\.[a-z0-9]{2,5}$/i', '', $base);
    $base = preg_replace('/([a-z])([A-Z])/', '$1 $2', $base);
    $base = preg_replace('/[_\-.]+/', ' ', $base);
    return trim($base);
}
function spandaman_tmdb_search_meta($queries) {
    global $apiKey, $language;
    $apiKeyText = trim((string)($apiKey ?? ''));
    if ($apiKeyText === '') return null;
    foreach ($queries as $query) {
        $query = trim((string)$query);
        if (strlen($query) < 3 || preg_match('/\b(hour free movies|free movies|movies|vod)\b/i', $query)) continue;
        $url = 'https://api.themoviedb.org/3/search/movie?api_key=' . urlencode($apiKeyText)
            . '&include_adult=true&language=' . urlencode((string)($language ?? 'en-US')) . '&query=' . urlencode($query);
        $ctx = stream_context_create(array('http' => array('timeout' => 12, 'ignore_errors' => true,
            'header' => "User-Agent: SPANDAMAN/1.0\r\nAccept: application/json\r\n")));
        $body = @file_get_contents($url, false, $ctx);
        if (!is_string($body) || $body === '') continue;
        $data = json_decode($body, true);
        if (!is_array($data) || empty($data['results']) || !is_array($data['results'][0])) continue;
        $entry = $data['results'][0];
        $poster = trim((string)($entry['poster_path'] ?? ''));
        $backdrop = trim((string)($entry['backdrop_path'] ?? ''));
        $art = $poster !== '' ? ('https://image.tmdb.org/t/p/original' . $poster) : ($backdrop !== '' ? ('https://image.tmdb.org/t/p/original' . $backdrop) : '');
        $plot = trim((string)($entry['overview'] ?? ''));
        if (spandaman_bad_art($art) && $plot === '') continue;
        return array(
            'art' => $art,
            'plot' => $plot,
            'rating' => $entry['vote_average'] ?? '',
            'group' => 'Movies'
        );
    }
    return null;
}
function spandaman_bad_art($url) {
    $url = strtolower(trim((string)$url));
    return $url === '' || strpos($url, 'no-logo') !== false || strpos($url, 'icon_logo') !== false || strpos($url, 'placeholder') !== false;
}
function spandaman_vod_metadata_index($items) {
    $index = array();
    foreach ($items as $item) {
        if (!is_array($item)) continue;
        $key = spandaman_title_key($item['name'] ?? '');
        if ($key === '') continue;
        $art = trim((string)($item['stream_icon'] ?? $item['cover'] ?? ''));
        $plot = trim((string)($item['plot'] ?? $item['description'] ?? $item['overview'] ?? ''));
        $rating = $item['rating'] ?? '';
        if (spandaman_bad_art($art) && $plot === '' && $rating === '') continue;
        if (!isset($index[$key]) || (!spandaman_bad_art($art) && spandaman_bad_art($index[$key]['art'] ?? ''))) {
            $index[$key] = array('art' => $art, 'plot' => $plot, 'rating' => $rating, 'group' => spandaman_group($item, 'vod'));
        }
    }
    return $index;
}
function spandaman_enrich_static_vod($items, $metadataIndex) {
    $out = array();
    foreach ($items as $item) {
        if (!is_array($item)) continue;
        $sourceUrl = $item['direct_source'] ?? $item['url'] ?? '';
        $keys = array(spandaman_title_key($item['name'] ?? ''), spandaman_url_title_key($sourceUrl));
        $meta = null;
        foreach ($keys as $key) {
            if ($key !== '' && isset($metadataIndex[$key])) {
                $meta = $metadataIndex[$key];
                break;
            }
        }
        if (!$meta && (spandaman_bad_art($item['stream_icon'] ?? $item['cover'] ?? '') || trim((string)($item['plot'] ?? '')) === '')) {
            $meta = spandaman_tmdb_search_meta(array(spandaman_url_title_query($sourceUrl), $item['name'] ?? ''));
        }
        if ($meta) {
            if (!spandaman_bad_art($meta['art'] ?? '') && spandaman_bad_art($item['stream_icon'] ?? $item['cover'] ?? '')) {
                $item['stream_icon'] = $meta['art'];
                $item['cover'] = $meta['art'];
            }
            if (trim((string)($item['plot'] ?? '')) === '' && trim((string)($meta['plot'] ?? '')) !== '') {
                $item['plot'] = $meta['plot'];
                $item['description'] = $meta['plot'];
            }
            if (($item['rating'] ?? '') === '' && ($meta['rating'] ?? '') !== '') {
                $item['rating'] = $meta['rating'];
                $item['rating_5based'] = is_numeric($meta['rating']) ? (floatval($meta['rating']) / 2) : $meta['rating'];
            }
            if (trim((string)($item['group'] ?? '')) === '' && trim((string)($meta['group'] ?? '')) !== '') {
                $item['group'] = $meta['group'];
            }
        }
        $out[] = $item;
    }
    return $out;
}
function spandaman_static_vod_row_is_live($item) {
    if (!is_array($item)) return false;
    $url = strtolower((string)($item['direct_source'] ?? $item['url'] ?? ''));
    $raw = strtolower(trim(($item['group'] ?? '') . ' ' . ($item['category_name'] ?? '') . ' ' . ($item['name'] ?? '')));
    if (preg_match('/\.mpd(\?|$)|[?&]channel=|\/linear\/|livestream|\/live\/|\/scheduler\/|schedulemaster|streamlock|\/smil:|\.smil(?:\/|\?|$)|xumo|pluto|amagi\.tv/i', $url)) return true;
    if (preg_match('/\b(tv|channel|24\s*hour|radio)\b/i', $raw) && preg_match('/\.m3u8(\?|$)|playlist\.m3u8/i', $url)) return true;
    return false;
}
function spandaman_reclass_static_vod_live($staticVod, &$staticLive) {
    $vod = array();
    foreach ($staticVod as $item) {
        if (spandaman_static_vod_row_is_live($item)) {
            $item['stream_type'] = 'live';
            $staticLive[] = $item;
        } else {
            $vod[] = $item;
        }
    }
    return $vod;
}
function spandaman_reclass_static_live_vod($staticLive, &$staticVod) {
    $live = array();
    foreach ($staticLive as $item) {
        if (!is_array($item)) continue;
        $id = intval($item['stream_id'] ?? 0);
        $url = strtolower((string)($item['direct_source'] ?? $item['url'] ?? ''));
        $looksVodId = ($id >= 200000 && $id < 300000);
        $looksVodUrl = preg_match('/\/vod\/|\/movie\/|vod\/hls|\/f\/[^\/]+\/[^\/]+\.(mp4|m3u8)|\.mp4(\?|$)/i', $url);
        if (($looksVodId || $looksVodUrl) && !spandaman_static_vod_row_is_live($item)) {
            $item['stream_type'] = 'movie';
            $staticVod[] = $item;
        } else {
            $live[] = $item;
        }
    }
    return $live;
}
function spandaman_static_group_name($item, $kind) {
    $group = trim((string)($item['group'] ?? $item['category_name'] ?? ''));
    if ($group !== '') return $group;
    if ($kind === 'live') return 'Entertainment Live';
    if ($kind === 'series') return 'TV Series';
    return 'Movies';
}
function spandaman_sync_static_outputs($channels, $base, $staticLive, $staticVod, $staticSeries) {
    $redirects = array();
    $all = '#EXTM3U x-tvg-url="' . $base . '/spandaman_epg.xml.gz" url-tvg="' . $base . '/spandaman_epg.xml.gz"' . "\n";
    $byKind = array('live' => $staticLive, 'vod' => $staticVod, 'series' => $staticSeries);
    foreach ($byKind as $kind => $items) {
        $m3u = "#EXTM3U\n";
        foreach ($items as $item) {
            if (!is_array($item)) continue;
            $id = intval($kind === 'series' ? ($item['series_id'] ?? 0) : ($item['stream_id'] ?? 0));
            $url = trim((string)($item['direct_source'] ?? ''));
            if ($id <= 0 || $url === '') continue;
            $name = str_replace(array('"', "\r", "\n"), array("'", ' ', ' '), trim((string)($item['name'] ?? 'SPANDAMAN')));
            $logo = str_replace('"', '%22', trim((string)($item['stream_icon'] ?? $item['cover'] ?? '')));
            $group = str_replace('"', "'", spandaman_static_group_name($item, $kind));
            $ext = trim((string)($item['container_extension'] ?? (($kind === 'live') ? 'ts' : 'mp4')));
            if ($ext === '') $ext = ($kind === 'live') ? 'ts' : 'mp4';
            $prefix = ($kind === 'live') ? 'live' : (($kind === 'vod') ? 'movie' : 'series');
            $line = '#EXTINF:-1 tvg-id="" tvg-name="' . $name . '" tvg-logo="' . $logo . '" group-title="' . $group . '",' . $name . "\n"
                . $base . '/' . $prefix . '/anything/anything/' . $id . '.' . $ext . "\n";
            $m3u .= $line;
            $all .= $line;
            $redirects[] = $id . "\t" . $kind . "\t" . str_replace(array("\t", "\r", "\n"), '', $url);
        }
        file_put_contents($channels . '/spandaman_xtream_' . $kind . '.m3u8', $m3u);
    }
    file_put_contents($channels . '/spandaman_xtream_all.m3u8', $all);
    file_put_contents($channels . '/spandaman_xtream_redirects.tsv', implode("\n", $redirects) . "\n");
}
function spandaman_base_url() {
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    if (strtolower($host) === 'www.apps.spandaman.co.uk') $host = 'apps.spandaman.co.uk';
    $dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/')), '/');
    if ($dir === '/' || $dir === '.') $dir = '';
    return $scheme . '://' . $host . $dir;
}
function spandaman_group($item, $kind) {
    $raw = strtolower(trim(($item['group'] ?? '') . ' ' . ($item['genre'] ?? '') . ' ' . ($item['name'] ?? '')));
    $adult = (($item['stream_type'] ?? '') === 'adult') || preg_match('/\b(adult|18\+|xxx|porn)\b/i', $raw);
    if ($adult) return ($kind === 'live') ? 'Adult Live' : (($kind === 'series') ? 'Adult Series' : 'Adult Movies');
    if ($kind === 'live') {
        if (preg_match('/sport|football|soccer|fifa|ufc|boxing|wwe|nba|nfl/i', $raw)) return 'Sports Live';
        if (preg_match('/news|cnn|bbc news|sky news|bloomberg|al jazeera/i', $raw)) return 'News Live';
        if (preg_match('/kid|children|cartoon|disney|nick|boomerang/i', $raw)) return 'Kids Live';
        if (preg_match('/music|radio|vevo|concert|mtv/i', $raw)) return 'Music Live';
        if (preg_match('/documentary|history|nature|discovery/i', $raw)) return 'Documentary Live';
        if (preg_match('/relig|faith|church|christian|islam/i', $raw)) return 'Religious Live';
        return 'Entertainment Live';
    }
    if ($kind === 'series') {
        if (preg_match('/kid|children|cartoon|anime|disney/i', $raw)) return 'Kids & Anime Series';
        if (preg_match('/documentary|history|nature|discovery/i', $raw)) return 'Documentary Series';
        if (preg_match('/reality|game show|talk show/i', $raw)) return 'Reality Series';
        return 'TV Series';
    }
    if (preg_match('/kid|children|family|animation|disney/i', $raw)) return 'Kids & Family Movies';
    if (preg_match('/documentary|history|nature|discovery/i', $raw)) return 'Documentary Movies';
    if (preg_match('/comedy/i', $raw)) return 'Comedy Movies';
    if (preg_match('/horror|thriller|mystery|crime/i', $raw)) return 'Horror & Thriller Movies';
    if (preg_match('/action|adventure|war|western/i', $raw)) return 'Action & Adventure Movies';
    if (preg_match('/drama|romance/i', $raw)) return 'Drama & Romance Movies';
    if (preg_match('/international|foreign|bollywood|korean|japanese|french|spanish|german|italian/i', $raw)) return 'International Movies';
    return 'Movies';
}
function spandaman_tmdb_cache_value($tmdbId, $kind) {
    if ($kind !== 'vod' || intval($tmdbId) <= 0) return null;
    $cachePath = __DIR__ . '/cache.json';
    if (!is_file($cachePath)) return null;
    $data = json_decode(file_get_contents($cachePath), true);
    if (!is_array($data)) return null;
    $key = intval($tmdbId) . '_tmdb_url';
    if (!isset($data[$key]) || !is_array($data[$key])) return null;
    $value = json_decode($data[$key]['value'] ?? 'null', true);
    return is_string($value) ? $value : null;
}
function spandaman_clean_items($items, $kind, &$categories, &$adultCount, &$idMap) {
    global $publishPending;
    $out = array();
    $seen = array();
    foreach ($items as $item) {
        $idKey = ($kind === 'series') ? 'series_id' : 'stream_id';
        $id = intval($item[$idKey] ?? 0);
        $name = trim($item['name'] ?? '');
        if ($id <= 0 || $name === '' || isset($seen[$id])) continue;
        if ($kind === 'vod') {
            $cachedTmdbUrl = spandaman_tmdb_cache_value($id, $kind);
            if ($cachedTmdbUrl === null || $cachedTmdbUrl === '_running_' || $cachedTmdbUrl === '_failed_' || !preg_match('#^https?://#i', $cachedTmdbUrl)) {
                continue;
            }
        }
        $seen[$id] = true;
        $offset = ($kind === 'live') ? 30000000 : (($kind === 'series') ? 20000000 : 10000000);
        $hostId = $offset + count($out) + 1;
        $item['spandaman_tmdb_id'] = $id;
        $item[$idKey] = $hostId;
        $idMap[] = $hostId . "\t" . $kind . "\t" . $id;
        $group = spandaman_group($item, $kind);
        $cat = (string)(1000 + (int)sprintf('%u', crc32($kind . '|' . strtolower($group))) % 800000);
        $item['category_id'] = $cat;
        $art = trim($item['stream_icon'] ?? $item['cover'] ?? '');
        if ($art === '') {
            $art = 'https://apps.spandaman.co.uk/icon_logo.png';
            $item['stream_icon'] = $art;
            $item['cover'] = $art;
        }
        if (($item['stream_type'] ?? '') === 'adult' || stripos($group, 'adult') !== false) {
            $group = ($kind === 'live') ? 'Adult Live' : (($kind === 'series') ? 'Adult Series' : 'Adult Movies');
            $item['category_id'] = ($kind === 'live') ? '999991' : (($kind === 'series') ? '999992' : '999993');
            $adultCount++;
        }
        $categories[$item['category_id']] = array('category_id' => $item['category_id'], 'category_name' => $group, 'parent_id' => 0);
        $out[] = $item;
    }
    return $out;
}

$liveCategories = array(); $vodCategories = array(); $seriesCategories = array(); $adultCount = 0; $idMap = array();
$live = spandaman_load_array(__DIR__ . '/channels/live_playlist.json');
$vodRaw = array_merge(spandaman_load_array(__DIR__ . '/playlist.json'), spandaman_load_array(__DIR__ . '/adult-movies.json'));
$vodMetadataIndex = spandaman_vod_metadata_index($vodRaw);
$vod = $vodRaw;
$series = spandaman_load_array(__DIR__ . '/tv_playlist.json');
$live = spandaman_clean_items($live, 'live', $liveCategories, $adultCount, $idMap);
$vod = spandaman_clean_items($vod, 'vod', $vodCategories, $adultCount, $idMap);
$series = spandaman_clean_items($series, 'series', $seriesCategories, $adultCount, $idMap);
$channels = __DIR__ . '/channels';
if (!is_dir($channels)) mkdir($channels, 0755, true);
if ($fullMetadata) {
    file_put_contents($channels . '/spandaman_tmdb_live_streams.json', json_encode($live, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    file_put_contents($channels . '/spandaman_tmdb_vod_streams.json', json_encode($vod, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    file_put_contents($channels . '/spandaman_tmdb_series_streams.json', json_encode($series, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    file_put_contents($channels . '/spandaman_tmdb_live_categories.json', json_encode(array_values($liveCategories), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    file_put_contents($channels . '/spandaman_tmdb_vod_categories.json', json_encode(array_values($vodCategories), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    file_put_contents($channels . '/spandaman_tmdb_series_categories.json', json_encode(array_values($seriesCategories), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    file_put_contents($channels . '/spandaman_tmdb_id_map.tsv', implode("\n", $idMap) . "\n");
    $redirects = array();
    foreach (array_merge($live, $vod, $series) as $item) {
        $kind = isset($item['series_id']) ? 'series' : (($item['stream_type'] ?? '') === 'live' ? 'live' : 'vod');
        $hostId = intval($item['series_id'] ?? $item['stream_id'] ?? 0);
        $url = str_replace(array("\t", "\r", "\n"), '', trim($item['direct_source'] ?? ''));
        if ($hostId > 0 && $url !== '') $redirects[] = $hostId . "\t" . $kind . "\t" . $url;
    }
    file_put_contents($channels . '/spandaman_tmdb_redirects.tsv', implode("\n", $redirects) . "\n");
}
function spandaman_write_m3u($items, $kind, $categories, $path) {
    $base = spandaman_base_url();
    $m3u = "#EXTM3U\n";
    if ($kind === 'series') {
        $m3u .= "# Series are published through Xtream get_series/get_series_info so episode URLs retain season metadata.\n";
        file_put_contents($path, $m3u);
        return;
    }
    foreach ($items as $item) {
        $id = intval($kind === 'series' ? ($item['series_id'] ?? 0) : ($item['stream_id'] ?? 0));
        if ($id <= 0) continue;
        $name = str_replace(array('"', "\r", "\n"), array("'", ' ', ' '), trim($item['name'] ?? 'SPANDAMAN'));
        $logo = str_replace('"', '%22', trim($item['stream_icon'] ?? $item['cover'] ?? ''));
        $cat = (string)($item['category_id'] ?? '');
        $group = $categories[$cat]['category_name'] ?? ucfirst($kind);
        $prefix = ($kind === 'live') ? 'live' : (($kind === 'vod') ? 'movie' : 'series');
        $ext = ($kind === 'live') ? 'ts' : 'mp4';
        $m3u .= '#EXTINF:-1 tvg-id="" tvg-name="' . $name . '" tvg-logo="' . $logo . '" group-title="' . $group . '",' . $name . "\n";
        $m3u .= $base . '/' . $prefix . '/anything/anything/' . $id . '.' . $ext . "\n";
    }
    file_put_contents($path, $m3u);
}
if ($fullMetadata) {
    spandaman_write_m3u($live, 'live', $liveCategories, $channels . '/spandaman_tmdb_live.m3u8');
    spandaman_write_m3u($vod, 'vod', $vodCategories, $channels . '/spandaman_tmdb_vod.m3u8');
    spandaman_write_m3u($series, 'series', $seriesCategories, $channels . '/spandaman_tmdb_series.m3u8');
}

$base = spandaman_base_url();
$merged = fopen(__DIR__ . '/spandaman_playlist.m3u8', 'wb');
fwrite($merged, '#EXTM3U x-tvg-url="' . $base . '/spandaman_epg.xml.gz" url-tvg="' . $base . '/spandaman_epg.xml.gz"' . "\n");
// Series parents are exposed through Xtream get_series/get_series_info. A parent is
// not a playable episode, so publishing it in M3U would create a guaranteed 404.
foreach (array(
    $channels . '/spandaman_xtream_all.m3u8',
    $channels . '/spandaman_xtream_live.m3u8',
    $channels . '/spandaman_xtream_vod.m3u8',
    $channels . '/spandaman_tmdb_vod.m3u8'
) as $path) {
    if (!is_file($path)) continue;
    if (basename($path) === 'spandaman_xtream_live.m3u8' || basename($path) === 'spandaman_xtream_vod.m3u8') {
        if (is_file($channels . '/spandaman_xtream_all.m3u8')) continue;
    }
    $handle = fopen($path, 'rb');
    if (!$handle) continue;
    while (($line = fgets($handle)) !== false) {
        if (stripos(trim($line), '#EXTM3U') === 0) continue;
        fwrite($merged, str_replace('[[SERVER_URL]]', $base, $line));
    }
    fclose($handle);
}
fclose($merged);
copy(__DIR__ . '/spandaman_playlist.m3u8', __DIR__ . '/spandaman_playlist.m3u');

$ctx = stream_context_create(array('http' => array('timeout' => 2, 'ignore_errors' => true)));
$headlessAddress = trim((string)($HeadlessVidX_Address ?? $HEADLESSVIDX_ADDRESS ?? ''));
if ($headlessAddress === '') $headlessAddress = getenv('PORT') ? ('127.0.0.1:' . getenv('PORT')) : '127.0.0.1:3202';
$headlessUrl = preg_match('#^https?://#i', $headlessAddress) ? rtrim($headlessAddress, '/') . '/ping' : 'http://' . rtrim($headlessAddress, '/') . '/ping';
$headlessReply = @file_get_contents($headlessUrl, false, $ctx);
$headlessOnline = is_string($headlessReply) && (stripos($headlessReply, 'Pong') !== false || stripos($headlessReply, '"ok"') !== false);
$staticLive = spandaman_load_array($channels . '/spandaman_xtream_live_streams.json');
$staticVod = spandaman_load_array($channels . '/spandaman_xtream_vod_streams.json');
$staticLive = spandaman_reclass_static_live_vod($staticLive, $staticVod);
$staticVod = spandaman_reclass_static_vod_live($staticVod, $staticLive);
$staticLive = array_values($staticLive);
if ($fullMetadata || $enrichStatic) {
    $staticVod = spandaman_enrich_static_vod($staticVod, $vodMetadataIndex);
}
file_put_contents($channels . '/spandaman_xtream_live_streams.json', json_encode($staticLive, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
file_put_contents($channels . '/spandaman_xtream_vod_streams.json', json_encode($staticVod, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
$staticSeries = spandaman_load_array($channels . '/spandaman_xtream_series_streams.json');
$staticSeries = array_values(array_filter($staticSeries, function($item) {
    return is_array($item) && intval($item['series_id'] ?? 0) > 0 && trim((string)($item['direct_source'] ?? '')) !== '';
}));
file_put_contents($channels . '/spandaman_xtream_series_streams.json', json_encode($staticSeries, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
spandaman_sync_static_outputs($channels, spandaman_base_url(), $staticLive, $staticVod, $staticSeries);
$base = spandaman_base_url();
$merged = fopen(__DIR__ . '/spandaman_playlist.m3u8', 'wb');
fwrite($merged, '#EXTM3U x-tvg-url="' . $base . '/spandaman_epg.xml.gz" url-tvg="' . $base . '/spandaman_epg.xml.gz"' . "\n");
foreach (array(
    $channels . '/spandaman_xtream_all.m3u8',
    $channels . '/spandaman_tmdb_vod.m3u8'
) as $path) {
    if (!is_file($path)) continue;
    $handle = fopen($path, 'rb');
    if (!$handle) continue;
    while (($line = fgets($handle)) !== false) {
        if (stripos(trim($line), '#EXTM3U') === 0) continue;
        fwrite($merged, str_replace('[[SERVER_URL]]', $base, $line));
    }
    fclose($handle);
}
fclose($merged);
copy(__DIR__ . '/spandaman_playlist.m3u8', __DIR__ . '/spandaman_playlist.m3u');
$publicLiveCount = count($staticLive);
$tmdbVodCount = $fullMetadata ? count($vod) : spandaman_json_array_file_count($channels . '/spandaman_tmdb_vod_streams.json', '"stream_id"');
$tmdbSeriesMetadataCount = $fullMetadata ? count($series) : spandaman_json_array_file_count($channels . '/spandaman_tmdb_series_streams.json', '"series_id"');
$tmdbLiveMetadataCount = $fullMetadata ? count($live) : spandaman_json_array_file_count($channels . '/spandaman_tmdb_live_streams.json', '"stream_id"');
$publicVodCount = count($staticVod) + $tmdbVodCount;
$publicSeriesCount = count($staticSeries);
$status = array(
    'ok' => true, 'updated_at' => gmdate('c'), 'live' => $publicLiveCount, 'vod' => $publicVodCount,
    'series' => $publicSeriesCount, 'adult' => $adultCount, 'adult_enabled' => true,
    'public_counts' => array('live' => $publicLiveCount, 'vod' => $publicVodCount, 'series' => $publicSeriesCount),
    'static_database_counts' => array('live' => count($staticLive), 'vod' => count($staticVod), 'series' => count($staticSeries)),
    'tmdb_counts' => array('live_metadata' => $tmdbLiveMetadataCount, 'vod_playable' => $tmdbVodCount, 'series_metadata' => $tmdbSeriesMetadataCount),
    'headlessvidx_online' => $headlessOnline, 'headlessvidx_address' => $headlessAddress,
    'playlist' => spandaman_base_url() . '/get.php?username=anything&password=anything&type=m3u_plus&output=ts',
    'player_api' => spandaman_base_url() . '/player_api.php?username=anything&password=anything'
);
file_put_contents($channels . '/spandaman_tmdb_status.json', json_encode($status, JSON_PRETTY_PRINT));
echo json_encode($status);
?>
