<?php
@ini_set('memory_limit', '256M');
@ini_set('max_execution_time', '30');
header('Access-Control-Allow-Origin: *');

$USER = 'base';
$PASS = 'base';
$BASE = 'https://apps.spandaman.co.uk/spandaman/tmdbbase';
$ACTION = isset($_GET['action']) ? trim((string)$_GET['action']) : '';
$TMDB_KEY = 'ab083c1bc18d15b25e9a2680cf6f745b';
$TMDB_LANG = 'en-US';

function sp_json($data) {
	header('Content-Type: application/json');
	echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
	exit();
}

function sp_auth_ok($user, $pass) {
	if (!isset($_GET['username']) && !isset($_GET['password'])) return true;
	return (($_GET['username'] ?? '') === $user && ($_GET['password'] ?? '') === $pass);
}

function sp_auth_fail() {
	sp_json(array(
		'user_info' => array('auth' => 0, 'status' => 'Disabled', 'message' => 'Invalid username or password'),
		'server_info' => array('url' => 'apps.spandaman.co.uk', 'timestamp_now' => time(), 'time_now' => date('Y-m-d H:i:s'))
	));
}

function sp_redirect_json($base, $filename) {
	$path = __DIR__ . '/' . $filename;
	if (!is_file($path) || filesize($path) <= 2) sp_json(array());
	header('Content-Type: application/json');
	header('Cache-Control: public, max-age=60');
	header('Location: ' . rtrim($base, '/') . '/' . rawurlencode($filename), true, 302);
	exit();
}

function sp_stream_file($path, $contentType = 'application/json') {
	if (!is_file($path) || filesize($path) <= 2) sp_json(array());
	while (ob_get_level() > 0) @ob_end_clean();
	header('Content-Type: ' . $contentType);
	$fh = fopen($path, 'rb');
	if (!$fh) sp_json(array());
	while (!feof($fh)) {
		echo fread($fh, 262144);
		flush();
	}
	fclose($fh);
	exit();
}

function sp_read_json_small($filename) {
	$path = __DIR__ . '/' . $filename;
	if (!is_file($path) || filesize($path) <= 2 || filesize($path) > 10485760) return array();
	$raw = file_get_contents($path);
	if (!is_string($raw)) return array();
	if (substr($raw, 0, 3) === "\xEF\xBB\xBF") $raw = substr($raw, 3);
	$data = json_decode($raw, true);
	return is_array($data) ? $data : array();
}

function sp_find_by_id_in_small_map($filename, $id) {
	$data = sp_read_json_small($filename);
	$key = (string)$id;
	if (isset($data[$key]) && is_array($data[$key])) return $data[$key];
	foreach ($data as $row) {
		if (is_array($row)) {
			$rid = (string)($row['stream_id'] ?? ($row['series_id'] ?? ($row['id'] ?? '')));
			if ($rid === $key) return $row;
		}
	}
	return array();
}

function sp_tmdb_img($path) {
	if (!is_string($path) || $path === '') return '';
	if (preg_match('~^https?://~i', $path)) return $path;
	return 'https://image.tmdb.org/t/p/original' . $path;
}

function sp_http_json($url, $timeout = 18) {
	$ctx = stream_context_create(array('http' => array(
		'timeout' => $timeout,
		'header' => "User-Agent: SPANDAMAN-TMDBBASE/1.0\r\nAccept: application/json\r\n"
	)));
	$raw = @file_get_contents($url, false, $ctx);
	if (!is_string($raw) || $raw === '') return array();
	$data = json_decode($raw, true);
	return is_array($data) ? $data : array();
}

