Open BusterNeece opened 4 years ago
I've found a way to make a custom player from within my application.
I've modified the embed to be able to
// Add to the embed through Public JS in the branding page of the admin panel
function radioStatus(){
if (document.getElementsByClassName('radio-control-play-button')[0]) {
const playState = document.getElementsByClassName('radio-control-play-button')[0].ariaLabel
const albumArt = document.getElementsByClassName('album_art')[0].src
const title = document.getElementsByClassName('now-playing-title')[0].innerText
const artist = document.getElementsByClassName('now-playing-artist')[0].innerText
const trackProgress = document.getElementsByClassName('progress-bar bg-secondary')[0].style.width
const volumeLevel = document.querySelector('.radio-control-volume-slider .form-range').value
return JSON.stringify(
{ playState: playState,
albumArt: albumArt,
title: title,
artist: artist,
trackProgress: trackProgress,
volumeLevel: volumeLevel})
} else{
return false
}
};
function broadcastRadioInfo() {
parent.postMessage(radioStatus(), "<domain of website/localhost>");
};
const intervalID = setInterval(broadcastRadioInfo, 500);
// this will cause the event to emit every 500ms
From the client I can then read the status of the radio by adding an EventListener
// Your client code
window.addEventListener("message", function(e) {
var message = e.data;
var origin = e.origin;
if (origin === "https://<url-of-radio-station>" && message) {
const radioStatus= JSON.parse(message);
});
I send messages to it from my application with an instruction object where play
is a boolean representing what state you want the player to be in.
document.getElementById("<id of the player iframe>").contentWindow.postMessage(
JSON.stringify({ play: true, volume: 50 }),
"https://<url-of-radio-station>"
);
which are in turn handled from the player by adding an event listener.
// Add to the embed through Public JS in the branding page of the admin panel
const SAFE_ORIGINS = ["https://<your-domain>", "http://<localhost-if-developing>"]
window.addEventListener('message', function(e) {
var message = e.data;
var origin = e.origin;
if (SAFE_ORIGINS.includes(origin)) {
const instructions = JSON.parse(message);
const playState = document.getElementsByClassName('radio-control-play-button')[0].ariaLabel;
if (playState == "Play" && instructions.play) {
document.getElementsByClassName('radio-control-play-button')[0].click();
} else if (playState == "Stop" && !instructions.play) {
document.getElementsByClassName('radio-control-play-button')[0].click();
}
if (instructions.volume) {
// This approach for changing the volume does not work because I believe that it changes the input value,
// but not the state of the Vue component directly.
const volumeSelector = document.querySelector('.radio-control-volume-slider .form-range');
volumeSelector.value = instructions.volume;
}
}
});
Accessing cross domain iFrame contents MDN Docs for postMessage
We've already abstracted out a large amount of our public radio player's code to a Vue component, which makes the idea of having it be a heavily customizable widget even more doable in a fairly short period of time.
Basically, what we're looking for in the initial implementation of a customizable embeddable widget would be: