Commit 26cf5bc8 authored by david's avatar david
Browse files

Improved loading behaviour. #1

parent 4869c19e
html, body {
position: relative;
width: 100%;
height: 100%;
}
body {
color: #333;
margin: 0;
padding: 8px;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
a {
color: rgb(0,100,200);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:visited {
color: rgb(0,80,160);
}
label {
display: block;
}
input, button, select, textarea {
font-family: inherit;
font-size: inherit;
padding: 0.4em;
margin: 0 0 0.5em 0;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 2px;
}
input:disabled {
color: #ccc;
}
input[type="range"] {
height: 0;
}
button {
color: #333;
background-color: #f4f4f4;
outline: none;
}
button:disabled {
color: #999;
}
button:not(:disabled):active {
background-color: #ddd;
}
button:focus {
border-color: #666;
}
......@@ -19,9 +19,10 @@
logo="https://o94.at/themes/custom/radio_orange/logo1.png"
logosize="180px"
api="http://localhost:8008/api/v1/"
css="http://localhost:8008/css/aura.css"
css="/sample/o94.css"
unknowntitle="Unbekannter Titel"
noschedulemessage="Keine weiteren Sendungen!"
nocurrentschedule="Derzeit keine Sendung"
nonextschedule="Keine weiteren Sendungen"
playoffset=3>
</aura-clock>
......
<svelte:options tag="aura-clock"/>
<main bind:this={rootElement}></main>
<script>
import { onMount } from 'svelte';
import { onMount, afterUpdate } from 'svelte';
export let css = "";
export let api = "http://localhost:8008/api/v1/";
export let name = "Studio Clock";
export let logo = "https://gitlab.servus.at/aura/meta/-/raw/master/images/aura-logo.png";
export let logosize = "100px";
export let noschedulemessage = "Nothing scheduled next!";
export let nocurrentschedule = "Right now, there's no show playing";
export let nonextschedule = "Nothing scheduled next!";
export let unknowntitle = "Unknown Title";
export let playoffset = 3;
let time = new Date();
let queryCurrent = "clock";
let rootElement;
let data;
let currentTrack = null;
let promise;
let prevClockData = null;
let clockData = null;
let currentTrackElement = null;
let timeLeft;
let scheduleTimeLeft = 0;
let reloadTime = 10;
let reloadWait = 0;
// these automatically update when `time`
// changes, because of the `$:` prefix
......@@ -25,19 +30,26 @@
$: minutes = time.getMinutes();
$: seconds = time.getSeconds();
data = fetchApi(queryCurrent);
promise = fetchApi(queryCurrent);
/* When component is mounted to the DOM */
onMount(() => {
const interval = setInterval(() => {
time = new Date();
timeLeft -= 1;
scheduleTimeLeft -= 1;
if (timeLeft <= 0 || data == null) {
currentTrack = null;
data = null;
data = fetchApi(queryCurrent);
/* End of track or end of schedule - load new data */
if (timeLeft <= 0 || scheduleTimeLeft <= 0) {
/* For some seconds refresh every second, to work around API timing delays */
if (timeLeft <= 0 && timeLeft >= -3 || scheduleTimeLeft <= 0 && scheduleTimeLeft >= -3 || reloadWait == 0) {
promise = fetchApi(queryCurrent);
reloadWait = reloadTime;
}
reloadWait -= 1;
}
}, 1000);
return () => {
......@@ -45,7 +57,14 @@
};
});
/* Load Clock data from the API */
/* Called after the component has been updated */
afterUpdate(async () => {
scrollToActiveTrack();
});
/* Load clock data from the API */
async function fetchApi(query) {
let response;
let data;
......@@ -71,26 +90,61 @@
}
}
/* Initialize the component */
function initComponent(info) {
function initComponent(value) {
/* Load external CSS */
if (css != null)
loadExternalCss(rootElement, css);
/* Set currently loaded data */
if (currentTrack == null && info != null && info.current_track != null) {
currentTrack = info;
if (value != null) {
clockData = value;
console.log("Current Data", value);
let t = time - Date.parse(info.current_track.track_start);
if (value.current_track != null) {
let t = time - Date.parse(value.current_track.track_start);
t = parseInt(t/1000);
timeLeft = value.current_track.track_duration - t - playoffset;
}
timeLeft = info.current_track.track_duration - t - playoffset;
console.log("Current Data", info);
if (value.current_schedule != null) {
let schedule_end = Date.parse(value.current_schedule.schedule_end);
schedule_end = parseInt(schedule_end/1000);
scheduleTimeLeft = schedule_end - time;
} else {
/* Decrease time left in any case to avoid reloading too often */
scheduleTimeLeft -= 1;
}
}
return "";
}
/* Checks if there's an existing, valid schedule */
function hasValidSchedule(value) {
if (value.current_schedule != null) {
if (value.current_schedule.schedule_end != null) {
let schedule_end = Date.parse(value.current_schedule.schedule_end);
let diff = schedule_end - time;
if (diff >= 0)
return true;
}
}
return false;
}
/* Checks if there is an existing valid playlist */
function hasValidPlaylist(value) {
if (hasValidSchedule(value))
if (value.current_playlist != null)
return true;
return false;
}
/* Display the title of a track */
function displayTitle(track) {
if (track != null) {
......@@ -105,6 +159,7 @@
return "";
}
/* Format the time */
function formatTime(seconds) {
if (seconds != null && Number.isInteger(seconds)) {
......@@ -121,17 +176,19 @@
return "";
}
/* Display the name of a show */
function displayShowName(schedule) {
let name = ""
if (schedule == null || schedule.show_name == null) {
name = '<span class="error">'+noschedulemessage+'</span>';
name = '<span class="error">'+nonextschedule+'</span>';
} else {
name = schedule.show_name;
}
return name;
}
/* Display the schedule of a show */
function displayShowSchedule(schedule) {
let str = "";
......@@ -146,7 +203,7 @@
hour: '2-digit',
minute:'2-digit'
});
str = "(" + scheduleStart;
str = "" + scheduleStart;
}
if (schedule.schedule_end != null) {
scheduleEnd = new Date(Date.parse(schedule.schedule_end));
......@@ -154,9 +211,9 @@
hour: '2-digit',
minute:'2-digit'
});
str = str + " - " + scheduleEnd + ")";
str = str + " - " + scheduleEnd + "";
} else {
str += ")";
str += "";
}
}
......@@ -166,18 +223,12 @@
/* Check if the given track is currently playing */
function isActive(entry, currentTrack) {
if (currentTrack != null && entry.track_num == currentTrack.track_num) {
// Scroll to current playlist entry
// location.hash = "#current-playlist-entry";
var element = document.querySelector("#current-playlist-entry");
if (element != null)
element.scrollIntoView();
return true;
}
return false;
}
/* Hack to load external CSS into the Web Component */
function loadExternalCss(root, file) {
let element = document.createElement("link");
......@@ -187,15 +238,13 @@
root.appendChild(element);
}
/* Called when the clock finished rendering */
function finalize_rendering() {
/* Sroll to currently playing track */
var element = document.querySelector("#current-playlist-entry");
if (element != null)
element.scrollIntoView();
return ""
/* Scrolls to the track currently playing */
function scrollToActiveTrack() {
if (currentTrackElement != null)
currentTrackElement.scrollIntoView();
}
</script>
<style>
......@@ -210,13 +259,14 @@
margin: 0;
font-size: 3em;
line-height: 80px;
color: #AAA;
}
#station-logo {
align-content: left;
text-align: right;
margin: 0 40px 0 10px;
opacity: 0.5;
opacity: 0.88;
filter: invert(100%);
}
......@@ -240,6 +290,13 @@
padding: 25px 25px 25px 50px;
}
#current-schedule {
border: 2px solid #333;
margin: 20px 20px 40px 20px;
background-color: #111;
height: 100%;
}
#current-schedule,
#next-schedule {
margin: 0 0 40px 20px;
......@@ -252,25 +309,31 @@
}
#current-schedule .schedule-title {
color: #ccc;
font-size: 3.3em;
text-align: center;
height: 100px;
}
#current-schedule .schedule-title h1 {
color: #ccc;
font-size: 2.8em;
position: relative;
top: 30%;
transform: translateY(-50%);
}
#next-schedule .schedule-title {
color: gray !important;
font-size: 2em;
}
#playlist {
border: 2px solid #333;
margin: 20px 20px 40px 20px;
padding: 10px;
height: calc(80% - 100px);
height: calc(100% - 155px);
overflow-y: auto;
scroll-behavior: smooth;
background-color: #111;
padding: 10px;
display: flex;
align-items: center;
border-top: 1px solid #333;;
}
#playlist::-webkit-scrollbar-track
......@@ -295,12 +358,14 @@
#playlist ol {
margin-left: 33px;
height: 95%;
}
.playlist-entry {
font-size: 1.9em;
padding-left: 53px;
padding-bottom: 13px;
color: #AAA;
}
#current-track * {
......@@ -331,7 +396,7 @@
}
.error {
font-size: 1.3em;
font-size: 1.1em;
color:red;
height:100%;
display : flex;
......@@ -384,11 +449,6 @@
text-decoration: underline;
}
footer #aura-logo {
filter: invert(100%);
width: 75px;
margin: 0 0 20px 0;
}
</style>
......@@ -449,28 +509,32 @@
<div id="right-column" class="column">
{#await data}
{#await promise}
<div class="spinner-border mt-5" role="status">
<span class="sr-only">Loading...</span>
</div>
{:then value}
{initComponent(value)}
{#if value.current_schedule}
<div id="current-schedule">
<h1 class="schedule-title">{@html displayShowName(value.current_schedule)} {displayShowSchedule(value.current_schedule)}</h1>
<!-- <div class="schedule-details">
<b>Type:</b> {value.current_schedule}, <b>Host:</b> {value.current_schedule}</div>-->
<div class="schedule-title">
<h1>
{#if hasValidSchedule(value)}
{@html displayShowName(value.current_schedule)} {displayShowSchedule(value.current_schedule)}
{:else}
<span class="error">{nocurrentschedule}</span>
{/if}
</h1>
</div>
<div id="playlist">
{#if value.current_playlist}
{#if hasValidPlaylist(value)}
<ol>
{#each value.current_playlist.entries as entry, index}
{#if isActive(entry, value.current_track)}
<li id="current-playlist-entry" class="playlist-entry is-active">
<li id="current-playlist-entry" class="playlist-entry is-active" bind:this={currentTrackElement}>
<!-- <span class="play-icon">&#9654;</span> -->
<span class="track-title">{displayTitle(entry)}</span>
<span class="track-time-left">({formatTime(timeLeft)})</span>
......@@ -488,7 +552,7 @@
{/each}
</ol>
{:else}
{#if value.current_track}
<div id="current-track" class="is-active">
<h2>
<span class="track-title">{displayTitle(value.track)}</span>
......@@ -496,11 +560,17 @@
</h2>
</div>
{/if}
{/if}
</div>
</div>
{#if value.current_schedule}
<div id="next-schedule">
<h3 class="schedule-title">{@html displayShowName(value.next_schedule)} {displayShowSchedule(value)}</h3>
</div>
{/if}
{:catch error}
<div class="error"><p>{error}</p></div>
......@@ -508,7 +578,6 @@
<footer>
<!-- {finalize_rendering()} -->
<a href="https://gitlab.servus.at/aura/engine-clock">Engine Clock</a> is fuelled by <a href="https://gitlab.servus.at/aura/engine">AURA Engine</a>
</footer>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment