- 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
383 lines
14 KiB
JavaScript
383 lines
14 KiB
JavaScript
/**
|
|
* AniWorld - Main Config Module
|
|
*
|
|
* Handles main configuration (directory, connection) and config management
|
|
* (backup, export, validate, reset).
|
|
*
|
|
* Dependencies: constants.js, api-client.js, ui-utils.js
|
|
*/
|
|
|
|
var AniWorld = window.AniWorld || {};
|
|
|
|
AniWorld.MainConfig = (function() {
|
|
'use strict';
|
|
|
|
const API = AniWorld.Constants.API;
|
|
|
|
/**
|
|
* Save main configuration
|
|
*/
|
|
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;
|
|
}
|
|
|
|
// 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();
|
|
|
|
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
|
|
*/
|
|
function reset() {
|
|
if (confirm('Are you sure you want to reset the main configuration? This will clear the anime directory.')) {
|
|
document.getElementById('anime-directory-input').value = '';
|
|
document.getElementById('series-count-input').value = '0';
|
|
AniWorld.UI.showToast('Main configuration reset', 'info');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test network connection
|
|
*/
|
|
async function testConnection() {
|
|
try {
|
|
AniWorld.UI.showToast('Testing connection...', 'info');
|
|
|
|
const response = await AniWorld.ApiClient.get(API.DIAGNOSTICS_NETWORK);
|
|
if (!response) return;
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.status === 'success') {
|
|
const networkStatus = data.data;
|
|
const connectionDiv = document.getElementById('connection-status-display');
|
|
const statusIndicator = connectionDiv.querySelector('.status-indicator');
|
|
const statusText = connectionDiv.querySelector('.status-text');
|
|
|
|
if (networkStatus.aniworld_reachable) {
|
|
statusIndicator.className = 'status-indicator connected';
|
|
statusText.textContent = 'Connected';
|
|
AniWorld.UI.showToast('Connection test successful', 'success');
|
|
} else {
|
|
statusIndicator.className = 'status-indicator disconnected';
|
|
statusText.textContent = 'Disconnected';
|
|
AniWorld.UI.showToast('Connection test failed', 'error');
|
|
}
|
|
} else {
|
|
AniWorld.UI.showToast('Connection test failed', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error testing connection:', error);
|
|
AniWorld.UI.showToast('Connection test failed', 'error');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Browse for directory
|
|
*/
|
|
function browseDirectory() {
|
|
const currentPath = document.getElementById('anime-directory-input').value;
|
|
const newPath = prompt('Enter the anime directory path:', currentPath);
|
|
|
|
if (newPath !== null && newPath.trim() !== '') {
|
|
document.getElementById('anime-directory-input').value = newPath.trim();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refresh status display
|
|
*/
|
|
async function refreshStatus() {
|
|
try {
|
|
// Load full configuration
|
|
const config = await loadCurrentConfig();
|
|
if (!config) return;
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create configuration backup
|
|
*/
|
|
async function createBackup() {
|
|
const backupName = prompt('Enter backup name (optional):');
|
|
|
|
try {
|
|
const response = await AniWorld.ApiClient.request(API.CONFIG_BACKUP, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name: backupName || '' })
|
|
});
|
|
|
|
if (!response) return;
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
AniWorld.UI.showToast('Backup created: ' + data.filename, 'success');
|
|
} else {
|
|
AniWorld.UI.showToast('Failed to create backup: ' + data.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating backup:', error);
|
|
AniWorld.UI.showToast('Failed to create backup', 'error');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* View configuration backups
|
|
*/
|
|
async function viewBackups() {
|
|
try {
|
|
const response = await AniWorld.ApiClient.get(API.CONFIG_BACKUPS);
|
|
if (!response) return;
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showBackupsModal(data.backups);
|
|
} else {
|
|
AniWorld.UI.showToast('Failed to load backups: ' + data.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading backups:', error);
|
|
AniWorld.UI.showToast('Failed to load backups', 'error');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show backups modal
|
|
*/
|
|
function showBackupsModal(backups) {
|
|
// Implementation for showing backups modal
|
|
console.log('Backups:', backups);
|
|
AniWorld.UI.showToast('Found ' + backups.length + ' backup(s)', 'info');
|
|
}
|
|
|
|
/**
|
|
* Export configuration
|
|
*/
|
|
function exportConfig() {
|
|
AniWorld.UI.showToast('Export configuration feature coming soon', 'info');
|
|
}
|
|
|
|
/**
|
|
* Validate configuration
|
|
*/
|
|
async function validateConfig() {
|
|
try {
|
|
const response = await AniWorld.ApiClient.request(API.CONFIG_VALIDATE, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({})
|
|
});
|
|
|
|
if (!response) return;
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showValidationResults(data.validation);
|
|
} else {
|
|
AniWorld.UI.showToast('Validation failed: ' + data.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error validating config:', error);
|
|
AniWorld.UI.showToast('Failed to validate configuration', 'error');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show validation results
|
|
*/
|
|
function showValidationResults(validation) {
|
|
const container = document.getElementById('validation-results');
|
|
container.innerHTML = '';
|
|
container.classList.remove('hidden');
|
|
|
|
if (validation.valid) {
|
|
const success = document.createElement('div');
|
|
success.className = 'validation-success';
|
|
success.innerHTML = '<i class="fas fa-check-circle"></i> Configuration is valid!';
|
|
container.appendChild(success);
|
|
} else {
|
|
const header = document.createElement('div');
|
|
header.innerHTML = '<strong>Validation Issues Found:</strong>';
|
|
container.appendChild(header);
|
|
}
|
|
|
|
// Show errors
|
|
validation.errors.forEach(function(error) {
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.className = 'validation-error';
|
|
errorDiv.innerHTML = '<i class="fas fa-times-circle"></i> Error: ' + error;
|
|
container.appendChild(errorDiv);
|
|
});
|
|
|
|
// Show warnings
|
|
validation.warnings.forEach(function(warning) {
|
|
const warningDiv = document.createElement('div');
|
|
warningDiv.className = 'validation-warning';
|
|
warningDiv.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Warning: ' + warning;
|
|
container.appendChild(warningDiv);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reset all configuration to defaults
|
|
*/
|
|
async function resetAllConfig() {
|
|
if (!confirm('Are you sure you want to reset all configuration to defaults? This cannot be undone (except by restoring a backup).')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await AniWorld.ApiClient.request(API.CONFIG_RESET, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ preserve_security: true })
|
|
});
|
|
|
|
if (!response) return;
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
AniWorld.UI.showToast('Configuration reset to defaults', 'success');
|
|
// Notify caller to reload config modal
|
|
return true;
|
|
} else {
|
|
AniWorld.UI.showToast('Failed to reset config: ' + data.error, 'error');
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
console.error('Error resetting config:', error);
|
|
AniWorld.UI.showToast('Failed to reset configuration', 'error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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,
|
|
reset: reset,
|
|
testConnection: testConnection,
|
|
browseDirectory: browseDirectory,
|
|
refreshStatus: refreshStatus,
|
|
createBackup: createBackup,
|
|
viewBackups: viewBackups,
|
|
exportConfig: exportConfig,
|
|
validateConfig: validateConfig,
|
|
resetAllConfig: resetAllConfig,
|
|
saveBackupConfig: saveBackupConfig
|
|
};
|
|
})();
|