Enhanced setup and settings pages with full configuration

- Extended SetupRequest model to include all configuration fields
- Updated setup API endpoint to handle comprehensive configuration
- Created new setup.html with organized configuration sections
- Enhanced config modal in index.html with all settings
- Updated JavaScript modules to use unified config API
- Added backup configuration section
- Documented new features in features.md and instructions.md
This commit is contained in:
2026-01-17 18:01:15 +01:00
parent d676cb7dca
commit 4e29c4ed80
12 changed files with 1807 additions and 680 deletions

View File

@@ -56,6 +56,9 @@ AniWorld.ConfigManager = (function() {
// NFO configuration
bindNFOEvents();
// Backup configuration
bindBackupEvents();
// Status panel
const closeStatus = document.getElementById('close-status');
if (closeStatus) {
@@ -118,8 +121,16 @@ AniWorld.ConfigManager = (function() {
}
}
/**
* Bind NFO config events
/** * Bind backup config events
*/
function bindBackupEvents() {
const saveBackup = document.getElementById('save-backup-config');
if (saveBackup) {
saveBackup.addEventListener('click', AniWorld.MainConfig.saveBackupConfig);
}
}
/** * Bind NFO config events
*/
function bindNFOEvents() {
const saveNFO = document.getElementById('save-nfo-config');

View File

@@ -113,28 +113,25 @@ AniWorld.LoggingConfig = (function() {
*/
async function save() {
try {
const config = {
log_level: document.getElementById('log-level').value,
enable_console_logging: document.getElementById('enable-console-logging').checked,
enable_console_progress: document.getElementById('enable-console-progress').checked,
enable_fail2ban_logging: document.getElementById('enable-fail2ban-logging').checked
// Get current config
const configResponse = await AniWorld.ApiClient.get(AniWorld.Constants.API.CONFIG);
if (!configResponse) return;
const config = await configResponse.json();
// Update logging settings
config.logging = {
level: document.getElementById('log-level').value.toUpperCase(),
file: document.getElementById('log-file').value.trim() || null,
max_bytes: document.getElementById('log-max-bytes').value ? parseInt(document.getElementById('log-max-bytes').value) : null,
backup_count: parseInt(document.getElementById('log-backup-count').value) || 3
};
const response = await AniWorld.ApiClient.request(API.LOGGING_CONFIG, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(config)
});
// Save updated config
const response = await AniWorld.ApiClient.put(AniWorld.Constants.API.CONFIG, config);
if (!response) return;
const data = await response.json();
if (data.success) {
AniWorld.UI.showToast('Logging configuration saved successfully', 'success');
await load();
} else {
AniWorld.UI.showToast('Failed to save logging config: ' + data.error, 'error');
}
AniWorld.UI.showToast('Logging configuration saved successfully', 'success');
await load();
} catch (error) {
console.error('Error saving logging config:', error);
AniWorld.UI.showToast('Failed to save logging configuration', 'error');

View File

@@ -20,31 +20,55 @@ AniWorld.MainConfig = (function() {
async function save() {
try {
const animeDirectory = document.getElementById('anime-directory-input').value.trim();
const appName = document.getElementById('app-name-input').value.trim();
const dataDir = document.getElementById('data-dir-input').value.trim();
if (!animeDirectory) {
AniWorld.UI.showToast('Please enter an anime directory path', 'error');
return;
}
const response = await AniWorld.ApiClient.post(API.CONFIG_DIRECTORY, {
directory: animeDirectory
});
// Get current config
const currentConfig = await loadCurrentConfig();
if (!currentConfig) {
AniWorld.UI.showToast('Failed to load current configuration', 'error');
return;
}
// Update fields
if (appName) currentConfig.name = appName;
if (dataDir) currentConfig.data_dir = dataDir;
if (!currentConfig.other) currentConfig.other = {};
currentConfig.other.anime_directory = animeDirectory;
// Save updated config
const response = await AniWorld.ApiClient.put(AniWorld.Constants.API.CONFIG, currentConfig);
if (!response) return;
const data = await response.json();
if (data.success) {
AniWorld.UI.showToast('Main configuration saved successfully', 'success');
await refreshStatus();
} else {
AniWorld.UI.showToast('Failed to save configuration: ' + data.error, 'error');
}
AniWorld.UI.showToast('Main configuration saved successfully', 'success');
await refreshStatus();
} catch (error) {
console.error('Error saving main config:', error);
AniWorld.UI.showToast('Failed to save main configuration', 'error');
}
}
/**
* Load current configuration from API
*/
async function loadCurrentConfig() {
try {
const response = await AniWorld.ApiClient.get(AniWorld.Constants.API.CONFIG);
if (!response) return null;
return await response.json();
} catch (error) {
console.error('Error loading config:', error);
return null;
}
}
/**
* Reset main configuration
*/
@@ -109,12 +133,45 @@ AniWorld.MainConfig = (function() {
*/
async function refreshStatus() {
try {
const response = await AniWorld.ApiClient.get(API.ANIME_STATUS);
if (!response) return;
const data = await response.json();
// Load full configuration
const config = await loadCurrentConfig();
if (!config) return;
document.getElementById('anime-directory-input').value = data.directory || '';
document.getElementById('series-count-input').value = data.series_count || '0';
// Populate general settings
document.getElementById('app-name-input').value = config.name || 'Aniworld';
document.getElementById('data-dir-input').value = config.data_dir || 'data';
document.getElementById('anime-directory-input').value = config.other?.anime_directory || '';
// Populate scheduler settings
document.getElementById('scheduled-rescan-enabled').checked = config.scheduler?.enabled || false;
document.getElementById('scheduled-rescan-interval').value = config.scheduler?.interval_minutes || 60;
// Populate logging settings
document.getElementById('log-level').value = config.logging?.level || 'INFO';
document.getElementById('log-file').value = config.logging?.file || '';
document.getElementById('log-max-bytes').value = config.logging?.max_bytes || '';
document.getElementById('log-backup-count').value = config.logging?.backup_count || 3;
// Populate backup settings
document.getElementById('backup-enabled').checked = config.backup?.enabled || false;
document.getElementById('backup-path').value = config.backup?.path || 'data/backups';
document.getElementById('backup-keep-days').value = config.backup?.keep_days || 30;
// Populate NFO settings
document.getElementById('tmdb-api-key').value = config.nfo?.tmdb_api_key || '';
document.getElementById('nfo-auto-create').checked = config.nfo?.auto_create || false;
document.getElementById('nfo-update-on-scan').checked = config.nfo?.update_on_scan || false;
document.getElementById('nfo-download-poster').checked = config.nfo?.download_poster !== false;
document.getElementById('nfo-download-logo').checked = config.nfo?.download_logo !== false;
document.getElementById('nfo-download-fanart').checked = config.nfo?.download_fanart !== false;
document.getElementById('nfo-image-size').value = config.nfo?.image_size || 'original';
// Get series count from status endpoint
const statusResponse = await AniWorld.ApiClient.get(API.ANIME_STATUS);
if (statusResponse) {
const statusData = await statusResponse.json();
document.getElementById('series-count-input').value = statusData.series_count || '0';
}
} catch (error) {
console.error('Error refreshing status:', error);
}
@@ -278,6 +335,36 @@ AniWorld.MainConfig = (function() {
}
}
/**
* Save backup configuration
*/
async function saveBackupConfig() {
try {
const config = await loadCurrentConfig();
if (!config) {
AniWorld.UI.showToast('Failed to load current configuration', 'error');
return;
}
// Update backup settings
config.backup = {
enabled: document.getElementById('backup-enabled').checked,
path: document.getElementById('backup-path').value.trim(),
keep_days: parseInt(document.getElementById('backup-keep-days').value) || 30
};
// Save updated config
const response = await AniWorld.ApiClient.put(AniWorld.Constants.API.CONFIG, config);
if (!response) return;
AniWorld.UI.showToast('Backup configuration saved successfully', 'success');
} catch (error) {
console.error('Error saving backup config:', error);
AniWorld.UI.showToast('Failed to save backup configuration', 'error');
}
}
// Public API
return {
save: save,
@@ -289,6 +376,7 @@ AniWorld.MainConfig = (function() {
viewBackups: viewBackups,
exportConfig: exportConfig,
validateConfig: validateConfig,
resetAllConfig: resetAllConfig
resetAllConfig: resetAllConfig,
saveBackupConfig: saveBackupConfig
};
})();

View File

@@ -92,8 +92,16 @@ AniWorld.NFOConfig = (function() {
return;
}
const nfoConfig = {
tmdb_api_key: tmdbKey ? tmdbKey.value.trim() : null,
// Get current config
const configResponse = await AniWorld.ApiClient.get(AniWorld.Constants.API.CONFIG);
if (!configResponse) {
throw new Error('Failed to load current configuration');
}
const config = await configResponse.json();
// Update NFO settings
config.nfo = {
tmdb_api_key: tmdbKey ? tmdbKey.value.trim() || null : null,
auto_create: autoCreate ? autoCreate.checked : false,
update_on_scan: updateOnScan ? updateOnScan.checked : false,
download_poster: downloadPoster ? downloadPoster.checked : true,
@@ -103,13 +111,7 @@ AniWorld.NFOConfig = (function() {
};
// Save configuration
const response = await AniWorld.ApiClient.request(
API.CONFIG,
{
method: 'PUT',
body: JSON.stringify({ nfo: nfoConfig })
}
);
const response = await AniWorld.ApiClient.put(AniWorld.Constants.API.CONFIG, config);
if (response) {
AniWorld.UI.showToast('NFO configuration saved successfully', 'success');

View File

@@ -55,24 +55,25 @@ AniWorld.SchedulerConfig = (function() {
async function save() {
try {
const enabled = document.getElementById('scheduled-rescan-enabled').checked;
const time = document.getElementById('scheduled-rescan-time').value;
const autoDownload = document.getElementById('auto-download-after-rescan').checked;
const interval = parseInt(document.getElementById('scheduled-rescan-interval').value) || 60;
const response = await AniWorld.ApiClient.post(API.SCHEDULER_CONFIG, {
// Get current config
const configResponse = await AniWorld.ApiClient.get(AniWorld.Constants.API.CONFIG);
if (!configResponse) return;
const config = await configResponse.json();
// Update scheduler settings
config.scheduler = {
enabled: enabled,
time: time,
auto_download_after_rescan: autoDownload
});
interval_minutes: interval
};
// Save updated config
const response = await AniWorld.ApiClient.put(AniWorld.Constants.API.CONFIG, config);
if (!response) return;
const data = await response.json();
if (data.success) {
AniWorld.UI.showToast('Scheduler configuration saved successfully', 'success');
await load();
} else {
AniWorld.UI.showToast('Failed to save config: ' + data.error, 'error');
}
AniWorld.UI.showToast('Scheduler configuration saved successfully', 'success');
await load();
} catch (error) {
console.error('Error saving scheduler config:', error);
AniWorld.UI.showToast('Failed to save scheduler configuration', 'error');