Added server-side saving for settings

This commit is contained in:
Trevor Mears
2025-12-31 15:35:37 -08:00
parent 404364b904
commit d1bfd1b9e7
7 changed files with 234 additions and 55 deletions
+8
View File
@@ -112,6 +112,14 @@ const API = {
cache: {
clear: (sourceId) => API.request('DELETE', `/proxy/cache/${sourceId}`)
}
},
// Settings
settings: {
get: () => API.request('GET', '/settings'),
update: (data) => API.request('PUT', '/settings', data),
reset: () => API.request('DELETE', '/settings'),
getDefaults: () => API.request('GET', '/settings/defaults')
}
};
+2 -1
View File
@@ -981,7 +981,8 @@ class ChannelList {
// Get stream URL
let streamUrl;
if (channel.sourceType === 'xtream') {
const streamFormat = localStorage.getItem('nodecast_tv_stream_format') || 'm3u8';
// Get stream format from player settings (server-side) or fallback
const streamFormat = window.app?.player?.settings?.streamFormat || 'm3u8';
const result = await API.proxy.xtream.getStreamUrl(channel.sourceId, channel.streamId, 'live', streamFormat);
streamUrl = result.url;
} else {
+70 -35
View File
@@ -15,48 +15,83 @@ class VideoPlayer {
this.overlayDuration = 5000; // 5 seconds
this.isUsingProxy = false;
this.currentUrl = null;
this.settingsLoaded = false;
// Settings (loaded from localStorage)
this.settings = this.loadSettings();
// Settings - start with defaults, load from server async
this.settings = this.getDefaultSettings();
this.init();
// Load settings from server, then init
this.loadSettingsFromServer().then(() => {
this.init();
});
}
/**
* Load settings from localStorage
* Default settings
*/
getDefaultSettings() {
return {
arrowKeysChangeChannel: true,
overlayDuration: 5,
defaultVolume: 80,
rememberVolume: true,
lastVolume: 80,
autoPlayNextEpisode: false,
forceProxy: false,
forceTranscode: false,
forceRemux: false,
streamFormat: 'm3u8',
epgRefreshInterval: '24'
};
}
/**
* Load settings from server API
*/
async loadSettingsFromServer() {
try {
const serverSettings = await API.settings.get();
this.settings = { ...this.getDefaultSettings(), ...serverSettings };
this.settingsLoaded = true;
console.log('[Player] Settings loaded from server');
} catch (err) {
console.warn('[Player] Failed to load settings from server, using defaults:', err.message);
// Fall back to localStorage for backwards compatibility
try {
const saved = localStorage.getItem('nodecast_tv_player_settings');
if (saved) {
this.settings = { ...this.getDefaultSettings(), ...JSON.parse(saved) };
console.log('[Player] Settings loaded from localStorage (fallback)');
}
} catch (localErr) {
console.error('[Player] Error loading localStorage settings:', localErr);
}
}
}
/**
* Save settings to server API
*/
async saveSettings() {
try {
await API.settings.update(this.settings);
console.log('[Player] Settings saved to server');
} catch (err) {
console.error('[Player] Error saving settings to server:', err);
// Also save to localStorage as backup
try {
localStorage.setItem('nodecast_tv_player_settings', JSON.stringify(this.settings));
} catch (localErr) {
console.error('[Player] Error saving to localStorage:', localErr);
}
}
}
/**
* Legacy sync method for compatibility - calls async version
*/
loadSettings() {
const defaults = {
arrowKeysChangeChannel: true, // Use arrow keys for channel navigation
overlayDuration: 5, // Seconds
defaultVolume: 80, // 0-100
rememberVolume: true, // Persist volume between sessions
lastVolume: 80, // Last used volume (if rememberVolume is true)
autoPlayNextEpisode: false, // Auto-play next episode in series
forceProxy: false, // Force all streams through backend proxy
forceTranscode: false, // Force audio transcoding (fixes Dolby/AC3 audio)
forceRemux: false // Force remux to MP4 (fixes raw .ts streams, lightweight)
};
try {
const saved = localStorage.getItem('nodecast_tv_player_settings');
if (saved) {
return { ...defaults, ...JSON.parse(saved) };
}
} catch (err) {
console.error('Error loading settings:', err);
}
return defaults;
}
/**
* Save settings to localStorage
*/
saveSettings() {
try {
localStorage.setItem('nodecast_tv_player_settings', JSON.stringify(this.settings));
} catch (err) {
console.error('Error saving settings:', err);
}
return this.settings;
}
/**
+37 -17
View File
@@ -105,29 +105,27 @@ class SettingsPage {
// EPG refresh interval
const epgRefreshSelect = document.getElementById('epg-refresh-interval');
if (epgRefreshSelect) {
// Load saved value
const savedInterval = localStorage.getItem('nodecast_tv_epg_refresh_interval');
if (savedInterval) {
epgRefreshSelect.value = savedInterval;
}
if (epgRefreshSelect && this.app.player?.settings) {
// Load saved value from player settings
epgRefreshSelect.value = this.app.player.settings.epgRefreshInterval || '24';
// Save on change
epgRefreshSelect.addEventListener('change', () => {
localStorage.setItem('nodecast_tv_epg_refresh_interval', epgRefreshSelect.value);
this.app.player.settings.epgRefreshInterval = epgRefreshSelect.value;
this.app.player.saveSettings();
});
}
// Stream output format
const streamFormatSelect = document.getElementById('setting-stream-format');
if (streamFormatSelect) {
// Load saved value
const savedFormat = localStorage.getItem('nodecast_tv_stream_format') || 'm3u8';
streamFormatSelect.value = savedFormat;
if (streamFormatSelect && this.app.player?.settings) {
// Load saved value from player settings
streamFormatSelect.value = this.app.player.settings.streamFormat || 'm3u8';
// Save on change
streamFormatSelect.addEventListener('change', () => {
localStorage.setItem('nodecast_tv_stream_format', streamFormatSelect.value);
this.app.player.settings.streamFormat = streamFormatSelect.value;
this.app.player.saveSettings();
});
}
}
@@ -146,12 +144,34 @@ class SettingsPage {
// Load sources when page is shown
await this.app.sourceManager.loadSources();
// Refresh player settings display
const arrowKeysToggle = document.getElementById('setting-arrow-keys');
const overlayDurationInput = document.getElementById('setting-overlay-duration');
// Refresh ALL player settings from server
if (this.app.player?.settings) {
arrowKeysToggle.checked = this.app.player.settings.arrowKeysChangeChannel;
overlayDurationInput.value = this.app.player.settings.overlayDuration;
const s = this.app.player.settings;
// Player settings
const arrowKeysToggle = document.getElementById('setting-arrow-keys');
const overlayDurationInput = document.getElementById('setting-overlay-duration');
const defaultVolumeSlider = document.getElementById('setting-default-volume');
const volumeValueDisplay = document.getElementById('volume-value');
const rememberVolumeToggle = document.getElementById('setting-remember-volume');
const autoPlayNextToggle = document.getElementById('setting-autoplay-next');
const forceProxyToggle = document.getElementById('setting-force-proxy');
const forceTranscodeToggle = document.getElementById('setting-force-transcode');
const forceRemuxToggle = document.getElementById('setting-force-remux');
const epgRefreshSelect = document.getElementById('epg-refresh-interval');
const streamFormatSelect = document.getElementById('setting-stream-format');
if (arrowKeysToggle) arrowKeysToggle.checked = s.arrowKeysChangeChannel;
if (overlayDurationInput) overlayDurationInput.value = s.overlayDuration;
if (defaultVolumeSlider) defaultVolumeSlider.value = s.defaultVolume;
if (volumeValueDisplay) volumeValueDisplay.textContent = s.defaultVolume + '%';
if (rememberVolumeToggle) rememberVolumeToggle.checked = s.rememberVolume;
if (autoPlayNextToggle) autoPlayNextToggle.checked = s.autoPlayNextEpisode;
if (forceProxyToggle) forceProxyToggle.checked = s.forceProxy || false;
if (forceTranscodeToggle) forceTranscodeToggle.checked = s.forceTranscode || false;
if (forceRemuxToggle) forceRemuxToggle.checked = s.forceRemux || false;
if (epgRefreshSelect) epgRefreshSelect.value = s.epgRefreshInterval || '24';
if (streamFormatSelect) streamFormatSelect.value = s.streamFormat || 'm3u8';
}
}