246 lines
6.7 KiB
PHP
246 lines
6.7 KiB
PHP
<?php
|
|
|
|
// Config
|
|
|
|
$GLOBALS["frairable_host"] = getenv("FRAIRABLE_HOST");
|
|
if (empty($GLOBALS["frairable_host"])) {
|
|
$GLOBALS["frairable_host"] = "https://airable.wifiradiofrontier.com";
|
|
}
|
|
|
|
$GLOBALS["frairable_dir_radios"] = getenv("FRAIRABLE_DIR_RADIOS");
|
|
if (empty($GLOBALS["frairable_dir_radios"])) {
|
|
$GLOBALS["frairable_dir_radios"] = dirname(__FILE__) . DIRECTORY_SEPARATOR . "radios";
|
|
}
|
|
|
|
|
|
|
|
// Common strings
|
|
$GLOBALS["frairable_part_custom"] = "custom=";
|
|
$GLOBALS["frairable_part_play"] = "play=";
|
|
$GLOBALS["frairable_uri_listing"] = "/frontiersmart/radios/custom";
|
|
$GLOBALS["frairable_uri_meta"] = "/frontiersmart/radio/$GLOBALS[frairable_part_custom]";
|
|
|
|
|
|
|
|
// Response utils
|
|
|
|
function respond_with_raw(&$data) {
|
|
ob_start();
|
|
{
|
|
ob_start();
|
|
{
|
|
echo($data);
|
|
ob_end_flush();
|
|
}
|
|
|
|
header("Content-Length: " . ob_get_length());
|
|
ob_end_flush();
|
|
}
|
|
}
|
|
|
|
function respond_with_json(&$data) {
|
|
header("Content-Type: application/json");
|
|
|
|
$data = json_encode($data);
|
|
respond_with_raw($data);
|
|
}
|
|
|
|
function respond_with_proxy($cb = NULL) {
|
|
$ch = curl_init("$GLOBALS[frairable_host]$_SERVER[REQUEST_URI]");
|
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_HEADER, 0);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $_SERVER["REQUEST_METHOD"]);
|
|
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
|
|
|
|
$headers_req = getallheaders();
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
"Accept: " . ($headers_req["Accept"] ?? "audio/aac;mp3;dash"),
|
|
"Accept-Language: " . ($headers_req["Accept-Language"] ?? "en-US"),
|
|
"Authorization: " . ($headers_req["Authorization"] ?? "????"),
|
|
"Connection: " . ($headers_req["Connection"] ?? "Close"),
|
|
"Content-Length: " . ($headers_req["Content-Length"] ?? "0"),
|
|
"User-Agent: " . ($headers_req["User-Agent"] ?? "ir-cui-FS2340-0000-0165_V4.5.13.707296-1A17")
|
|
]);
|
|
|
|
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $headerstr) {
|
|
$len = strlen($headerstr);
|
|
$header = explode(":", $headerstr, 2);
|
|
|
|
if (count($header) < 2) {
|
|
return $len;
|
|
}
|
|
|
|
$key = trim($header[0]);
|
|
$value = trim($header[1]);
|
|
|
|
if ($key !== "Content-Length") {
|
|
header($headerstr);
|
|
}
|
|
|
|
return $len;
|
|
});
|
|
|
|
$data = curl_exec($ch);
|
|
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
http_response_code($httpCode);
|
|
|
|
if ($_SERVER["REQUEST_METHOD"] === "GET" && $httpCode === 200) {
|
|
if ($cb !== NULL) {
|
|
$data = json_decode($data, true);
|
|
$cb($data);
|
|
$data = json_encode($data);
|
|
}
|
|
|
|
if ($data === "null") {
|
|
$data = "";
|
|
|
|
if (200 <= $httpCode && $httpCode < 300) {
|
|
http_response_code(404);
|
|
}
|
|
}
|
|
}
|
|
|
|
respond_with_raw($data);
|
|
}
|
|
|
|
|
|
|
|
// Radio data manglers
|
|
|
|
function get_radio_data($id) {
|
|
$path = $GLOBALS["frairable_dir_radios"] . DIRECTORY_SEPARATOR . $id . ".json";
|
|
$path = realpath($path);
|
|
|
|
if (!str_starts_with($path, dirname(__FILE__))) {
|
|
http_response_code(400);
|
|
die();
|
|
}
|
|
|
|
return json_decode(file_get_contents($path), true);
|
|
}
|
|
|
|
function get_radio_entry($id) {
|
|
$data = get_radio_data($id);
|
|
|
|
$data["contains"] = [];
|
|
|
|
// The ID MUST match with the URI for the radio meta.
|
|
$data["id"] = ["frontiersmart", "radio", "$GLOBALS[frairable_part_custom]$id"];
|
|
$data["url"] = "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_meta]$id";
|
|
|
|
unset($data["streams"]);
|
|
|
|
return $data;
|
|
}
|
|
|
|
function get_radio_meta($id) {
|
|
$data = get_radio_data($id);
|
|
|
|
$data["id"] = ["frontiersmart", "radio", "$GLOBALS[frairable_part_custom]$id"];
|
|
$data["url"] = "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_meta]$id";
|
|
|
|
foreach ($data["streams"] as $index => &$stream) {
|
|
$stream["url"] = "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_meta]$id/$GLOBALS[frairable_part_play]$index";
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
function get_radio_play($id, $index) {
|
|
$data = get_radio_data($id);
|
|
|
|
// Clone loves to complain about the stream not being an object...
|
|
// Deep clone using json is ugly, but eh.
|
|
$stream = json_decode(json_encode($data["streams"][$index]), true);
|
|
|
|
// The redirect ID can be anything, as long as it is unique.
|
|
// It doesn't need to match with the URI.
|
|
$stream["id"] = ["frontiersmart", "redirect", "$GLOBALS[frairable_part_custom]$id/$GLOBALS[frairable_part_play]$index"];
|
|
$stream["content"] = $data;
|
|
|
|
unset($stream["reliability"]);
|
|
|
|
return $stream;
|
|
}
|
|
|
|
|
|
|
|
// Routing
|
|
|
|
if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
|
// Stock starting point - add our own entry here.
|
|
|
|
respond_with_proxy(function(&$data) {
|
|
array_push($data["content"]["entries"], [
|
|
"id" => [
|
|
"frontiersmart",
|
|
"directory",
|
|
"custom"
|
|
],
|
|
"title" => "Frairable (Custom)",
|
|
"url" => "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_listing]"
|
|
]);
|
|
});
|
|
|
|
|
|
} elseif ($_SERVER["REQUEST_URI"] === $GLOBALS["frairable_uri_listing"]) {
|
|
// Our custom menu with our own entries.
|
|
|
|
$entries = [];
|
|
|
|
foreach (new DirectoryIterator($GLOBALS["frairable_dir_radios"]) as $sub) {
|
|
if ($sub->isDot() || $sub->isDir()) {
|
|
continue;
|
|
}
|
|
|
|
$id = basename($sub->getFilename(), ".json");
|
|
|
|
$entries[] = get_radio_entry($id);
|
|
}
|
|
|
|
$data = [
|
|
"id" => [
|
|
"frontiersmart",
|
|
"directory",
|
|
"custom"
|
|
],
|
|
"title" => "Frairable (Custom)",
|
|
"url" => "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_listing]",
|
|
"content" => [
|
|
"entries" => $entries
|
|
]
|
|
];
|
|
|
|
respond_with_json($data);
|
|
|
|
|
|
} elseif (str_starts_with($_SERVER["REQUEST_URI"], $GLOBALS["frairable_uri_meta"])) {
|
|
// The radio fetches different radio info multiple times:
|
|
// - Metadata when selecting the entry, containing a list of streams.
|
|
// - Playing info after the radio picked a stream to play.
|
|
// See the dumped meta.json and play.json for more info.. and to witness the complex redundancy.
|
|
|
|
$id = substr($_SERVER["REQUEST_URI"], strlen($GLOBALS["frairable_uri_meta"]));
|
|
|
|
$split = strpos($id, "/$GLOBALS[frairable_part_play]");
|
|
if ($split) {
|
|
$index = intval(substr($id, $split + strlen("/$GLOBALS[frairable_part_play]")));
|
|
$id = substr($id, 0, $split);
|
|
respond_with_json(get_radio_play($id, $index));
|
|
|
|
} else {
|
|
respond_with_json(get_radio_meta($id));
|
|
}
|
|
|
|
|
|
} else {
|
|
respond_with_proxy();
|
|
}
|
|
|
|
|
|
|
|
?>
|