function sp_find_json_row_by_id_stream($filename, $id, $idKeys = array('stream_id', 'series_id', 'id', 'num')) {
	$path = __DIR__ . '/' . $filename;
	if (!is_file($path) || filesize($path) <= 2) return array();
	$fh = fopen($path, 'rb');
	if (!$fh) return array();
	$target = (string)$id;
	$depth = 0;
	$inString = false;
	$escape = false;
	$capturing = false;
	$buf = '';
	while (($chunk = fread($fh, 65536)) !== false && $chunk !== '') {
		$len = strlen($chunk);
		for ($i = 0; $i < $len; $i++) {
			$ch = $chunk[$i];
			if ($inString) {
				if ($capturing) $buf .= $ch;
				if ($escape) {
					$escape = false;
				} elseif ($ch === '\\') {
					$escape = true;
				} elseif ($ch === '"') {
					$inString = false;
				}
				continue;
			}
			if ($ch === '"') {
				$inString = true;
				if ($capturing) $buf .= $ch;
				continue;
			}
			if ($ch === '{') {
				$depth++;
				if ($depth === 1) {
					$capturing = true;
					$buf = '{';
				} elseif ($capturing) {
					$buf .= $ch;
				}
				continue;
			}
			if ($ch === '}') {
				if ($capturing) $buf .= $ch;
				if ($depth === 1 && $capturing) {
					$row = json_decode($buf, true);
					if (is_array($row)) {
						foreach ($idKeys as $key) {
							if ((string)($row[$key] ?? '') === $target) {
								fclose($fh);
								return $row;
							}
						}
					}
					$capturing = false;
					$buf = '';
				}
				$depth = max(0, $depth - 1);
				continue;
			}
			if ($capturing) $buf .= $ch;
		}
	}
	fclose($fh);
	return array();
}

function sp_series_row_by_id($id) {
	$row = sp_find_json_row_by_id_stream('spandaman_series_player_streams.json', $id, array('series_id', 'id', 'num'));
	return is_array($row) ? $row : array();
}

function sp_vod_row_by_id($id) {
	$row = sp_find_json_row_by_id_stream('adult-movies.json', $id, array('stream_id', 'num', 'id'));
	if (!empty($row)) return $row;
	$row = sp_find_json_row_by_id_stream('playlist.json', $id, array('stream_id', 'num', 'id'));
	if (!empty($row)) return $row;
	return sp_find_json_row_by_id_stream('spandaman_vod_player_streams.json', $id, array('stream_id', 'num', 'id'));
}

function sp_merge_series_episode_map($map) {
	if (empty($map) || !is_array($map)) return;
	$path = __DIR__ . '/spandaman_series_episode_map.json';
	$current = array();
	if (is_file($path) && filesize($path) > 2 && filesize($path) < 16777216) {
		$tmp = json_decode((string)@file_get_contents($path), true);
		if (is_array($tmp)) $current = $tmp;
	}
	foreach ($map as $k => $v) {
		if ($k !== '' && $v !== '') $current[(string)$k] = $v;
	}
	@file_put_contents($path, json_encode($current, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), LOCK_EX);
	@chmod($path, 0777);
}

if (!sp_auth_ok($USER, $PASS)) sp_auth_fail();

if ($ACTION === '') {
	$now = time();
	sp_json(array(
		'user_info' => array(
			'username' => $_GET['username'] ?? $USER,
			'password' => $_GET['password'] ?? $PASS,
			'message' => '',
			'auth' => 1,
			'status' => 'Active',
			'exp_date' => '4095101905',
			'is_trial' => '0',
			'active_cons' => '0',
			'created_at' => '1684851647',
			'max_connections' => '1000',
			'allowed_output_formats' => array('m3u8', 'ts')
		),
		'server_info' => array(
			'url' => 'apps.spandaman.co.uk',
			'port' => '80',
			'https_port' => '',
			'server_protocol' => 'http',
			'rtmp_port' => '',
			'timezone' => 'Europe/London',
			'timestamp_now' => $now,
			'time_now' => date('Y-m-d H:i:s', $now)
		)
	));
}

if ($ACTION === 'get_live_streams') sp_redirect_json($BASE, 'spandaman_live_player_streams.json');
if ($ACTION === 'get_vod_streams') sp_redirect_json($BASE, 'spandaman_vod_player_streams.json');
if ($ACTION === 'get_series') sp_redirect_json($BASE, 'spandaman_series_player_streams.json');

if ($ACTION === 'get_live_categories') sp_redirect_json($BASE, 'spandaman_live_player_categories.json');
if ($ACTION === 'get_vod_categories') sp_redirect_json($BASE, 'spandaman_vod_player_categories.json');
if ($ACTION === 'get_series_categories') sp_redirect_json($BASE, 'spandaman_series_player_categories.json');

