Adds screen audio/narration voices to the screens (Can be turned off in settings)
Some checks are pending
build-docker / Build Image (push) Waiting to run
Some checks are pending
build-docker / Build Image (push) Waiting to run
This commit is contained in:
parent
e4a14fdedd
commit
0afd3f14a0
10 changed files with 131 additions and 0 deletions
BIN
server/alert/current-conditions.mp3
Normal file
BIN
server/alert/current-conditions.mp3
Normal file
Binary file not shown.
BIN
server/alert/hourly-forecast.mp3
Normal file
BIN
server/alert/hourly-forecast.mp3
Normal file
Binary file not shown.
BIN
server/alert/hourly-graph.mp3
Normal file
BIN
server/alert/hourly-graph.mp3
Normal file
Binary file not shown.
BIN
server/alert/local-radar.mp3
Normal file
BIN
server/alert/local-radar.mp3
Normal file
Binary file not shown.
BIN
server/alert/regional-observations.mp3
Normal file
BIN
server/alert/regional-observations.mp3
Normal file
Binary file not shown.
BIN
server/alert/travel-forecast.mp3
Normal file
BIN
server/alert/travel-forecast.mp3
Normal file
Binary file not shown.
|
|
@ -59,6 +59,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
if (mediaVolume.value !== clampMediaVolume(mediaVolume.value)) {
|
||||
mediaVolume.value = clampMediaVolume(mediaVolume.value);
|
||||
}
|
||||
|
||||
// Screen audio setting is managed via localStorage and checked directly in playScreenAudio()
|
||||
});
|
||||
|
||||
const unlockAudio = () => {
|
||||
|
|
@ -342,6 +344,7 @@ const startAlertTone = async () => {
|
|||
alertTonePending = true;
|
||||
return;
|
||||
}
|
||||
stopScreenAudio(); // Stop screen audio when alert plays
|
||||
initializeAlertTonePlayer();
|
||||
try {
|
||||
alertTonePending = true;
|
||||
|
|
@ -370,6 +373,82 @@ const stopAlertTone = () => {
|
|||
|
||||
const playAlertTone = () => startAlertTone();
|
||||
|
||||
// Screen audio constants and variables
|
||||
const SCREEN_AUDIO_DUCK_VOLUME = 0.10; // 10% ducking (vs 5% for alerts)
|
||||
const screenAudioMap = {
|
||||
'radar': 'local-radar.mp3',
|
||||
'regional-forecast': 'regional-observations.mp3',
|
||||
'travel': 'travel-forecast.mp3',
|
||||
'hourly-graph': 'hourly-graph.mp3',
|
||||
'hourly': 'hourly-forecast.mp3',
|
||||
'current-weather': 'current-conditions.mp3',
|
||||
};
|
||||
|
||||
let screenAudioPlayer = null;
|
||||
|
||||
// Helper function to check if screen audio is enabled (always reads from localStorage)
|
||||
const isScreenAudioEnabled = () => {
|
||||
const saved = window.localStorage.getItem('screenAudioEnabled');
|
||||
return saved !== null ? saved === 'true' : true; // Default: enabled
|
||||
};
|
||||
|
||||
// Play screen audio
|
||||
const playScreenAudio = async (screenId) => {
|
||||
// Always check localStorage to ensure setting is current
|
||||
if (!isScreenAudioEnabled()) return;
|
||||
|
||||
const fileName = screenAudioMap[screenId];
|
||||
if (!fileName) return;
|
||||
|
||||
// Stop any existing screen audio first
|
||||
stopScreenAudio();
|
||||
|
||||
// Don't play if alert tone is active
|
||||
if (alertToneActive || alertTonePending) return;
|
||||
|
||||
// Duck background music to 10%
|
||||
if (player && !player.paused) {
|
||||
player.volume = SCREEN_AUDIO_DUCK_VOLUME;
|
||||
}
|
||||
|
||||
// Create and play audio
|
||||
screenAudioPlayer = new Audio(withBasePath(`alert/${fileName}`));
|
||||
screenAudioPlayer.type = 'audio/mpeg';
|
||||
|
||||
screenAudioPlayer.addEventListener('ended', () => {
|
||||
screenAudioPlayer = null;
|
||||
// Only restore if alert isn't playing
|
||||
if (!alertToneActive && !alertTonePending) {
|
||||
restoreMediaAfterAlert();
|
||||
}
|
||||
});
|
||||
|
||||
screenAudioPlayer.addEventListener('error', () => {
|
||||
screenAudioPlayer = null;
|
||||
if (!alertToneActive && !alertTonePending) {
|
||||
restoreMediaAfterAlert();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await screenAudioPlayer.play();
|
||||
} catch (e) {
|
||||
screenAudioPlayer = null;
|
||||
if (!alertToneActive && !alertTonePending) {
|
||||
restoreMediaAfterAlert();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Stop screen audio immediately
|
||||
const stopScreenAudio = () => {
|
||||
if (screenAudioPlayer) {
|
||||
screenAudioPlayer.pause();
|
||||
screenAudioPlayer.currentTime = 0;
|
||||
screenAudioPlayer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const playerCanPlay = async () => {
|
||||
// check to make sure they user still wants music (protect against slow loading music)
|
||||
if (!mediaPlaying.value) return;
|
||||
|
|
@ -402,4 +481,6 @@ export {
|
|||
handleClick,
|
||||
playAlertTone,
|
||||
stopAlertTone,
|
||||
playScreenAudio,
|
||||
stopScreenAudio,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -385,10 +385,18 @@ const handleNavButton = (button) => {
|
|||
break;
|
||||
case 'next':
|
||||
setPlaying(false);
|
||||
// Stop screen audio immediately when navigating
|
||||
import('./media.mjs').then((media) => {
|
||||
media.stopScreenAudio();
|
||||
});
|
||||
navTo(msg.command.nextFrame);
|
||||
break;
|
||||
case 'previous':
|
||||
setPlaying(false);
|
||||
// Stop screen audio immediately when navigating
|
||||
import('./media.mjs').then((media) => {
|
||||
media.stopScreenAudio();
|
||||
});
|
||||
navTo(msg.command.previousFrame);
|
||||
break;
|
||||
case 'menu':
|
||||
|
|
|
|||
|
|
@ -231,6 +231,32 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
settingsSection.innerHTML = '';
|
||||
settingsSection.append(...settingHtml);
|
||||
|
||||
// Add screen audio toggle checkbox
|
||||
const screenAudioContainer = document.createElement('div');
|
||||
screenAudioContainer.className = 'info';
|
||||
const screenAudioLabel = document.createElement('label');
|
||||
screenAudioLabel.htmlFor = 'screen-audio-checkbox';
|
||||
const screenAudioCheckbox = document.createElement('input');
|
||||
screenAudioCheckbox.type = 'checkbox';
|
||||
screenAudioCheckbox.id = 'screen-audio-checkbox';
|
||||
// Load saved preference or default to enabled
|
||||
const savedScreenAudio = window.localStorage.getItem('screenAudioEnabled');
|
||||
screenAudioCheckbox.checked = savedScreenAudio !== null ? savedScreenAudio === 'true' : true;
|
||||
screenAudioCheckbox.addEventListener('change', () => {
|
||||
window.localStorage.setItem('screenAudioEnabled', screenAudioCheckbox.checked);
|
||||
// Import media module and update setting
|
||||
import('./media.mjs').then((media) => {
|
||||
// Media module will read the localStorage value
|
||||
if (!screenAudioCheckbox.checked) {
|
||||
media.stopScreenAudio();
|
||||
}
|
||||
});
|
||||
});
|
||||
screenAudioLabel.appendChild(screenAudioCheckbox);
|
||||
screenAudioLabel.appendChild(document.createTextNode(' Play screen audio'));
|
||||
screenAudioContainer.appendChild(screenAudioLabel);
|
||||
settingsSection.appendChild(screenAudioContainer);
|
||||
|
||||
// update visibility on some settings
|
||||
const modeSelect = document.getElementById('settings-scanLineMode-label');
|
||||
const { value } = settings.scanLines;
|
||||
|
|
|
|||
|
|
@ -219,8 +219,19 @@ class WeatherDisplay {
|
|||
|
||||
this.startNavCount();
|
||||
|
||||
// Check if display was already active before showing
|
||||
const wasActive = this.active;
|
||||
|
||||
this.elem.classList.add('show');
|
||||
document.querySelector('#divTwc').classList.add(this.elemId);
|
||||
|
||||
// Play screen-specific audio only if display was not already active
|
||||
// This prevents audio restart on frame changes (e.g., Local Radar animation)
|
||||
if (!wasActive) {
|
||||
import('./media.mjs').then((media) => {
|
||||
media.playScreenAudio(this.elemId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
hideCanvas() {
|
||||
|
|
@ -228,6 +239,11 @@ class WeatherDisplay {
|
|||
this.elem.classList.remove('show');
|
||||
// used to change backgrounds for widescreen
|
||||
document.querySelector('#divTwc').classList.remove(this.elemId);
|
||||
|
||||
// Stop screen audio when leaving
|
||||
import('./media.mjs').then((media) => {
|
||||
media.stopScreenAudio();
|
||||
});
|
||||
}
|
||||
|
||||
get active() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue