mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
Feature/music skip delay (#115)
* feat: Add configurable delay for music module skip when nothing playing - Add 'skip_when_nothing_playing' and 'skip_delay_seconds' config options - Implement timer-based skip logic that waits 2 seconds before skipping - Reset timer when music resumes or display is deactivated - Improve user experience by preventing jarring immediate skips - Maintains backward compatibility with existing configurations * feat: Add live priority support to music manager - Add 'live_priority' and 'live_game_duration' config options for music - Integrate music manager into live priority rotation system - Add 'music_live' mode that participates in live priority takeover - Music manager joins live priority rotation when actively playing - Supports future plugin ecosystem with consistent live priority interface - Maintains backward compatibility with existing music configurations * feat: Add new music settings to web interface - Add 'Skip When Nothing Playing' checkbox and delay configuration - Add 'Enable Live Priority' checkbox and duration configuration - Update music form JavaScript to save all new settings - Users can now configure music skip behavior and live priority through web UI * fix: Improve music live priority integration - Enhanced music live content detection with detailed logging - Modified live priority logic to properly handle music mode - Added music to live priority sports collection when actively playing - Updated live priority rotation to handle music mode correctly - Improved live priority takeover logic for music manager - Music now properly participates in live priority rotation when playing * perf: Reduce logging frequency for music live priority - Add timestamp-based throttling to music live priority logging - Info messages now only appear every 30 seconds instead of every few milliseconds - Debug messages are also throttled to reduce log spam - Maintains visibility of important events while reducing noise * Fix unreachable code bug in music live priority handling - Moved music live priority logic outside the sports iteration loop where it was unreachable - The 'if sport == music' block was never executed since 'music' wasn't in the sports list - Consolidated music handling in its own separate section for cleaner code structure - Added music configuration options to config template - Maintained exact same functionality while eliminating dead code * Fix music_live_game_duration setting not being used - Modified get_current_duration() method to check for music live priority mode - When music is in live priority mode, use configured live_game_duration setting - Added proper config reading for music_live_game_duration during initialization - Ensures music displays for the configured duration when in live priority mode * Fix stale timestamp bug in live priority debug logging - Fixed issue where debug log at line 1240 was using a stale current_time variable - The current_time variable was conditionally reassigned in music live priority check - This caused inconsistent log throttling behavior - Now uses fresh current_time_for_debug variable for accurate throttling
This commit is contained in:
@@ -577,7 +577,11 @@
|
||||
"enabled": false,
|
||||
"preferred_source": "ytm",
|
||||
"YTM_COMPANION_URL": "http://192.168.86.12:9863",
|
||||
"POLLING_INTERVAL_SECONDS": 1
|
||||
"POLLING_INTERVAL_SECONDS": 1,
|
||||
"skip_when_nothing_playing": true,
|
||||
"skip_delay_seconds": 2,
|
||||
"live_priority": true,
|
||||
"live_game_duration": 30
|
||||
},
|
||||
"of_the_day": {
|
||||
"enabled": false,
|
||||
|
||||
@@ -38,7 +38,7 @@ from src.youtube_display import YouTubeDisplay
|
||||
from src.calendar_manager import CalendarManager
|
||||
from src.text_display import TextDisplay
|
||||
from src.static_image_manager import StaticImageManager
|
||||
from src.music_manager import MusicManager
|
||||
from src.music_manager import MusicManager, SkipModuleException
|
||||
from src.of_the_day_manager import OfTheDayManager
|
||||
from src.news_manager import NewsManager
|
||||
|
||||
@@ -103,8 +103,11 @@ class DisplayController:
|
||||
self.music_manager = None
|
||||
else:
|
||||
logger.info("Music module is disabled in main configuration (config.json).")
|
||||
# Read music live game duration setting regardless of whether music is enabled
|
||||
self.music_live_game_duration = music_config_main.get('live_game_duration', 30)
|
||||
else:
|
||||
logger.error("Config not loaded before MusicManager initialization attempt.")
|
||||
self.music_live_game_duration = 30 # Default fallback
|
||||
logger.info("MusicManager initialized in %.3f seconds", time.time() - music_init_time)
|
||||
|
||||
# Initialize NHL managers if enabled
|
||||
@@ -324,6 +327,12 @@ class DisplayController:
|
||||
self.ncaaw_basketball_live_priority = self.config.get('ncaaw_basketball_scoreboard', {}).get('live_priority', True)
|
||||
self.ncaam_hockey_live_priority = self.config.get('ncaam_hockey_scoreboard', {}).get('live_priority', True)
|
||||
self.ncaaw_hockey_live_priority = self.config.get('ncaaw_hockey_scoreboard', {}).get('live_priority', True)
|
||||
self.music_live_priority = self.config.get('music', {}).get('live_priority', True)
|
||||
|
||||
# Live priority logging throttling
|
||||
self._last_music_live_priority_log = 0
|
||||
self._last_music_rotation_log = 0
|
||||
self._music_live_priority_log_interval = 30.0 # Log every 30 seconds
|
||||
|
||||
# List of available display modes (adjust order as desired)
|
||||
self.available_modes = []
|
||||
@@ -493,6 +502,7 @@ class DisplayController:
|
||||
'ncaa_fb_recent': 15,
|
||||
'ncaa_fb_upcoming': 15,
|
||||
'music': 20, # Default duration for music, will be overridden by config if present
|
||||
'music_live': 30, # Default duration for music live mode
|
||||
'ncaa_baseball_live': 30, # Added NCAA Baseball durations
|
||||
'ncaa_baseball_recent': 15,
|
||||
'ncaa_baseball_upcoming': 15,
|
||||
@@ -644,6 +654,16 @@ class DisplayController:
|
||||
# Fall back to configured duration
|
||||
return self.display_durations.get(mode_key, 600)
|
||||
|
||||
# Handle music live priority mode
|
||||
elif mode_key == 'music' and self.music_live_priority and self.music_manager and self._music_has_live_content():
|
||||
# Use the configured live game duration for music when in live priority mode
|
||||
music_live_duration = getattr(self, 'music_live_game_duration', 30)
|
||||
# Only log if duration has changed or we haven't logged this duration yet
|
||||
if not hasattr(self, '_last_logged_music_live_duration') or self._last_logged_music_live_duration != music_live_duration:
|
||||
logger.info(f"Using music live priority duration: {music_live_duration} seconds")
|
||||
self._last_logged_music_live_duration = music_live_duration
|
||||
return music_live_duration
|
||||
|
||||
# Simplify weather key handling
|
||||
elif mode_key.startswith('weather_'):
|
||||
return self.display_durations.get(mode_key, 15)
|
||||
@@ -1034,12 +1054,34 @@ class DisplayController:
|
||||
return
|
||||
|
||||
if not live_priority:
|
||||
# Only add to rotation if manager exists and has live games
|
||||
if manager and getattr(manager, 'live_games', None):
|
||||
live_games = getattr(manager, 'live_games', None)
|
||||
if mode_name not in self.available_modes:
|
||||
self.available_modes.append(mode_name)
|
||||
logger.debug(f"Added {mode_name} to rotation (found {len(live_games)} live games)")
|
||||
# Only add to rotation if manager exists and has live games/content
|
||||
if manager:
|
||||
# Special handling for music manager - check if music is actively playing
|
||||
if mode_name == 'music_live':
|
||||
has_live_content = self._music_has_live_content()
|
||||
logger.debug(f"Music live mode update: mode_name={mode_name}, has_live_content={has_live_content}, in_available_modes={mode_name in self.available_modes}")
|
||||
if has_live_content and mode_name not in self.available_modes:
|
||||
self.available_modes.append(mode_name)
|
||||
# Throttle logging - only log every 30 seconds
|
||||
current_time = time.time()
|
||||
if current_time - self._last_music_rotation_log >= self._music_live_priority_log_interval:
|
||||
logger.info(f"Added {mode_name} to rotation (music is playing)")
|
||||
self._last_music_rotation_log = current_time
|
||||
elif not has_live_content and mode_name in self.available_modes:
|
||||
self.available_modes.remove(mode_name)
|
||||
# Throttle logging - only log every 30 seconds
|
||||
current_time = time.time()
|
||||
if current_time - self._last_music_rotation_log >= self._music_live_priority_log_interval:
|
||||
logger.info(f"Removed {mode_name} from rotation (music stopped)")
|
||||
self._last_music_rotation_log = current_time
|
||||
elif getattr(manager, 'live_games', None):
|
||||
live_games = getattr(manager, 'live_games', None)
|
||||
if mode_name not in self.available_modes:
|
||||
self.available_modes.append(mode_name)
|
||||
logger.debug(f"Added {mode_name} to rotation (found {len(live_games)} live games)")
|
||||
else:
|
||||
if mode_name in self.available_modes:
|
||||
self.available_modes.remove(mode_name)
|
||||
else:
|
||||
if mode_name in self.available_modes:
|
||||
self.available_modes.remove(mode_name)
|
||||
@@ -1077,6 +1119,32 @@ class DisplayController:
|
||||
update_mode('ncaaw_basketball_live', getattr(self, 'ncaaw_basketball_live', None), self.ncaaw_basketball_live_priority, ncaaw_basketball_enabled)
|
||||
update_mode('ncaam_hockey_live', getattr(self, 'ncaam_hockey_live', None), self.ncaam_hockey_live_priority, ncaam_hockey_enabled)
|
||||
update_mode('ncaaw_hockey_live', getattr(self, 'ncaaw_hockey_live', None), self.ncaaw_hockey_live_priority, ncaaw_hockey_enabled)
|
||||
# Add music to live priority rotation if enabled and music is playing
|
||||
music_enabled = self.config.get('music', {}).get('enabled', False)
|
||||
# Throttle debug logging - only log every 30 seconds
|
||||
current_time = time.time()
|
||||
if current_time - self._last_music_rotation_log >= self._music_live_priority_log_interval:
|
||||
logger.debug(f"Music enabled: {music_enabled}, live_priority: {self.music_live_priority}, manager: {self.music_manager is not None}")
|
||||
update_mode('music_live', self.music_manager, self.music_live_priority, music_enabled)
|
||||
|
||||
def _music_has_live_content(self) -> bool:
|
||||
"""Check if music manager has live content (actively playing music)."""
|
||||
if not self.music_manager:
|
||||
logger.debug("Music manager not initialized")
|
||||
return False
|
||||
|
||||
# Get current track info from music manager
|
||||
current_track_info = self.music_manager.get_current_display_info()
|
||||
if not current_track_info:
|
||||
logger.debug("No current track info from music manager")
|
||||
return False
|
||||
|
||||
# Check if music is currently playing
|
||||
is_playing = current_track_info.get('is_playing', False)
|
||||
title = current_track_info.get('title', '')
|
||||
has_live_content = is_playing and title != 'Nothing Playing'
|
||||
|
||||
return has_live_content
|
||||
|
||||
def run(self):
|
||||
"""Run the display controller, switching between displays."""
|
||||
@@ -1114,6 +1182,15 @@ class DisplayController:
|
||||
has_live_games, live_sport_type = self._check_live_games()
|
||||
is_currently_live = self.current_display_mode.endswith('_live')
|
||||
|
||||
# Special case: if we're in music mode and music is actively playing, treat it as live
|
||||
if self.current_display_mode == 'music' and self._music_has_live_content():
|
||||
is_currently_live = True
|
||||
# Throttle logging - only log every 30 seconds
|
||||
current_time = time.time()
|
||||
if current_time - self._last_music_rotation_log >= self._music_live_priority_log_interval:
|
||||
logger.debug("Music mode with active content treated as live priority")
|
||||
self._last_music_rotation_log = current_time
|
||||
|
||||
# Collect all sports with live_priority=True that have live games
|
||||
live_priority_sports = []
|
||||
for sport, attr, priority in [
|
||||
@@ -1132,7 +1209,8 @@ class DisplayController:
|
||||
('ncaaw_hockey', 'ncaaw_hockey_live', self.ncaaw_hockey_live_priority)
|
||||
]:
|
||||
manager = getattr(self, attr, None)
|
||||
# Only consider sports that are enabled (manager is not None) and have actual live games
|
||||
|
||||
# Standard sports logic
|
||||
live_games = getattr(manager, 'live_games', None) if manager is not None else None
|
||||
# Check that manager exists, has live_priority enabled, has live_games attribute, and has at least one live game
|
||||
if (manager is not None and
|
||||
@@ -1144,27 +1222,43 @@ class DisplayController:
|
||||
elif manager is not None and priority and live_games is not None:
|
||||
logger.debug(f"{sport} has live_priority=True but {len(live_games)} live games (not taking over)")
|
||||
|
||||
# Special handling for music - check if music is actively playing
|
||||
if (self.music_manager is not None and
|
||||
self.music_live_priority and
|
||||
self._music_has_live_content()):
|
||||
live_priority_sports.append('music')
|
||||
# Throttle logging - only log every 30 seconds
|
||||
current_time = time.time()
|
||||
if current_time - self._last_music_live_priority_log >= self._music_live_priority_log_interval:
|
||||
logger.info("Live priority music found: music is playing - added to live priority rotation")
|
||||
self._last_music_live_priority_log = current_time
|
||||
|
||||
# Determine if we have any live priority sports
|
||||
live_priority_takeover = len(live_priority_sports) > 0
|
||||
# Throttle debug logging - only log every 30 seconds
|
||||
current_time_for_debug = time.time()
|
||||
if current_time_for_debug - self._last_music_rotation_log >= self._music_live_priority_log_interval:
|
||||
logger.debug(f"Live priority sports: {live_priority_sports}, takeover: {live_priority_takeover}")
|
||||
|
||||
manager_to_display = None
|
||||
# --- State Machine for Display Logic ---
|
||||
if is_currently_live:
|
||||
if live_priority_takeover:
|
||||
# Check if we need to rotate to the next live priority sport
|
||||
current_sport_type = self.current_display_mode.replace('_live', '')
|
||||
current_sport_type = self.current_display_mode.replace('_live', '') if self.current_display_mode.endswith('_live') else self.current_display_mode
|
||||
|
||||
# If current sport is not in live priority sports, switch to first one
|
||||
if current_sport_type not in live_priority_sports:
|
||||
next_sport = live_priority_sports[0]
|
||||
new_mode = f"{next_sport}_live"
|
||||
# Special case for music - use "music" mode instead of "music_live"
|
||||
new_mode = "music" if next_sport == "music" else f"{next_sport}_live"
|
||||
logger.info(f"Current live sport {current_sport_type} no longer has priority, switching to {new_mode}")
|
||||
self.current_display_mode = new_mode
|
||||
if hasattr(self, '_last_logged_duration'):
|
||||
delattr(self, '_last_logged_duration')
|
||||
self.force_clear = True
|
||||
self.last_switch = current_time
|
||||
manager_to_display = getattr(self, f"{next_sport}_live", None)
|
||||
manager_to_display = self.music_manager if next_sport == "music" else getattr(self, f"{next_sport}_live", None)
|
||||
else:
|
||||
# Check if duration has elapsed for current sport
|
||||
current_duration = self.get_current_duration()
|
||||
@@ -1173,7 +1267,8 @@ class DisplayController:
|
||||
current_index = live_priority_sports.index(current_sport_type)
|
||||
next_index = (current_index + 1) % len(live_priority_sports)
|
||||
next_sport = live_priority_sports[next_index]
|
||||
new_mode = f"{next_sport}_live"
|
||||
# Special case for music - use "music" mode instead of "music_live"
|
||||
new_mode = "music" if next_sport == "music" else f"{next_sport}_live"
|
||||
|
||||
logger.info(f"Rotating live priority sports: {current_sport_type} -> {next_sport} (duration: {current_duration}s)")
|
||||
self.current_display_mode = new_mode
|
||||
@@ -1181,10 +1276,11 @@ class DisplayController:
|
||||
delattr(self, '_last_logged_duration')
|
||||
self.force_clear = True
|
||||
self.last_switch = current_time
|
||||
manager_to_display = getattr(self, f"{next_sport}_live", None)
|
||||
manager_to_display = self.music_manager if next_sport == "music" else getattr(self, f"{next_sport}_live", None)
|
||||
else:
|
||||
self.force_clear = False
|
||||
manager_to_display = getattr(self, f"{current_sport_type}_live", None)
|
||||
# Special case for music - use "music" mode instead of "music_live"
|
||||
manager_to_display = self.music_manager if current_sport_type == "music" else getattr(self, f"{current_sport_type}_live", None)
|
||||
else:
|
||||
# If no sport has live_priority takeover, treat as regular rotation
|
||||
is_currently_live = False
|
||||
@@ -1193,14 +1289,19 @@ class DisplayController:
|
||||
if live_priority_takeover:
|
||||
# Switch to first live priority sport
|
||||
next_sport = live_priority_sports[0]
|
||||
new_mode = f"{next_sport}_live"
|
||||
# Special case for music - use "music" mode instead of "music_live"
|
||||
new_mode = "music" if next_sport == "music" else f"{next_sport}_live"
|
||||
|
||||
# Double-check that the manager actually has live games before switching
|
||||
target_manager = getattr(self, f"{next_sport}_live", None)
|
||||
if target_manager and hasattr(target_manager, 'live_games') and len(target_manager.live_games) > 0:
|
||||
# Double-check that the manager actually has live content before switching
|
||||
if next_sport == "music":
|
||||
target_manager = self.music_manager if self._music_has_live_content() else None
|
||||
else:
|
||||
target_manager = getattr(self, f"{next_sport}_live", None)
|
||||
|
||||
if target_manager and ((next_sport == "music") or (hasattr(target_manager, 'live_games') and len(target_manager.live_games) > 0)):
|
||||
logger.info(f"Live priority takeover: Switching to {new_mode} from {self.current_display_mode}")
|
||||
logger.debug(f"[DisplayController] Live priority takeover details: sport={next_sport}, manager={target_manager}, live_games={target_manager.live_games}")
|
||||
if previous_mode_before_switch == 'music' and self.music_manager:
|
||||
logger.debug(f"[DisplayController] Live priority takeover details: sport={next_sport}, manager={target_manager}")
|
||||
if previous_mode_before_switch == 'music' and self.music_manager and next_sport != "music":
|
||||
self.music_manager.deactivate_music_display()
|
||||
self.current_display_mode = new_mode
|
||||
# Reset logged duration when mode changes
|
||||
@@ -1210,7 +1311,7 @@ class DisplayController:
|
||||
self.last_switch = current_time
|
||||
manager_to_display = target_manager
|
||||
else:
|
||||
logger.warning(f"[DisplayController] Live priority takeover attempted for {new_mode} but manager has no live games, skipping takeover")
|
||||
logger.warning(f"[DisplayController] Live priority takeover attempted for {new_mode} but manager has no live content, skipping takeover")
|
||||
live_priority_takeover = False
|
||||
else:
|
||||
# No live_priority takeover, regular rotation
|
||||
@@ -1329,6 +1430,8 @@ class DisplayController:
|
||||
manager_to_display = self.soccer_upcoming
|
||||
elif self.current_display_mode == 'music' and self.music_manager:
|
||||
manager_to_display = self.music_manager
|
||||
elif self.current_display_mode == 'music_live' and self.music_manager:
|
||||
manager_to_display = self.music_manager
|
||||
elif self.current_display_mode == 'nhl_live' and self.nhl_live:
|
||||
manager_to_display = self.nhl_live
|
||||
elif self.current_display_mode == 'nba_live' and self.nba_live:
|
||||
@@ -1377,12 +1480,22 @@ class DisplayController:
|
||||
logger.info(f"manager_to_display is {current_manager_type}")
|
||||
self._last_logged_manager_type = current_manager_type
|
||||
|
||||
if self.current_display_mode == 'music' and self.music_manager:
|
||||
if self.current_display_mode in ['music', 'music_live'] and self.music_manager:
|
||||
# Call MusicManager's display method
|
||||
self.music_manager.display(force_clear=self.force_clear)
|
||||
# Reset force_clear if it was true for this mode
|
||||
if self.force_clear:
|
||||
self.force_clear = False
|
||||
try:
|
||||
self.music_manager.display(force_clear=self.force_clear)
|
||||
# Reset force_clear if it was true for this mode
|
||||
if self.force_clear:
|
||||
self.force_clear = False
|
||||
except SkipModuleException as e:
|
||||
# Music module requested skip (nothing playing and configured to skip)
|
||||
logger.info(f"Music module requested skip: {e}")
|
||||
# Force change to next module
|
||||
self.force_change = True
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error in music display: {e}", exc_info=True)
|
||||
# Reset force_clear on error
|
||||
self.force_clear = True
|
||||
elif manager_to_display:
|
||||
logger.debug(f"Attempting to display mode: {self.current_display_mode} using manager {type(manager_to_display).__name__} with force_clear={self.force_clear}")
|
||||
# Call the appropriate display method based on mode/manager type
|
||||
|
||||
@@ -34,6 +34,10 @@ class MusicSource(Enum):
|
||||
SPOTIFY = auto()
|
||||
YTM = auto()
|
||||
|
||||
class SkipModuleException(StopIteration):
|
||||
"""Exception raised when a module should be skipped to the next one."""
|
||||
pass
|
||||
|
||||
class MusicManager:
|
||||
def __init__(self, display_manager, config, update_callback=None):
|
||||
self.display_manager = display_manager
|
||||
@@ -65,6 +69,7 @@ class MusicManager:
|
||||
self.album_scroll_tick = 0
|
||||
self.is_music_display_active = False # New state variable
|
||||
self.is_currently_showing_nothing_playing = False # To prevent flashing
|
||||
self.nothing_playing_start_time = None # Timestamp when "Nothing Playing" started being displayed
|
||||
self._needs_immediate_full_refresh = False # Flag for forcing refresh from YTM updates
|
||||
self.ytm_event_data_queue = queue.Queue(maxsize=1) # Queue for event data
|
||||
|
||||
@@ -306,6 +311,10 @@ class MusicManager:
|
||||
def deactivate_music_display(self):
|
||||
logger.info("Music display deactivated.")
|
||||
self.is_music_display_active = False
|
||||
# Reset the nothing playing timer when display is deactivated
|
||||
if self.nothing_playing_start_time is not None:
|
||||
logger.debug("MusicManager: Display deactivated, resetting nothing playing timer")
|
||||
self.nothing_playing_start_time = None
|
||||
if self.ytm and self.ytm.is_connected:
|
||||
logger.info("Disconnecting YTM client due to music display deactivation.")
|
||||
self.ytm.disconnect_client()
|
||||
@@ -692,6 +701,23 @@ class MusicManager:
|
||||
if perform_full_refresh_this_cycle:
|
||||
logger.debug(f"MusicManager.display (Full Refresh Render): Using snapshot - Title: '{snapshot_title_for_log}'")
|
||||
|
||||
# --- Check if we should skip when nothing is playing ---
|
||||
music_config = self.config.get('music', {})
|
||||
skip_when_nothing_playing = music_config.get('skip_when_nothing_playing', True)
|
||||
skip_delay_seconds = music_config.get('skip_delay_seconds', 2)
|
||||
|
||||
if (not current_track_info_snapshot or current_track_info_snapshot.get('title') == 'Nothing Playing') and skip_when_nothing_playing:
|
||||
# Check if we've been showing "Nothing Playing" for the configured delay
|
||||
current_time = time.time()
|
||||
if self.nothing_playing_start_time is None:
|
||||
# We just started showing "Nothing Playing", set the start time
|
||||
self.nothing_playing_start_time = current_time
|
||||
logger.debug(f"MusicManager: Started showing 'Nothing Playing', timer set (will skip after {skip_delay_seconds}s)")
|
||||
|
||||
elif current_time - self.nothing_playing_start_time >= skip_delay_seconds:
|
||||
logger.info(f"MusicManager: Nothing playing for {skip_delay_seconds}+ seconds, raising SkipModuleException to advance to next module.")
|
||||
raise SkipModuleException(f"Music module: Nothing playing for {skip_delay_seconds}+ seconds and skip_when_nothing_playing is enabled")
|
||||
|
||||
# --- Original Nothing Playing Logic ---
|
||||
if not current_track_info_snapshot or current_track_info_snapshot.get('title') == 'Nothing Playing':
|
||||
if not hasattr(self, '_last_nothing_playing_log_time') or time.time() - getattr(self, '_last_nothing_playing_log_time', 0) > 30:
|
||||
@@ -722,6 +748,11 @@ class MusicManager:
|
||||
self.last_album_art_url = None
|
||||
return
|
||||
|
||||
# Reset the nothing playing timer when music starts playing
|
||||
if self.nothing_playing_start_time is not None:
|
||||
logger.debug("MusicManager: Music started playing, resetting nothing playing timer")
|
||||
self.nothing_playing_start_time = None
|
||||
|
||||
self.is_currently_showing_nothing_playing = False
|
||||
|
||||
if perform_full_refresh_this_cycle:
|
||||
|
||||
@@ -1790,6 +1790,37 @@
|
||||
<input type="number" class="form-control" id="music_polling_interval" name="music_polling_interval" value="{{ safe_config_get(main_config, 'music', 'POLLING_INTERVAL_SECONDS', default=1) }}" min="1" max="60">
|
||||
<div class="description">How often to check for music updates</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="music_skip_when_nothing_playing" name="music_skip_when_nothing_playing" {% if safe_config_get(main_config, 'music', 'skip_when_nothing_playing', default=True) %}checked{% endif %}>
|
||||
Skip When Nothing Playing
|
||||
</label>
|
||||
<div class="description">Skip to next module when no music is playing</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="music_skip_delay_seconds">Skip Delay (seconds):</label>
|
||||
<input type="number" class="form-control" id="music_skip_delay_seconds" name="music_skip_delay_seconds" value="{{ safe_config_get(main_config, 'music', 'skip_delay_seconds', default=2) }}" min="0" max="60">
|
||||
<div class="description">Wait time before skipping when nothing playing</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="music_live_priority" name="music_live_priority" {% if safe_config_get(main_config, 'music', 'live_priority', default=True) %}checked{% endif %}>
|
||||
Enable Live Priority
|
||||
</label>
|
||||
<div class="description">Include music in live priority rotation when playing</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="music_live_game_duration">Live Duration (seconds):</label>
|
||||
<input type="number" class="form-control" id="music_live_game_duration" name="music_live_game_duration" value="{{ safe_config_get(main_config, 'music', 'live_game_duration', default=30) }}" min="10" max="300">
|
||||
<div class="description">How long music stays in live priority rotation</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success">Save Music Settings</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -3222,7 +3253,11 @@
|
||||
enabled: document.getElementById('music_enabled').checked,
|
||||
preferred_source: document.getElementById('music_preferred_source').value,
|
||||
YTM_COMPANION_URL: document.getElementById('ytm_companion_url').value,
|
||||
POLLING_INTERVAL_SECONDS: parseInt(document.getElementById('music_polling_interval').value)
|
||||
POLLING_INTERVAL_SECONDS: parseInt(document.getElementById('music_polling_interval').value),
|
||||
skip_when_nothing_playing: document.getElementById('music_skip_when_nothing_playing').checked,
|
||||
skip_delay_seconds: parseInt(document.getElementById('music_skip_delay_seconds').value),
|
||||
live_priority: document.getElementById('music_live_priority').checked,
|
||||
live_game_duration: parseInt(document.getElementById('music_live_game_duration').value)
|
||||
}
|
||||
};
|
||||
await saveConfigJson(payload);
|
||||
|
||||
Reference in New Issue
Block a user