if ($ACTION === 'get_vod_info') {
	$id = (string)($_GET['vod_id'] ?? '');
	$row = sp_vod_row_by_id($id);
	$name = (string)($row['name'] ?? ($row['title'] ?? ('VOD ' . $id)));
	$icon = (string)($row['stream_icon'] ?? ($row['cover'] ?? ($row['movie_image'] ?? ($row['poster'] ?? ''))));
	if ($icon === '' && isset($row['poster_path'])) $icon = sp_tmdb_img($row['poster_path']);
	$plot = (string)($row['plot'] ?? ($row['description'] ?? ($row['overview'] ?? '')));
	$rating = (string)($row['rating'] ?? '');
	$genre = (string)($row['genres'] ?? ($row['genre'] ?? ($row['group'] ?? '')));
	$direct = (string)($row['direct_source'] ?? '');
	if ($direct === '' || strpos($direct, '/movie/base/base/') === false) $direct = $BASE . '/movie/base/base/' . rawurlencode($id) . '.mp4';
	sp_json(array(
		'info' => array(
			'name' => $name,
			'movie_image' => $icon,
			'cover_big' => $icon,
			'cover' => $icon,
			'plot' => $plot,
			'description' => $plot,
			'genre' => $genre,
			'cast' => (string)($row['cast'] ?? ''),
			'director' => (string)($row['director'] ?? ''),
			'rating' => $rating,
			'releasedate' => (string)($row['releaseDate'] ?? ($row['release_date'] ?? '')),
			'duration_secs' => (int)($row['duration_secs'] ?? 0),
			'duration' => (string)($row['duration'] ?? ''),
			'backdrop_path' => isset($row['backdrop_path']) ? (array)$row['backdrop_path'] : array()
		),
		'movie_data' => array(
			'stream_id' => is_numeric($id) ? (int)$id : $id,
			'name' => $name,
			'added' => (string)($row['added'] ?? time()),
			'category_id' => (string)($row['category_id'] ?? '878'),
			'container_extension' => (string)($row['container_extension'] ?? 'mp4'),
			'direct_source' => $direct
		)
	));
}

