tidy up formatting

This commit is contained in:
Ben Harris 2021-09-12 20:13:59 -04:00
parent af6bb5e0df
commit e5b4379406
10 changed files with 214 additions and 205 deletions

View File

@ -5,7 +5,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://tilde.team/css/hacker.css"> <link rel="stylesheet" href="/css/hacker.css">
<title>tilderadio dj info</title> <title>tilderadio dj info</title>
</head> </head>

View File

@ -1,6 +1,8 @@
<footer class="text-center"> <footer class="text-center">
<a href="https://tildegit.org/tilderadio/site">page source</a> | <a href="/dmca.php">DMCA</a> <a href="https://tildegit.org/tilderadio/site">page source</a> | <a href="/dmca.php">DMCA</a>
</footer> </footer>
</div>
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script> <script src="/js/bootstrap.min.js"></script>

View File

@ -8,8 +8,8 @@
</title> </title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/hacker.css"> <link rel="stylesheet" href="/css/hacker.css">
<link rel="stylesheet" href="/css/calendar.css"> <link rel="icon" type="image/png" href="/logos/tilderadio.png">
<link rel="icon" type="image/png" href="https://tilderadio.org/logos/tilderadio.png"><?=isset($additional_head)?PHP_EOL." ".$additional_head.PHP_EOL:""?> <?=isset($additional_head) ? PHP_EOL . " " . $additional_head . PHP_EOL : ""?>
</head> </head>
<body> <body>
@ -36,4 +36,9 @@
</nav> </nav>
</div> </div>
<br> <br>
<br> <br>
<div class="container">
<h1>
<a href="/"><img style="width:72px;margin-top:-30px;margin-right:5px;" src="/logos/tilderadio.png" alt="">tilderadio.org</a>
</h1>
<hr>

View File

@ -1,16 +1,18 @@
<?php include 'header.php'; ?> <?php include 'header.php'; ?>
<h1> <blockquote><?=json_decode(file_get_contents("https://bot.tildegit.org/api/slogan"))?></blockquote>
<a href="/"><img style="width:72px;margin-top:-30px;margin-right:5px;" src="./logos/tilderadio.png" alt="">tilderadio.org</a>
</h1> <p>tilderadio is internet radio streamed by / for users of the <a href="https://tildeverse.org/">tildeverse</a>.</p>
<h4><?=json_decode(file_get_contents("https://bot.tildegit.org/api/slogan"))?></h4>
<p> <p>
TildeRadio is Internet radio streamed by / for users of the <a href="https://tildeverse.org/">tildeverse</a>. <a href="https://tilde.chat/kiwi/#tilderadio" target="_blank">Join us in #tilderadio</a>,
our dedicated IRC channel on <a href="https://tilde.chat">tilde.chat</a>
</p> </p>
<p><a href="https://kiwi.tilde.chat/#tilderadio" target="_blank">Join us in #tilderadio</a>, our dedicated IRC channel on <a href="https://tilde.chat">tilde.chat</a></p> <p>
<p>Follow us on Mastodon where we announce when DJ's go live! <a href="https://tilde.zone/@tilderadio" target="_blank">@tilderadio</a></p> follow us on mastodon where we announce when DJ's go live!
<a href="https://tilde.zone/@tilderadio" target="_blank">@tilderadio</a>
</p>
<hr> <hr>
@ -19,13 +21,11 @@ TildeRadio is Internet radio streamed by / for users of the <a href="https://til
<iframe src="https://azuracast.tilderadio.org/public/tilderadio/embed" style="width: 100%; min-height: 160px; border: 0;"></iframe> <iframe src="https://azuracast.tilderadio.org/public/tilderadio/embed" style="width: 100%; min-height: 160px; border: 0;"></iframe>
<p> <p>Or use the following links in your media player of choice:</p>
Or use the following links in your media player of choice:
</p>
<ul> <ul>
<li>https://azuracast.tilderadio.org/radio/8000/radio.ogg</li> <li>https://azuracast.tilderadio.org/radio/8000/radio.ogg</li>
<li>https://azuracast.tilderadio.org/radio/8000/radio.mp3</li> <li>https://azuracast.tilderadio.org/radio/8000/radio.mp3</li>
</ul> </ul>
<hr> <hr>

View File

@ -1,3 +1,2 @@
<?php <?php
$apikey = "my azuracast api key"; $apikey = "my azuracast api key";

View File

@ -2,99 +2,91 @@
<h4>upcoming broadcasts</h4> <h4>upcoming broadcasts</h4>
<?php <?php
function check_in_range($start_date, $end_date, $checkdate) { function check_in_range($start_date, $end_date, $checkdate) {
$start_ts = strtotime($start_date); $start_ts = strtotime($start_date);
$end_ts = strtotime($end_date); $end_ts = strtotime($end_date);
$ch_ts = strtotime($checkdate); $ch_ts = strtotime($checkdate);
return (($ch_ts >= $start_ts) && ($ch_ts < $end_ts)); return (($ch_ts >= $start_ts) && ($ch_ts < $end_ts));
} }
// Create a date range between the schedule start and end dates // Create a date range between the schedule start and end dates
$begin = new DateTime($schedule[0]['start']); $begin = new DateTime($schedule[0]['start']);
$end = new DateTime(end($schedule)['start']); $end = new DateTime(end($schedule)['start']);
$daterange = new DatePeriod($begin, new DateInterval('P1D'), $end); $daterange = new DatePeriod($begin, new DateInterval('P1D'), $end);
?> ?>
<table class="calendar"> <table class="calendar">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<?php <?php
// Loop over our date range to draw the headers // Loop over our date range to draw the headers
foreach($daterange as $date){ foreach($daterange as $date){ ?>
?> <th>
<th> <span class="day"><?php echo $date->format("d") ?></span>
<span class="day"><?php echo $date->format("d") ?></span> <span class="long"><?php echo $date->format("l") ?></span>
<span class="long"><?php echo $date->format("l") ?></span> <span class="short"><?php echo $date->format("D") ?></span>
<span class="short"><?php echo $date->format("D") ?></span> </th>
</th> <?php } ?>
<?php </tr>
} </thead>
?> <tbody>
</tr>
</thead>
<tbody>
<?php <?php
// time will count us by 30-min increments through the day // time will count us by 30-min increments through the day
$time = mktime(0, 0, 0, 1, 1); $time = mktime(0, 0, 0, 1, 1);
// Loop over the day in 30 min increments // Loop over the day in 30 min increments
for ($i = 0; $i < 86400; $i += 1800) { for ($i = 0; $i < 86400; $i += 1800) { ?>
?>
<tr> <tr>
<?php <?php
// Only show row if we're on a full hour block. It's a rowspan 2 // Only show row if we're on a full hour block. It's a rowspan 2
if ((($i / 1800) % 2) === 0 ) { if ((($i / 1800) % 2) === 0 ) { ?>
?> <td class="hour" rowspan="2"><span><?php echo date('H', $time + $i) ?>:00</span></td>
<td class="hour" rowspan="2"><span><?php echo date('H', $time + $i) ?>:00</span></td> <?php } ?>
<?php
}
?>
<?php <?php
$now = new DateTime(); $now = new DateTime();
$halfhour = new DateInterval('PT30M'); $halfhour = new DateInterval('PT30M');
$wrotepointer = false; $wrotepointer = false;
// Loop over each day of the week for this 30 min span // Loop over each day of the week for this 30 min span
foreach($daterange as $date){ foreach ($daterange as $date) {
// merge date (changing days) and time (incrementing by 30 min) to draw calendar by row. // merge date (changing days) and time (incrementing by 30 min) to draw calendar by row.
$merge = new DateTime($date->format('Y-m-d') .' ' .date('H:i:s', $time + $i)); $merge = new DateTime($date->format('Y-m-d') . ' ' . date('H:i:s', $time + $i));
// Set id for this time span, for referencing in JS. // Set id for this time span, for referencing in JS.
$props = 'id="show-'.$merge->getTimestamp().'"'; $props = 'id="show-' . $merge->getTimestamp() . '"';
// We'll now use $merge to see if any shows are airing at this time // We'll now use $merge to see if any shows are airing at this time
$matchedshow = null; $matchedshow = null;
foreach ($schedule as $show) { foreach ($schedule as $show) {
if (check_in_range($show['start'], $show['end'], $merge->format('Y-m-d H:i:s'))) { if (check_in_range($show['start'], $show['end'], $merge->format('Y-m-d H:i:s'))) {
$matchedshow = $show; $matchedshow = $show;
break; break;
} }
}
$active = false;
if (!$wrotepointer) {
// If current time is in this range, draw pointer.
$end = DateTimeImmutable::createFromMutable($merge)->add($halfhour);
if ($now >= $merge && $now < $end) {
$active = true;
$props .= ' class="active"';
}
}
echo "<td $props>";
if ($matchedshow) {
echo '<div class="show-title">' . $matchedshow['title'] . '</div>';
// if no match was found, leave an empty node
}
if ($active) {
// Cell height here should be synced with height of '.calendar tbody tr td' in ../css/calendar.css
$height = 32;
$top = round(date_diff($merge, $now)->format('%i') / 30 * ($height-1));
echo '<div id="pointer" style="top:'.$top.'px"></div>';
$wrotepointer = true;
}
echo "</td>\n";
} }
$active = false; ?>
if (!$wrotepointer) {
// If current time is in this range, draw pointer.
$end = DateTimeImmutable::createFromMutable($merge)->add($halfhour);
if ($now >= $merge && $now < $end) {
$active = true;
$props .= ' class="active"';
}
}
echo "<td $props>";
if ($matchedshow) {
echo '<div class="show-title">'.$matchedshow['title'].'</div>';
// if no match was found, leave an empty node
}
if ($active) {
// Cell height here should be synced with height of '.calendar tbody tr td' in ../css/calendar.css
$height = 32;
$top = round(date_diff($merge, $now)->format('%i') / 30 * ($height-1));
echo '<div id="pointer" style="top:'.$top.'px"></div>';
$wrotepointer = true;
}
echo "</td>\n";
}
?>
</tr> </tr>
<?php <?php } ?>
} </tbody>
?>
</tbody>
</table> </table>
</section> </section>

View File

@ -1,6 +1,6 @@
<?php <?php
$from = gmdate("Y-m-d\T00:00:00\Z",strtotime("today")); $from = gmdate("Y-m-d\T00:00:00\Z", strtotime("today"));
$to = gmdate("Y-m-d\T00:00:00\Z",strtotime("today + 8 days")); $to = gmdate("Y-m-d\T00:00:00\Z", strtotime("today + 8 days"));
include 'schedule.php'; include 'schedule.php';
function ics_formatdate($date) { function ics_formatdate($date) {
@ -19,56 +19,57 @@ header('Content-Disposition: attachment; filename="tilderadio.ics"');
define("ICS_EOL","\r\n"); define("ICS_EOL","\r\n");
// Header. // Header.
echo "BEGIN:VCALENDAR".ICS_EOL; echo "BEGIN:VCALENDAR" . ICS_EOL;
echo "VERSION:2.0".ICS_EOL; echo "VERSION:2.0" . ICS_EOL;
echo "PRODID:tilderadio schedule".ICS_EOL; echo "PRODID:tilderadio schedule" . ICS_EOL;
echo "DTSTAMP:".ics_formatdate("now").ICS_EOL; echo "DTSTAMP:" . ics_formatdate("now") . ICS_EOL;
// A list of event IDs that we have on the calendar, to avoid duplication // A list of event IDs that we have on the calendar, to avoid duplication
$event_ids = array(); $event_ids = [];
foreach ($schedule as $event) { foreach ($schedule as $event) {
$id = strval($event["id"]).gmdate("DHis",strtotime($event["start"])).gmdate("DHis",strtotime($event["end"])); $id = strval($event["id"]) . gmdate("DHis", strtotime($event["start"])) . gmdate("DHis", strtotime($event["end"]));
if (!in_array($id,$event_ids)){
array_push($event_ids,$id); if (!in_array($id,$event_ids)) {
array_push($event_ids, $id);
// The VEVENT structure's pretty easy to generate, especially since we're already in UTC. // The VEVENT structure's pretty easy to generate, especially since we're already in UTC.
echo "BEGIN:VEVENT".ICS_EOL; echo "BEGIN:VEVENT" . ICS_EOL;
// First, we need a creation date. // First, we need a creation date.
// Just go with now. // Just go with now.
echo "DTSTAMP:".ics_formatdate("now").ICS_EOL; echo "DTSTAMP:" . ics_formatdate("now") . ICS_EOL;
// Next, the event start and end. // Next, the event start and end.
echo "DTEND:".ics_formatdate($event["end"]).ICS_EOL; echo "DTEND:" . ics_formatdate($event["end"]) . ICS_EOL;
echo "DTSTART:".ics_formatdate($event["start"]).ICS_EOL; echo "DTSTART:" . ics_formatdate($event["start"]) . ICS_EOL;
// Next, the recurrence rule. // Next, the recurrence rule.
if ($event["title"]!="tomasino") { if ($event["title"] != "tomasino") {
// We assume the format is weekly. (tomasino is the only DJ to have requested any other frequency.) // We assume the format is weekly. (tomasino is the only DJ to have requested any other frequency.)
echo "RRULE:FREQ=WEEKLY".ICS_EOL; echo "RRULE:FREQ=WEEKLY" . ICS_EOL;
} else { } else {
// TTT only comes on the last Sunday of the month, 23:30:00 UTC to 01:00:00 UTC // TTT only comes on the last Sunday of the month, 23:30:00 UTC to 01:00:00 UTC
if (gmdate("His",strtotime($event["start"]))=="233000" && gmdate("His",strtotime($event["end"]))=="010000") { if (gmdate("His", strtotime($event["start"])) == "233000" && gmdate("His", strtotime($event["end"])) == "010000") {
echo "RRULE:FREQ=MONTHLY;WKST=SU;BYDAY=SU;BYSETPOS=-1".ICS_EOL; echo "RRULE:FREQ=MONTHLY;WKST=SU;BYDAY=SU;BYSETPOS=-1" . ICS_EOL;
} else { } else {
// his other shows are weekly though // his other shows are weekly though
echo "RRULE:FREQ=WEEKLY".ICS_EOL; echo "RRULE:FREQ=WEEKLY" . ICS_EOL;
} }
} }
// Next, the event title, or "summary" as the spec calls it. // Next, the event title, or "summary" as the spec calls it.
echo "SUMMARY:DJ ".$event["title"].ICS_EOL; echo "SUMMARY:DJ " . $event["title"] . ICS_EOL;
// Finally, a unique ID for this event. // Finally, a unique ID for this event.
// To make absolutely certain we don't repeat the same event ID, I decided to use a SHA256 hash of the event structure. // To make absolutely certain we don't repeat the same event ID, I decided to use a SHA256 hash of the event structure.
echo "UID:"; echo "UID:";
echo hash("sha256",json_encode($event)); echo hash("sha256", json_encode($event));
// to avoid the validator complaining about lines longer than 75 characters, split after the hash // to avoid the validator complaining about lines longer than 75 characters, split after the hash
echo ICS_EOL." "; echo ICS_EOL . " ";
// Now finish the address UID // Now finish the address UID
echo "@tilderadio.org".ICS_EOL; echo "@tilderadio.org" . ICS_EOL;
// Finally, close the VEVENT structure. // Finally, close the VEVENT structure.
echo "END:VEVENT".ICS_EOL; echo "END:VEVENT" . ICS_EOL;
// Next event? // Next event?
} }
} }
// Finally, close out the VCALENDAR structure. // Finally, close out the VCALENDAR structure.
echo "END:VCALENDAR".ICS_EOL; echo "END:VCALENDAR" . ICS_EOL;
?> ?>

View File

@ -1,13 +1,19 @@
<?php <?php
$additional_head='<link rel="alternate" type="text/calendar" href="https://tilderadio.org/schedule/ics.php">'; $additional_head='<link rel="stylesheet" href="/css/calendar.css">
include '../header.php'; <link rel="alternate" type="text/calendar" href="https://tilderadio.org/schedule/ics.php">';
include __DIR__ . '/../header.php';
include 'schedule.php'; include 'schedule.php';
?> ?>
<h1><a href="https://tilderadio.org"><img style="width:72px;margin-top:-30px;margin-right:5px;" src="../logos/tilderadio.png" alt="tilderadio logo">tilderadio.org</a></h1> <p>
<p>all times in UTC. current time is <span id="utcdate"><?=formatdate("now")?></span> all times in UTC. current time is <span id="utcdate"><?=formatdate("now")?></span>
<span class="pointer-label-wrapper">(</span><span class="pointer-label">&mdash;</span><span class="pointer-label-wrapper">)</span>.</p> <span class="pointer-label-wrapper">(</span><span class="pointer-label">&mdash;</span><span class="pointer-label-wrapper">)</span>.
<p>this schedule is also available in <a href="https://icalendar.org/validator.html?url=https://tilderadio.org/schedule/ics.php">iCalendar format</a>. point your calendar client at <code>https://tilderadio.org/schedule/ics.php</code>.</p> </p>
<p>
this schedule is also available in <a href="https://icalendar.org/validator.html?url=https://tilderadio.org/schedule/ics.php">iCalendar format</a>.
point your calendar client at <code>https://tilderadio.org/schedule/ics.php</code>.
</p>
<?php <?php
include 'calendar.php'; include 'calendar.php';
@ -63,15 +69,19 @@ function getCurrentRange(now) {
// Update the timer and pointer as time passes. // Update the timer and pointer as time passes.
// Because PHP gives the time on page load, people who disable Javascript won't be missing out on much. // Because PHP gives the time on page load, people who disable Javascript won't be missing out on much.
let months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
let daysOfWeek = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]; let daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
function update_date() { function update_date() {
var d = new Date(); var d = new Date();
document.getElementById("utcdate").innerText = daysOfWeek[d.getUTCDay()]+" "+months[d.getUTCMonth()]+" "+d.getUTCDate().toString()+" "+d.getUTCHours().toString().padStart(2,'0')+":"+d.getUTCMinutes().toString().padStart(2,'0'); document.getElementById("utcdate").innerText =
setTimeout(update_date,15000); daysOfWeek[d.getUTCDay()] + " " + months[d.getUTCMonth()] + " " +
d.getUTCDate().toString() + " " + d.getUTCHours().toString().padStart(2,'0') +
":" + d.getUTCMinutes().toString().padStart(2,'0');
setTimeout(update_date, 15000);
updatePointer(d); updatePointer(d);
} }
setTimeout(update_date,15000); setTimeout(update_date, 15000);
let pointer = document.getElementById("pointer"); let pointer = document.getElementById("pointer");
// Create pointer in case it wasn't added in the page generation. // Create pointer in case it wasn't added in the page generation.
@ -102,11 +112,10 @@ function updatePointer(d) {
} }
// Move pointer based on time in current cell. // Move pointer based on time in current cell.
const progress = (d.getTime() - range.startTime) / halfHour; const progress = (d.getTime() - range.startTime) / halfHour;
pointer.style.top = (progress * (range.cell.offsetHeight-1)).toFixed(0) + 'px'; pointer.style.top = (progress * (range.cell.offsetHeight - 1)).toFixed(0) + 'px';
} }
// Update pointer immediately // Update pointer immediately
updatePointer(new Date()); updatePointer(new Date());
</script> </script>
<?php include '../footer.php'; ?> <?php include __DIR__.'/../footer.php'; ?>

