From 8281be7ba874e116ccc43e41d1275c1d531c54dc Mon Sep 17 00:00:00 2001 From: kaotisk Date: Thu, 10 Oct 2024 07:42:13 +0300 Subject: Implementation --- client/index.html | 37 +++++++++ client/js/radio_emulator.js | 188 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 client/index.html create mode 100644 client/js/radio_emulator.js (limited to 'client') diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..1cfcd5d --- /dev/null +++ b/client/index.html @@ -0,0 +1,37 @@ + + + + + +

Radio station example

+
+

Hit play!

+ +
+ +
+
+
+

Artist

+

+

Title

+

+

You are here for (seconds)

+

+

Started on

+

+

Current time

+

+

Hash of current show

+

+

Hash of list

+

+
+
+ Data +
+ + + diff --git a/client/js/radio_emulator.js b/client/js/radio_emulator.js new file mode 100644 index 0000000..98138e7 --- /dev/null +++ b/client/js/radio_emulator.js @@ -0,0 +1,188 @@ +// Radio Emulator +// Kaotisk Hund 2024 +// +// A simple co-mechanism to pretend playing a live radio as it would happen for +// a radio station that mostly plays prerecoded shows. +// +// Client side implementation +// Let's remind here the structures we are waiting for: +// 1. Hash +// 2. 0 +// 3. audio/ogg file +// 4. application/json file +// +// 1. Hash +// Can be an SHA512sum or SHA256sum, we don't do checks, we only ask the hash +// accompanied by what do we think it is. +// +// 2. 0 +// When nothing exists on the radio station we are visiting. +// +// 3. audio/ogg file +// An audio file to play. +// +// 4. application/json file +// Could be one of the following: +// - list +// - show_info +// + +var audioElement = document.querySelector('audio'); +var sourceElement = document.querySelector('source'); +var currentTimeP = document.querySelector('.current-time'); +var listStartedP = document.querySelector('.started-on'); +var currentShowHash = document.querySelector('.current-show-hash'); +var listHash = document.querySelector('.list-hash'); +var artistP = document.querySelector('.artist'); +var titleP = document.querySelector('.title'); +var radioPlayerDiv = document.querySelector('.radio-player'); +var youAreHere = document.querySelector('.you-are-here'); + +var seconds_here = 0; +function increaseSeconds() +{ + seconds_here = seconds_here+1; + youAreHere.innerText = seconds_here; + return seconds_here; +} +function getSecondsHere() +{ + return seconds_here; +} + +setInterval(increaseSeconds, 1000); + + +function FetchJSON( url, callback, params ) +{ + const request = new XMLHttpRequest(); + request.addEventListener("load", ()=>{ + var json = JSON.parse(request.response); + if(request.status !== 404){ + callback(json, params); + } else { + console.log(`ERROR ${request.status} while loading ${url}`); + } + }); + request.addEventListener("error", ()=>{ + console.log("An error occured. While loading: "+url+" for "+callback+"."); + }); + // ProgressBar update: Interesting but not needed + // request.addEventListener("progress", (event)=>{ + // if (event.lengthComputable && progressPlaceholder){ + // httpProgressPlaceholder.value = (event.loaded / event.total) * 100; + // } else { + // httpProgressPlaceholder.value = 0; + // // console.log("Supposingly zeroed progressPlaceholder"); + // } + // }); + request.addEventListener("abort", ()=>{ + console.log("Request aborted."); + }); + request.open("GET", url); + request.send(); +} + +function genericCallback(json, params) +{ + console.log('genericCallback'); + console.log(json); + console.log(params); +} + +var calledLoadShowCallback = 0; + +function stopHereAndReflect() +{ + +} + +function loadShowCallback(json, params) +{ + const [ list, now_on_sequence, element, hash_of_list ] = params; +// if ( calledLoadShowCallback === 0 ) +// { +// calledLoadShowCallback++; + console.log('loadShowCallback'); + console.log(json); + console.log(element); + console.log(params); + listStartedP.innerText = list.started_on; + listHash.innerText = hash_of_list; + currentShowHash.innerText = json.hash; + artistP.innerText = json.artist; + titleP.innerText = json.title; + // audioElement.pause(); + sourceElement.src = "http://z.kaotisk-hund.com:8010/v0/audio/ogg/" + json.hash + "#t=" + Math.floor((now_on_sequence - element.starts_on)/1000); + sourceElement.type = json.mimetype; + audioElement.load(); + console.log('plays here: '+(now_on_sequence - element.starts_on)/1000); + audioElement.addEventListener('canplaythrough', function(){ + console.log('CAN PLAY THROUGH'); + if ( calledLoadShowCallback < 100 ) + { + calledLoadShowCallback++; + currentTimeP.innerText = ((now_on_sequence - element.starts_on)/1000); + audioElement.currentTime = ((now_on_sequence - element.starts_on)/1000); + audioElement.play(); + } + }); + audioElement.addEventListener('ended', function(){ + location.reload(); + //FetchJSON('http://z.kaotisk-hund.com:8010/v0/list', hashCallback, [ new Date().getTime()]); + }); + sync_radio(); + setTimeout(sync_radio, 30000); + +// } else { +// return 0; +// } +} + +function sync_radio() +{ + var value = currentTimeP.innerText; + var new_now = parseFloat(value) + getSecondsHere(); + console.log("Trying to sync @ "+ value + " + " +getSecondsHere() + " = " + new_now); + if ( value !== "" ) + { + audioElement.currentTime = new_now; + } +} + +function listCallback(json, params) +{ + console.log('listCallback'); + var [ now, hash_of_list ] = params; + // var now = Date.now(); + var delta_time = now - json.started_on; + var min_times_played = Math.floor( delta_time / json.duration ); + var max_times_to_be_played = delta_time / json.duration; + var Dt = max_times_to_be_played - min_times_played; + var now_on_sequence = Dt * json.duration; + console.log(`now_on_sequence: ${now_on_sequence}, Dt: ${Dt}`) + + previous = { starts_on: 0 }; + json.list.forEach((element)=>{ + if ( now_on_sequence < element.starts_on && now_on_sequence > previous.starts_on){ + } else { + now_on_sequence = now_on_sequence - previous.starts_on; + console.log(now_on_sequence); + previous = element; + console.log(element); + FetchJSON("http://z.kaotisk-hund.com:8010/v0/application/json/" + element.hash, loadShowCallback, [json, now_on_sequence, element, hash_of_list]); + } + }); +} + +function hashCallback(json, params) +{ + var [ now ] = params; + console.log('hashCallback'); + FetchJSON('http://z.kaotisk-hund.com:8010/v0/application/json/' + json.latest_list, listCallback, [now, json.latest_list]); +} + +FetchJSON('http://z.kaotisk-hund.com:8010/v0/list', hashCallback, [ new Date().getTime() ]); + + + -- cgit v1.2.3