There\'s nothing up next yet.
' +
'',
)
@@ -132,14 +132,14 @@ function success(data) {
' title="Show on air next: ' +
data.payload.next.title +
'.">' +
- '
' +
makeContent(data.payload.next) +
'',
)
} else {
$('.current-and-next-next').replaceWith(
'
' +
- '
Next ' +
+ '
Up next ' +
makeContent(data.payload.next) +
'',
)
diff --git a/public/js/live-player.js b/public/js/live-player.js
new file mode 100644
index 00000000..381daa0f
--- /dev/null
+++ b/public/js/live-player.js
@@ -0,0 +1,160 @@
+export function makePlayer(config) {
+ const { idPrefix, audioUrl, icecastStatusUrl } = config;
+ let player = new Audio();
+ player.preload = 'none';
+ const playPause = document.getElementById(`${idPrefix}-play`);
+ const volume = document.getElementById(`${idPrefix}-volume`);
+ const currentTrackTitle = document.getElementById(`${idPrefix}-track-title`);
+ const currentTrackArtist = document.getElementById(`${idPrefix}-track-artist`);
+ const currentTrackContainer = document.getElementById(`${idPrefix}-track-container`);
+
+ function updateButton() {
+ if (player.paused) {
+ playPause.innerHTML = '
';
+ } else {
+ playPause.innerHTML = '
';
+ }
+ }
+
+ let playbackError = false;
+
+ function markLoading() {
+ playPause.innerHTML = '
• • • ';
+ }
+
+ function markError() {
+ playbackError = true;
+ playPause.disabled = true;
+ playPause.innerHTML = '
';
+ }
+
+ function setNowPlaying(title, artist) {
+ currentTrackTitle.innerText = title;
+ currentTrackArtist.innerText = artist;
+ if (title === 'URY' && artist === null) {
+ currentTrackContainer.style.display = 'none';
+ } else {
+ currentTrackContainer.style.display = 'block';
+ }
+ }
+
+ let nowPlayingUpdate = null;
+
+ function fetchNowPlaying() {
+ fetch(icecastStatusUrl)
+ .then((resp) => {
+ if (!resp.ok) {
+ console.error('failed to fetch current track', resp.status, resp.statusText);
+ nowPlayingUpdate = setTimeout(fetchNowPlaying, 10_000);
+ return;
+ } else {
+ return resp.json();
+ }
+ })
+ .then((resp) => {
+ const stream = resp.icestats.source.filter((s) => s.listenurl.indexOf('/live-high-ogg') !== -1)[0];
+ const { artist, title } = stream;
+
+ setNowPlaying(title, artist);
+
+ // Update every 10s
+ nowPlayingUpdate = setTimeout(fetchNowPlaying, 10_000);
+ }).catch((e) => {
+ console.error('failed to fetch now playing', e);
+ });
+ }
+
+ const playbackControls = {
+ play() {
+ if (playbackError) {
+ console.log('playback error');
+ return;
+ }
+ if (!nowPlayingUpdate) {
+ fetchNowPlaying();
+ }
+
+ if (!this.playing) {
+ player.src = audioUrl;
+ player.play();
+ }
+ },
+
+ pause() {
+ if (playbackError) {
+ console.error('playback error');
+ return;
+ }
+ if (nowPlayingUpdate) {
+ clearTimeout(nowPlayingUpdate);
+ nowPlayingUpdate = null;
+ }
+
+ player.src = null;
+ player.srcObject = null;
+
+ updateButton();
+ },
+
+ setVolume(level) {
+ player.volume = level;
+ },
+
+ get playing() {
+ return player.src !== null && !player.paused;
+ }
+ };
+
+ player.addEventListener('waiting', () => {
+ if (playbackError) return;
+ markLoading();
+ })
+
+ player.addEventListener('pause', () => {
+ if (playbackError) return;
+ updateButton();
+ });
+
+ player.addEventListener('play', () => {
+ if (playbackError) return;
+ updateButton();
+ });
+
+ player.addEventListener('playing', () => {
+ if (playbackError) return;
+ updateButton();
+ });
+
+ player.addEventListener('ended', () => {
+ if (playbackError) return;
+ console.log('retrying load');
+ player.load();
+ });
+
+ player.addEventListener('error', (ev) => {
+ console.log(ev.error);
+ markError();
+ });
+
+ playPause.addEventListener('click', () => {
+ if (player.paused) {
+ playbackControls.play();
+ } else {
+ playbackControls.pause();
+ }
+ });
+
+ playbackControls.setVolume(parseInt(volume.value) / 11.0);
+ volume.addEventListener('input', () => {
+ playbackControls.setVolume(parseInt(volume.value) / 11.0);
+ });
+
+ window.onbeforeunload = () => {
+ console.log('before unload');
+ if (playbackControls.playing) {
+ return '';
+ }
+ };
+
+ return playbackControls;
+}
diff --git a/sass/elements/_currentAndNext.scss b/sass/elements/_currentAndNext.scss
index 7491c78a..f17353e2 100644
--- a/sass/elements/_currentAndNext.scss
+++ b/sass/elements/_currentAndNext.scss
@@ -1,5 +1,5 @@
.current-next {
- background: url("/images/bg-banner-1.jpg") center center no-repeat;
+ background: url("/images/bg-banner-1.jpg") center no-repeat;
background-size: cover;
color: white;
box-sizing: content-box;
@@ -75,4 +75,19 @@
background: $current-next-next-bg;
}
+ .current-and-next-player {
+ transition: max-height 500ms ease;
+ overflow: hidden;
+ max-height: 256px;
+
+ &.closed {
+ transition: max-height 500ms ease;
+ max-height: 0;
+ @include media-breakpoint-down(sm) {
+ // silly hack since the closed player has a height of 1px,
+ // even though i tell it that it can have a max height of 0
+ background-color: red;
+ }
+ }
+ }
}
diff --git a/sass/elements/_elements.scss b/sass/elements/_elements.scss
index ec6182fa..825fb419 100644
--- a/sass/elements/_elements.scss
+++ b/sass/elements/_elements.scss
@@ -8,4 +8,5 @@
@import "snow";
@import "aprilFools";
@import "show";
-@import "faq";
\ No newline at end of file
+@import "faq";
+@import "livePlayer";
\ No newline at end of file
diff --git a/sass/elements/_livePlayer.scss b/sass/elements/_livePlayer.scss
new file mode 100644
index 00000000..07b95053
--- /dev/null
+++ b/sass/elements/_livePlayer.scss
@@ -0,0 +1,73 @@
+.live-container {
+ gap: 1.5rem;
+}
+
+.live-now-playing p {
+ margin: 0;
+}
+
+@include media-breakpoint-down(md) {
+ .mobile-column {
+ flex-direction: column;
+ align-items: center !important;
+ justify-content: left !important;
+ text-align: center;
+ gap: 1rem;
+ }
+}
+
+.play-pause-button {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ border-radius: 99999px;
+ background-color: $ury-blue-color;
+ color: white;
+ border: none;
+ outline: none;
+ width: 48px;
+ height: 48px;
+ box-shadow: 0 0.25rem 1rem rgba(0,0,0,0.5);
+ transition: transform ease 200ms, box-shadow ease 200ms;
+ &:hover {
+ transform: scale(1.1);
+ box-shadow: 0 0.25rem 1rem rgba(0,0,0,0.75);
+ }
+ &:focus {
+ outline: none;
+ }
+ &:active {
+ transform: scale(0.9);
+ box-shadow: 0 0.25rem 1rem rgba(0,0,0,0.5);
+ }
+
+ .player-load-dots span {
+ animation: pulse 2000ms ease infinite;
+
+ &:nth-child(1) {
+ animation-delay: 0ms;
+ }
+ &:nth-child(2) {
+ animation-delay: 250ms;
+ }
+ &:nth-child(3) {
+ animation-delay: 500ms;
+ }
+ }
+}
+
+@keyframes pulse {
+ from {
+ opacity: 1;
+ }
+ 25% {
+ opacity: 0;
+ }
+ 75% {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
diff --git a/structs/config.go b/structs/config.go
index 8d7a672f..2ad91731 100644
--- a/structs/config.go
+++ b/structs/config.go
@@ -47,6 +47,8 @@ type PageContext struct {
CINLive string `toml:"cinLive"`
IndexCountdown *IndexCountdownConfig `toml:"indexCountdown"`
CacheBuster string `toml:"cacheBuster"`
+ LiveAudioURL string `toml:"liveAudioUrl"`
+ IcecastStatusURL string `toml:"icecastStatusUrl"`
Pages []Page
Youtube youtube
Gmaps gmaps
@@ -92,9 +94,9 @@ type Page struct {
}
type youtube struct {
- APIKey string `toml:"apiKey"`
- CINPlaylistID string `toml:"cinPlaylistID"`
- ChannelURL string `toml:"channelURL"`
+ APIKey string `toml:"apiKey"`
+ CINPlaylistID string `toml:"cinPlaylistID"`
+ ChannelURL string `toml:"channelURL"`
}
type gmaps struct {
diff --git a/views/elements/current_and_next.tmpl b/views/elements/current_and_next.tmpl
index e1ae71e9..dbf1eab9 100644
--- a/views/elements/current_and_next.tmpl
+++ b/views/elements/current_and_next.tmpl
@@ -1,6 +1,6 @@
{{define "current_and_next"}}
-{{with .CurrentAndNext}}
+{{with .PageData.CurrentAndNext}}
{{if .Current}}
@@ -14,9 +14,9 @@
{{end}}
-
{{end}}
+
+ {{template "live_player" .}}
+
+
+
diff --git a/views/elements/live_player.tmpl b/views/elements/live_player.tmpl
new file mode 100644
index 00000000..7382e8d2
--- /dev/null
+++ b/views/elements/live_player.tmpl
@@ -0,0 +1,35 @@
+{{define "live_player"}}
+
+
+
+
+
+
+
+
Listening to {{.PageContext.LongName}}
+
+ Now playing:
+ by
+
+
+
+
+ Volume:
+
+
+
+
+ Pop-up player
+
+
+
+
+
+{{end}}
diff --git a/views/elements/message_box.tmpl b/views/elements/message_box.tmpl
index 9ba3cc2d..cc53934a 100644
--- a/views/elements/message_box.tmpl
+++ b/views/elements/message_box.tmpl
@@ -2,7 +2,7 @@
{{with .}}
Send a Message
-
-
You can also text on 07851 101 313
+
{{end}}
{{end}}
diff --git a/views/index.tmpl b/views/index.tmpl
index 7b663f51..a1825a6d 100644
--- a/views/index.tmpl
+++ b/views/index.tmpl
@@ -15,16 +15,16 @@