View File

@ -2,53 +2,54 @@
include 'apikey.php'; include 'apikey.php';
if (empty($apikey)) { if (empty($apikey)) {
/* If we don't have the API key, assume we're developing. Pull data from live version of this file */ /* If we don't have the API key, assume we're developing. Pull data from live version of this file */
$context = stream_context_create([ $context = stream_context_create([
"http" => [ "http" => [
"method" => "GET", "method" => "GET",
] ]
]); ]);
$schedule = json_decode(file_get_contents("https://tilderadio.org/schedule/nextdj.php?json=true", false, $context), true); $schedule = json_decode(file_get_contents("https://tilderadio.org/schedule/nextdj.php?json=true", false, $context), true);
} else { } else {
$context = stream_context_create([ $context = stream_context_create([
"http" => [ "http" => [
"method" => "GET", "method" => "GET",
"header" => "X-API-Key: $apikey\r\n" "header" => "X-API-Key: $apikey\r\n"
] ]
]); ]);
$schedule = json_decode( $schedule = json_decode(
file_get_contents( file_get_contents(
"https://azuracast.tilderadio.org/api/station/1/schedule?rows=2", "https://azuracast.tilderadio.org/api/station/1/schedule?rows=2",
false, false,
$context $context
), ),
true true
); );
} }
if (isset($_GET["json"]) && $_GET["json"] === "yes") { if (isset($_GET["json"]) && $_GET["json"] === "yes") {
echo json_encode($schedule); echo json_encode($schedule);
} else { } else {
$data = $schedule[0]; $data = $schedule[0];
if ((strtotime($data["start"])-strtotime("now"))<0) { if ((strtotime($data["start"]) - strtotime("now")) < 0) {
echo $data["name"]." should be streaming now, and "; echo $data["name"] . " should be streaming now, and ";
$data = $schedule[1]; $data = $schedule[1];
} }
echo $data["name"]." will stream at ".gmdate("D M d H:i",strtotime($data["start"]))." UTC (in "; echo $data["name"] . " will stream at " . gmdate("D M d H:i", strtotime($data["start"])) . " UTC (in ";
$diff = strtotime($data["start"])-strtotime("now");
if ($diff<60) { $diff = strtotime($data["start"]) - strtotime("now");
echo "".$diff." seconds)"; if ($diff < 60) {
} else { echo "" . $diff . " seconds)";
$minutes = intdiv($diff,60); } else {
$seconds = $diff % 60; $minutes = intdiv($diff, 60);
if ($minutes<60) { $seconds = $diff % 60;
echo "".$minutes." minutes and ".$seconds." seconds)"; if ($minutes<60) {
} else { echo "" . $minutes . " minutes and " . $seconds . " seconds)";
$hours = intdiv($minutes,60); } else {
$minutes = $minutes % 60; $hours = intdiv($minutes, 60);
echo "".$hours." hours, ".$minutes." minutes and ".$seconds." seconds)"; $minutes = $minutes % 60;
} echo "" . $hours . " hours, " . $minutes . " minutes and " . $seconds . " seconds)";
} }
echo "."; }
echo ".";
} }

View File

@ -2,35 +2,35 @@
include 'apikey.php'; include 'apikey.php';
if (empty($apikey)) { if (empty($apikey)) {
/* If we don't have the API key, assume we're developing. Pull data from live version of this file */ /* If we don't have the API key, assume we're developing. Pull data from live version of this file */
$context = stream_context_create([ $context = stream_context_create([
"http" => [ "http" => [
"method" => "GET", "method" => "GET",
] ]
]); ]);
$schedule = json_decode(file_get_contents("https://tilderadio.org/schedule/schedule.php?json=yes", false, $context), true); $schedule = json_decode(file_get_contents("https://tilderadio.org/schedule/schedule.php?json=yes", false, $context), true);
} else { } else {
$context = stream_context_create([ $context = stream_context_create([
"http" => [ "http" => [
"method" => "GET", "method" => "GET",
"header" => "X-API-Key: $apikey\r\n" "header" => "X-API-Key: $apikey\r\n"
] ]
]); ]);
// allow ics.php to overwrite $from and $to // allow ics.php to overwrite $from and $to
if (!isset($from,$to)) { if (!isset($from, $to)) {
$from = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 1 day")); $from = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 1 day"));
$to = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 8 days")); $to = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 8 days"));
} }
$schedule = json_decode( $schedule = json_decode(
file_get_contents( file_get_contents(
"https://azuracast.tilderadio.org/api/station/1/streamers/schedule?start=$from&end=$to", "https://azuracast.tilderadio.org/api/station/1/streamers/schedule?start=$from&end=$to",
false, false,
$context $context
), ),
true true
); );
} }
usort($schedule, function ($a, $b) { usort($schedule, function ($a, $b) {