mirror of
https://github.com/netbymatt/ws4kp.git
synced 2026-04-14 07:39:29 -07:00
Merge branch 'main' into background-reload
This commit is contained in:
|
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 251 B |
|
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 455 B |
BIN
server/images/social/1200x600.png
Normal file
BIN
server/images/social/1200x600.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 243 KiB |
BIN
server/music/default/Catch the Sun.mp3
Normal file
BIN
server/music/default/Catch the Sun.mp3
Normal file
Binary file not shown.
BIN
server/music/default/Crisp day.mp3
Normal file
BIN
server/music/default/Crisp day.mp3
Normal file
Binary file not shown.
BIN
server/music/default/Rolling Clouds.mp3
Normal file
BIN
server/music/default/Rolling Clouds.mp3
Normal file
Binary file not shown.
BIN
server/music/default/Strong Breeze.mp3
Normal file
BIN
server/music/default/Strong Breeze.mp3
Normal file
Binary file not shown.
3
server/music/readme.txt
Normal file
3
server/music/readme.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
.mp3 files placed in this folder will be available via the un-mute button in the application.
|
||||
No subdirectories will be scanned, and music will be played in a random order.
|
||||
The default folder will be used only if no .mp3 files are found in this /server/music folder
|
||||
163
server/scripts/modules/media.mjs
Normal file
163
server/scripts/modules/media.mjs
Normal file
@@ -0,0 +1,163 @@
|
||||
import { json } from './utils/fetch.mjs';
|
||||
import Setting from './utils/setting.mjs';
|
||||
|
||||
let playlist;
|
||||
let currentTrack = 0;
|
||||
let player;
|
||||
|
||||
const mediaPlaying = new Setting('mediaPlaying', 'Media Playing', 'boolean', false, null, true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// add the event handler to the page
|
||||
document.getElementById('ToggleMedia').addEventListener('click', toggleMedia);
|
||||
// get the playlist
|
||||
getMedia();
|
||||
});
|
||||
|
||||
const getMedia = async () => {
|
||||
try {
|
||||
// fetch the playlist
|
||||
const rawPlaylist = await json('playlist.json');
|
||||
// store the playlist
|
||||
playlist = rawPlaylist;
|
||||
// enable the media player
|
||||
enableMediaPlayer();
|
||||
} catch (e) {
|
||||
console.error("Couldn't get playlist");
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const enableMediaPlayer = () => {
|
||||
// see if files are available
|
||||
if (playlist?.availableFiles?.length > 0) {
|
||||
// randomize the list
|
||||
randomizePlaylist();
|
||||
// enable the icon
|
||||
const icon = document.getElementById('ToggleMedia');
|
||||
icon.classList.add('available');
|
||||
// set the button type
|
||||
setIcon();
|
||||
// if we're already playing (sticky option) then try to start playing
|
||||
if (mediaPlaying.value === true) {
|
||||
startMedia();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setIcon = () => {
|
||||
// get the icon
|
||||
const icon = document.getElementById('ToggleMedia');
|
||||
if (mediaPlaying.value === true) {
|
||||
icon.classList.add('playing');
|
||||
} else {
|
||||
icon.classList.remove('playing');
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMedia = (forcedState) => {
|
||||
// handle forcing
|
||||
if (typeof forcedState === 'boolean') {
|
||||
mediaPlaying.value = forcedState;
|
||||
} else {
|
||||
// toggle the state
|
||||
mediaPlaying.value = !mediaPlaying.value;
|
||||
}
|
||||
// handle the state change
|
||||
stateChanged();
|
||||
};
|
||||
|
||||
const startMedia = async () => {
|
||||
// if there's not media player yet, enable it
|
||||
if (!player) {
|
||||
initializePlayer();
|
||||
} else {
|
||||
try {
|
||||
await player.play();
|
||||
} catch (e) {
|
||||
// report the error
|
||||
console.error('Couldn\'t play music');
|
||||
console.error(e);
|
||||
// set state back to not playing for good UI experience
|
||||
mediaPlaying.value = false;
|
||||
stateChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const stopMedia = () => {
|
||||
if (!player) return;
|
||||
player.pause();
|
||||
};
|
||||
|
||||
const stateChanged = () => {
|
||||
// update the icon
|
||||
setIcon();
|
||||
// react to the new state
|
||||
if (mediaPlaying.value) {
|
||||
startMedia();
|
||||
} else {
|
||||
stopMedia();
|
||||
}
|
||||
};
|
||||
|
||||
const randomizePlaylist = () => {
|
||||
let availableFiles = [...playlist.availableFiles];
|
||||
const randomPlaylist = [];
|
||||
while (availableFiles.length > 0) {
|
||||
// get a randon item from the available files
|
||||
const i = Math.floor(Math.random() * availableFiles.length);
|
||||
// add it to the final list
|
||||
randomPlaylist.push(availableFiles[i]);
|
||||
// remove the file from the available files
|
||||
availableFiles = availableFiles.filter((file, index) => index !== i);
|
||||
}
|
||||
playlist.availableFiles = randomPlaylist;
|
||||
};
|
||||
|
||||
const initializePlayer = () => {
|
||||
// basic sanity checks
|
||||
if (!playlist.availableFiles || playlist?.availableFiles.length === 0) {
|
||||
throw new Error('No playlist available');
|
||||
}
|
||||
if (player) {
|
||||
return;
|
||||
}
|
||||
// create the player
|
||||
player = new Audio();
|
||||
|
||||
// reset the playlist index
|
||||
currentTrack = 0;
|
||||
|
||||
// add event handlers
|
||||
player.addEventListener('canplay', playerCanPlay);
|
||||
player.addEventListener('ended', playerEnded);
|
||||
|
||||
// get the first file
|
||||
player.src = `music/${playlist.availableFiles[currentTrack]}`;
|
||||
player.type = 'audio/mpeg';
|
||||
};
|
||||
|
||||
const playerCanPlay = async () => {
|
||||
// check to make sure they user still wants music (protect against slow loading music)
|
||||
if (!mediaPlaying.value) return;
|
||||
// start playing
|
||||
startMedia();
|
||||
};
|
||||
|
||||
const playerEnded = () => {
|
||||
// next track
|
||||
currentTrack += 1;
|
||||
// roll over and re-randomize the tracks
|
||||
if (currentTrack >= playlist.availableFiles) {
|
||||
randomizePlaylist();
|
||||
currentTrack = 0;
|
||||
}
|
||||
// update the player source
|
||||
player.src = `music/${playlist.availableFiles[currentTrack]}`;
|
||||
};
|
||||
|
||||
export {
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
toggleMedia,
|
||||
};
|
||||
@@ -10,7 +10,7 @@ const settings = { speed: { value: 1.0 } };
|
||||
const init = () => {
|
||||
// create settings
|
||||
settings.wide = new Setting('wide', 'Widescreen', 'checkbox', false, wideScreenChange, true);
|
||||
settings.kiosk = new Setting('kiosk', 'Kiosk', 'boolean', false, kioskChange, false);
|
||||
settings.kiosk = new Setting('kiosk', 'Kiosk', 'checkbox', false, kioskChange, false);
|
||||
settings.speed = new Setting('speed', 'Speed', 'select', 1.0, null, true, [
|
||||
[0.5, 'Very Fast'],
|
||||
[0.75, 'Fast'],
|
||||
|
||||
@@ -167,6 +167,8 @@ class Setting {
|
||||
case 'select':
|
||||
this.selectHighlight(newValue);
|
||||
break;
|
||||
case 'boolean':
|
||||
break;
|
||||
case 'checkbox':
|
||||
default:
|
||||
this.element.checked = newValue;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
34
server/styles/scss/_media.scss
Normal file
34
server/styles/scss/_media.scss
Normal file
@@ -0,0 +1,34 @@
|
||||
.media {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#ToggleMedia {
|
||||
display: none;
|
||||
|
||||
&.available {
|
||||
display: inline-block;
|
||||
|
||||
img.on {
|
||||
display: none;
|
||||
}
|
||||
|
||||
img.off {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// icon switch is handled by adding/removing the .playing class
|
||||
&.playing {
|
||||
img.on {
|
||||
display: block;
|
||||
}
|
||||
|
||||
img.off {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,4 +11,5 @@
|
||||
@import 'radar';
|
||||
@import 'regional-forecast';
|
||||
@import 'almanac';
|
||||
@import 'hazards';
|
||||
@import 'hazards';
|
||||
@import 'media';
|
||||
Reference in New Issue
Block a user