Cleanup
This commit is contained in:
parent
f913eb9b69
commit
e75a3b34f9
22
README.md
22
README.md
@ -14,23 +14,29 @@ This repo contains a single php file that sits in between your radio and the Air
|
|||||||
|
|
||||||
|
|
||||||
## How can I use this?
|
## How can I use this?
|
||||||
The way I've set it up on my Raspberry Pi 4b is absolutely cursed and there's certainly better ways to do it, but it's 04:34am as I'm clacking my keys right now and I want sleep, so here's my setup:
|
|
||||||
|
### TL;DR
|
||||||
|
|
||||||
|
- Set up a web server on ports 80 and 443,
|
||||||
|
- Use `index.php` for every request,
|
||||||
|
- Redirect `airable.wifiradiofrontier.com` to your proxying device (f.e. via a DNS adblocker such as Pi-hole),
|
||||||
|
- Play around with the `radios` folder next to `index.php`.
|
||||||
|
|
||||||
|
### My setup
|
||||||
|
|
||||||
|
The way I've set it up on my Raspberry Pi 4b is absolutely cursed and there's certainly better ways to do it.
|
||||||
- Home Assistant OS
|
- Home Assistant OS
|
||||||
- Yes, I know running custom software outside of addons (which are just neatly packaged docker containers with special rules) isn't supported, but if it works in such a restrictive environment, then it surely works everywhere.
|
- Yes, I know running custom software outside of addons (which are just neatly packaged docker containers with special rules) isn't supported, but if it works in such a restrictive environment, then it surely works everywhere.
|
||||||
- [linuxserver/nginx](https://docs.linuxserver.io/images/docker-nginx/)
|
- [linuxserver/nginx](https://docs.linuxserver.io/images/docker-nginx/)
|
||||||
- Easy to set up, supports a wide range of platforms, and I don't need any of the fancyness that comes with linuxserver/swag (certbot) as it sits in my local network.
|
- Easy to set up, supports a wide range of platforms, and I don't need any of the fancyness that comes with linuxserver/swag (certbot) as it sits in my local network.
|
||||||
- The default config uses `index.php` for all requests, which is exactly what we want! Yay!
|
- The default config uses `index.php` for all requests, which is exactly what we want! Yay!
|
||||||
- Plop `index.php` and the `radios` dir into `www` (or set up a mount for it).
|
- Mounted such that `index.php` and the `radios` dir end up as `www`
|
||||||
- In your favourite DNS adblocker (Pi-hole or AdGuard Home), redirect `airable.wifiradiofrontier.com` to your device's IP.
|
- AdGuard Home to redirect `airable.wifiradiofrontier.com` to my raspi.
|
||||||
- Put a web radio into the radios dir (using my existing config as an example), or create your own:
|
- desktop.json contains a stream hosted using the following:
|
||||||
- [Icecast](https://icecast.org/) or another web radio server
|
- [Icecast](https://icecast.org/) or another web radio server
|
||||||
- I'm personally using [AzuraCast](https://www.azuracast.com/), which uses Icecast under the hood, but with arm64 support!
|
- I'm personally using [AzuraCast](https://www.azuracast.com/), which uses Icecast under the hood, but with arm64 support!
|
||||||
- [butt](https://danielnoethen.de/butt/)
|
- [butt](https://danielnoethen.de/butt/)
|
||||||
- This is really just if you want to f.e. stream your PC audio to your internet radio.
|
- This is really just if you want to f.e. stream your PC audio to your internet radio.
|
||||||
- ???
|
|
||||||
- Profit!
|
|
||||||
|
|
||||||
**TL;DR: Set up a web server on ports 80 and 443, make it use `index.php` for every request, play around with the `radios` folder.**
|
|
||||||
|
|
||||||
|
|
||||||
## Any hints for following your footsteps?
|
## Any hints for following your footsteps?
|
||||||
|
92
index.php
92
index.php
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// Config
|
||||||
|
|
||||||
$GLOBALS["frairable_host"] = getenv("FRAIRABLE_HOST");
|
$GLOBALS["frairable_host"] = getenv("FRAIRABLE_HOST");
|
||||||
if (empty($GLOBALS["frairable_host"])) {
|
if (empty($GLOBALS["frairable_host"])) {
|
||||||
$GLOBALS["frairable_host"] = "https://airable.wifiradiofrontier.com";
|
$GLOBALS["frairable_host"] = "https://airable.wifiradiofrontier.com";
|
||||||
@ -11,10 +13,21 @@ if (empty($GLOBALS["frairable_dir_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) {
|
function respond_with_raw(&$data) {
|
||||||
ob_start();
|
ob_start();
|
||||||
{
|
{
|
||||||
ob_start("ob_data");
|
ob_start();
|
||||||
{
|
{
|
||||||
echo($data);
|
echo($data);
|
||||||
ob_end_flush();
|
ob_end_flush();
|
||||||
@ -28,21 +41,11 @@ function respond_with_raw(&$data) {
|
|||||||
function respond_with_json(&$data) {
|
function respond_with_json(&$data) {
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
ob_start();
|
$data = json_encode($data);
|
||||||
{
|
respond_with_raw($data);
|
||||||
ob_start("ob_data");
|
|
||||||
{
|
|
||||||
echo(json_encode($data));
|
|
||||||
ob_end_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
header("Content-Length: " . ob_get_length());
|
|
||||||
ob_end_flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function respond_with_proxy($cb = NULL) {
|
||||||
function airable_proxy($cb = NULL) {
|
|
||||||
$ch = curl_init("$GLOBALS[frairable_host]$_SERVER[REQUEST_URI]");
|
$ch = curl_init("$GLOBALS[frairable_host]$_SERVER[REQUEST_URI]");
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
@ -54,7 +57,7 @@ function airable_proxy($cb = NULL) {
|
|||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
"Accept: " . ($headers_req["Accept"] ?? "audio/aac;mp3;dash"),
|
"Accept: " . ($headers_req["Accept"] ?? "audio/aac;mp3;dash"),
|
||||||
"Accept-Language: " . ($headers_req["Accept-Language"] ?? "en-US"),
|
"Accept-Language: " . ($headers_req["Accept-Language"] ?? "en-US"),
|
||||||
"Authorization: " . ($headers_req["Authorization"] ?? "true"),
|
"Authorization: " . ($headers_req["Authorization"] ?? "????"),
|
||||||
"Connection: " . ($headers_req["Connection"] ?? "Close"),
|
"Connection: " . ($headers_req["Connection"] ?? "Close"),
|
||||||
"Content-Length: " . ($headers_req["Content-Length"] ?? "0"),
|
"Content-Length: " . ($headers_req["Content-Length"] ?? "0"),
|
||||||
"User-Agent: " . ($headers_req["User-Agent"] ?? "ir-cui-FS2340-0000-0165_V4.5.13.707296-1A17")
|
"User-Agent: " . ($headers_req["User-Agent"] ?? "ir-cui-FS2340-0000-0165_V4.5.13.707296-1A17")
|
||||||
@ -105,6 +108,9 @@ function airable_proxy($cb = NULL) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Radio data manglers
|
||||||
|
|
||||||
function get_radio_data($id) {
|
function get_radio_data($id) {
|
||||||
$path = $GLOBALS["frairable_dir_radios"] . DIRECTORY_SEPARATOR . $id . ".json";
|
$path = $GLOBALS["frairable_dir_radios"] . DIRECTORY_SEPARATOR . $id . ".json";
|
||||||
$path = realpath($path);
|
$path = realpath($path);
|
||||||
@ -121,8 +127,10 @@ function get_radio_entry($id) {
|
|||||||
$data = get_radio_data($id);
|
$data = get_radio_data($id);
|
||||||
|
|
||||||
$data["contains"] = [];
|
$data["contains"] = [];
|
||||||
$data["id"] = ["frontiersmart", "radio", "custom=$id"];
|
|
||||||
$data["url"] = "$GLOBALS[frairable_host]/frontiersmart/radio/custom=$id";
|
// 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"]);
|
unset($data["streams"]);
|
||||||
|
|
||||||
@ -132,11 +140,11 @@ function get_radio_entry($id) {
|
|||||||
function get_radio_meta($id) {
|
function get_radio_meta($id) {
|
||||||
$data = get_radio_data($id);
|
$data = get_radio_data($id);
|
||||||
|
|
||||||
$data["id"] = ["frontiersmart", "radio", "custom=$id"];
|
$data["id"] = ["frontiersmart", "radio", "$GLOBALS[frairable_part_custom]$id"];
|
||||||
$data["url"] = "$GLOBALS[frairable_host]/frontiersmart/radio/custom=$id";
|
$data["url"] = "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_meta]$id";
|
||||||
|
|
||||||
foreach ($data["streams"] as $index => &$stream) {
|
foreach ($data["streams"] as $index => &$stream) {
|
||||||
$stream["url"] = "$GLOBALS[frairable_host]/frontiersmart/radio/custom=$id/play=$index";
|
$stream["url"] = "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_meta]$id/$GLOBALS[frairable_part_play]$index";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@ -145,11 +153,13 @@ function get_radio_meta($id) {
|
|||||||
function get_radio_play($id, $index) {
|
function get_radio_play($id, $index) {
|
||||||
$data = get_radio_data($id);
|
$data = get_radio_data($id);
|
||||||
|
|
||||||
// clone loves to complain about the stream not being an object...
|
// Clone loves to complain about the stream not being an object...
|
||||||
// deep clone using json is ugly, but eh.
|
// Deep clone using json is ugly, but eh.
|
||||||
$stream = json_decode(json_encode($data["streams"][$index]), true);
|
$stream = json_decode(json_encode($data["streams"][$index]), true);
|
||||||
|
|
||||||
$stream["id"] = ["frontiersmart", "redirect", "custom=$id/play=$index"];
|
// 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;
|
$stream["content"] = $data;
|
||||||
|
|
||||||
unset($stream["reliability"]);
|
unset($stream["reliability"]);
|
||||||
@ -157,8 +167,14 @@ function get_radio_play($id, $index) {
|
|||||||
return $stream;
|
return $stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Routing
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
||||||
airable_proxy(function(&$data) {
|
// Stock starting point - add our own entry here.
|
||||||
|
|
||||||
|
respond_with_proxy(function(&$data) {
|
||||||
array_push($data["content"]["entries"], [
|
array_push($data["content"]["entries"], [
|
||||||
"id" => [
|
"id" => [
|
||||||
"frontiersmart",
|
"frontiersmart",
|
||||||
@ -166,11 +182,14 @@ if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
|||||||
"custom"
|
"custom"
|
||||||
],
|
],
|
||||||
"title" => "Frairable (Custom)",
|
"title" => "Frairable (Custom)",
|
||||||
"url" => "$GLOBALS[frairable_host]/frontiersmart/radios/custom"
|
"url" => "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_listing]"
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
} elseif ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios/custom") {
|
|
||||||
|
} elseif ($_SERVER["REQUEST_URI"] === $GLOBALS["frairable_uri_listing"]) {
|
||||||
|
// Our custom menu with our own entries.
|
||||||
|
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
foreach (new DirectoryIterator($GLOBALS["frairable_dir_radios"]) as $sub) {
|
foreach (new DirectoryIterator($GLOBALS["frairable_dir_radios"]) as $sub) {
|
||||||
@ -190,7 +209,7 @@ if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
|||||||
"custom"
|
"custom"
|
||||||
],
|
],
|
||||||
"title" => "Frairable (Custom)",
|
"title" => "Frairable (Custom)",
|
||||||
"url" => "$GLOBALS[frairable_host]$_SERVER[REQUEST_URI]",
|
"url" => "$GLOBALS[frairable_host]$GLOBALS[frairable_uri_listing]",
|
||||||
"content" => [
|
"content" => [
|
||||||
"entries" => $entries
|
"entries" => $entries
|
||||||
]
|
]
|
||||||
@ -198,12 +217,18 @@ if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
|||||||
|
|
||||||
respond_with_json($data);
|
respond_with_json($data);
|
||||||
|
|
||||||
} elseif (str_starts_with($_SERVER["REQUEST_URI"], "/frontiersmart/radio/custom=")) {
|
|
||||||
$id = substr($_SERVER["REQUEST_URI"], strlen("/frontiersmart/radio/custom="));
|
|
||||||
|
|
||||||
$split = strpos($id, "/play=");
|
} 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) {
|
if ($split) {
|
||||||
$index = intval(substr($id, $split + strlen("/play=")));
|
$index = intval(substr($id, $split + strlen("/$GLOBALS[frairable_part_play]")));
|
||||||
$id = substr($id, 0, $split);
|
$id = substr($id, 0, $split);
|
||||||
respond_with_json(get_radio_play($id, $index));
|
respond_with_json(get_radio_play($id, $index));
|
||||||
|
|
||||||
@ -211,8 +236,11 @@ if ($_SERVER["REQUEST_URI"] === "/frontiersmart/radios") {
|
|||||||
respond_with_json(get_radio_meta($id));
|
respond_with_json(get_radio_meta($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
airable_proxy();
|
respond_with_proxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
@ -22,7 +22,7 @@
|
|||||||
"samplerate": 48
|
"samplerate": 48
|
||||||
},
|
},
|
||||||
"reliability": 0.99,
|
"reliability": 0.99,
|
||||||
"url": "http://icecast.toriel.0x0a.de/desktop.mp3"
|
"url": "http://azuracast.toriel.0x0a.de/listen/toriel_radio/radio.mp3"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user