if ($ACTION === 'get_series_info') {
	global $TMDB_KEY, $TMDB_LANG, $BASE;
	$id = (string)($_GET['series_id'] ?? '');
	$cache = sp_find_by_id_in_small_map('spandaman_series_info_index.json', $id);
	if (!empty($cache)) sp_json($cache);
	$series = sp_series_row_by_id($id);
	$name = (string)($series['name'] ?? ('Series ' . $id));
	$cover = (string)($series['cover'] ?? ($series['stream_icon'] ?? ''));
	$details = sp_http_json('https://api.themoviedb.org/3/tv/' . rawurlencode($id) . '?api_key=' . rawurlencode($TMDB_KEY) . '&include_adult=true&append_to_response=external_ids,credits&language=' . rawurlencode($TMDB_LANG), 20);
	if (empty($details)) {
		sp_json(array(
			'seasons' => array(array('air_date' => '', 'episode_count' => 0, 'id' => 1, 'name' => 'Season 1', 'season_number' => 1)),
			'info' => array('name' => $name, 'cover' => $cover, 'cover_big' => $cover, 'plot' => (string)($series['plot'] ?? ''), 'rating' => (string)($series['rating'] ?? '')),
			'episodes' => array()
		));
	}
	$totalSeasons = max(0, (int)($details['number_of_seasons'] ?? 0));
	$full = $details;
	for ($start = 1; $start <= $totalSeasons; $start += 20) {
		$end = min($start + 19, $totalSeasons);
		$parts = array();
		for ($s = $start; $s <= $end; $s++) $parts[] = 'season/' . $s;
		$batch = sp_http_json('https://api.themoviedb.org/3/tv/' . rawurlencode($id) . '?api_key=' . rawurlencode($TMDB_KEY) . '&append_to_response=' . rawurlencode(implode(',', $parts)) . '&language=' . rawurlencode($TMDB_LANG), 25);
		foreach ($parts as $part) {
			if (isset($batch[$part]) && is_array($batch[$part])) $full[$part] = $batch[$part];
		}
	}
	$poster = sp_tmdb_img($full['poster_path'] ?? '');
	if ($poster === '') $poster = $cover;
	$backdrop = sp_tmdb_img($full['backdrop_path'] ?? '');
	$genres = array();
	foreach (($full['genres'] ?? array()) as $g) if (isset($g['name'])) $genres[] = $g['name'];
	$cast = array();
	foreach (($details['credits']['cast'] ?? array()) as $actor) {
		if (($actor['known_for_department'] ?? '') === 'Acting' && isset($actor['name'])) $cast[] = $actor['name'];
		if (count($cast) >= 4) break;
	}
	$result = array(
		'seasons' => array(),
		'info' => array(
			'name' => (string)($full['name'] ?? $name),
			'cover' => $poster,
			'cover_big' => $poster,
			'plot' => (string)($full['overview'] ?? ($series['plot'] ?? '')),
			'cast' => implode(', ', $cast),
			'director' => (string)($full['created_by'][0]['name'] ?? ''),
			'genre' => implode(', ', $genres),
			'releaseDate' => (string)($full['first_air_date'] ?? ''),
			'last_modified' => strtotime((string)($full['last_air_date'] ?? '')) ?: time(),
			'rating' => (string)($full['vote_average'] ?? ($series['rating'] ?? '')),
			'rating_5based' => (float)($full['vote_average'] ?? 0) / 2,
			'backdrop_path' => $backdrop ? array($backdrop) : array(),
			'youtube_trailer' => '',
			'episode_run_time' => (int)($full['episode_run_time'][0] ?? 0),
			'category_id' => (string)($series['category_id'] ?? '')
		),
		'episodes' => array()
	);
	$routeMap = array();
	$today = strtotime('today');
	for ($seasonNumber = 1; $seasonNumber <= $totalSeasons; $seasonNumber++) {
		$key = 'season/' . $seasonNumber;
		if (!isset($full[$key]) || !is_array($full[$key])) continue;
		$seasonData = $full[$key];
		$episodes = is_array($seasonData['episodes'] ?? null) ? $seasonData['episodes'] : array();
		$result['seasons'][] = array(
			'air_date' => (string)($seasonData['air_date'] ?? ''),
			'episode_count' => count($episodes),
			'id' => (string)($seasonData['_id'] ?? $seasonNumber),
			'name' => 'Season ' . $seasonNumber,
			'overview' => (string)($seasonData['overview'] ?? ''),
			'season_number' => $seasonNumber,
			'backdrop_path' => $backdrop,
			'cover' => $poster,
			'cover_big' => $poster
		);
		foreach ($episodes as $episode) {
			$air = strtotime((string)($episode['air_date'] ?? ''));
			if ($air && $air > $today) continue;
			$episodeId = (string)($episode['id'] ?? '');
			if ($episodeId === '') continue;
			$epNum = (int)($episode['episode_number'] ?? 0);
			$token = base64_encode((string)($details['external_ids']['imdb_id'] ?? ('tmdb' . $id)) . ':' . $id . '/season/' . $seasonNumber . '/episode/' . $epNum);
			$routeMap[$episodeId] = $token;
			$still = sp_tmdb_img($episode['still_path'] ?? '');
			if ($still === '') $still = $backdrop ?: $poster;
			if (!isset($result['episodes'][(string)$seasonNumber])) $result['episodes'][(string)$seasonNumber] = array();
			$result['episodes'][(string)$seasonNumber][] = array(
				'id' => is_numeric($episodeId) ? (int)$episodeId : $episodeId,
				'episode_num' => $epNum,
				'title' => 'S' . str_pad((string)$seasonNumber, 2, '0', STR_PAD_LEFT) . 'E' . str_pad((string)$epNum, 2, '0', STR_PAD_LEFT) . ' - ' . (string)($episode['name'] ?? ''),
				'container_extension' => 'm3u8',
				'custom_sid' => '',
				'added' => (string)($air ?: time()),
				'season' => $seasonNumber,
				'direct_source' => $BASE . '/series/base/base/' . rawurlencode($episodeId) . '.m3u8',
				'info' => array(
					'tmdb_id' => is_numeric($id) ? (int)$id : $id,
					'name' => (string)($episode['name'] ?? ''),
					'cover_big' => $still,
					'movie_image' => $still,
					'plot' => (string)($episode['overview'] ?? '')
				)
			);
		}
	}
	sp_merge_series_episode_map($routeMap);
	sp_json($result);
}

sp_json(array());
