- Added NFOConfig model with TMDB API key, auto-create, media downloads, image size settings - Created NFO settings section in UI with form fields and validation - Implemented nfo-config.js module for loading, saving, and testing TMDB connection - Added TMDB API key validation endpoint (POST /api/config/tmdb/validate) - Integrated NFO config into AppConfig and ConfigUpdate models - Added 5 unit tests for NFO config model validation - Added API test for TMDB validation endpoint - All 16 config model tests passing, all 10 config API tests passing - Documented in docs/task7_status.md (100% complete)
249 lines
7.5 KiB
JavaScript
249 lines
7.5 KiB
JavaScript
/**
|
|
* AniWorld - Config Manager Module
|
|
*
|
|
* Orchestrates configuration modal and delegates to specialized config modules.
|
|
*
|
|
* Dependencies: constants.js, api-client.js, ui-utils.js,
|
|
* scheduler-config.js, logging-config.js, advanced-config.js, main-config.js
|
|
*/
|
|
|
|
var AniWorld = window.AniWorld || {};
|
|
|
|
AniWorld.ConfigManager = (function() {
|
|
'use strict';
|
|
|
|
const API = AniWorld.Constants.API;
|
|
|
|
/**
|
|
* Initialize the config manager
|
|
*/
|
|
function init() {
|
|
bindEvents();
|
|
}
|
|
|
|
/**
|
|
* Bind UI events
|
|
*/
|
|
function bindEvents() {
|
|
// Config modal
|
|
const configBtn = document.getElementById('config-btn');
|
|
if (configBtn) {
|
|
configBtn.addEventListener('click', showConfigModal);
|
|
}
|
|
|
|
const closeConfig = document.getElementById('close-config');
|
|
if (closeConfig) {
|
|
closeConfig.addEventListener('click', hideConfigModal);
|
|
}
|
|
|
|
const configModal = document.querySelector('#config-modal .modal-overlay');
|
|
if (configModal) {
|
|
configModal.addEventListener('click', hideConfigModal);
|
|
}
|
|
|
|
// Scheduler configuration
|
|
bindSchedulerEvents();
|
|
|
|
// Logging configuration
|
|
bindLoggingEvents();
|
|
|
|
// Advanced configuration
|
|
bindAdvancedEvents();
|
|
|
|
// Main configuration
|
|
bindMainEvents();
|
|
|
|
// NFO configuration
|
|
bindNFOEvents();
|
|
|
|
// Status panel
|
|
const closeStatus = document.getElementById('close-status');
|
|
if (closeStatus) {
|
|
closeStatus.addEventListener('click', hideStatus);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind scheduler-related events
|
|
*/
|
|
function bindSchedulerEvents() {
|
|
const schedulerEnabled = document.getElementById('scheduled-rescan-enabled');
|
|
if (schedulerEnabled) {
|
|
schedulerEnabled.addEventListener('change', AniWorld.SchedulerConfig.toggleTimeInput);
|
|
}
|
|
|
|
const saveScheduler = document.getElementById('save-scheduler-config');
|
|
if (saveScheduler) {
|
|
saveScheduler.addEventListener('click', AniWorld.SchedulerConfig.save);
|
|
}
|
|
|
|
const testScheduler = document.getElementById('test-scheduled-rescan');
|
|
if (testScheduler) {
|
|
testScheduler.addEventListener('click', AniWorld.SchedulerConfig.testRescan);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind logging-related events
|
|
*/
|
|
function bindLoggingEvents() {
|
|
const saveLogging = document.getElementById('save-logging-config');
|
|
if (saveLogging) {
|
|
saveLogging.addEventListener('click', AniWorld.LoggingConfig.save);
|
|
}
|
|
|
|
const testLogging = document.getElementById('test-logging');
|
|
if (testLogging) {
|
|
testLogging.addEventListener('click', AniWorld.LoggingConfig.testLogging);
|
|
}
|
|
|
|
const refreshLogs = document.getElementById('refresh-log-files');
|
|
if (refreshLogs) {
|
|
refreshLogs.addEventListener('click', AniWorld.LoggingConfig.loadLogFiles);
|
|
}
|
|
|
|
const cleanupLogs = document.getElementById('cleanup-logs');
|
|
if (cleanupLogs) {
|
|
cleanupLogs.addEventListener('click', AniWorld.LoggingConfig.cleanupLogs);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind advanced config events
|
|
*/
|
|
function bindAdvancedEvents() {
|
|
const saveAdvanced = document.getElementById('save-advanced-config');
|
|
if (saveAdvanced) {
|
|
saveAdvanced.addEventListener('click', AniWorld.AdvancedConfig.save);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind NFO config events
|
|
*/
|
|
function bindNFOEvents() {
|
|
const saveNFO = document.getElementById('save-nfo-config');
|
|
if (saveNFO) {
|
|
saveNFO.addEventListener('click', AniWorld.NFOConfig.save);
|
|
}
|
|
|
|
const testTMDB = document.getElementById('test-tmdb-connection');
|
|
if (testTMDB) {
|
|
testTMDB.addEventListener('click', AniWorld.NFOConfig.testTMDBConnection);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind main configuration events
|
|
*/
|
|
function bindMainEvents() {
|
|
const createBackup = document.getElementById('create-config-backup');
|
|
if (createBackup) {
|
|
createBackup.addEventListener('click', AniWorld.MainConfig.createBackup);
|
|
}
|
|
|
|
const viewBackups = document.getElementById('view-config-backups');
|
|
if (viewBackups) {
|
|
viewBackups.addEventListener('click', AniWorld.MainConfig.viewBackups);
|
|
}
|
|
|
|
const exportConfig = document.getElementById('export-config');
|
|
if (exportConfig) {
|
|
exportConfig.addEventListener('click', AniWorld.MainConfig.exportConfig);
|
|
}
|
|
|
|
const validateConfig = document.getElementById('validate-config');
|
|
if (validateConfig) {
|
|
validateConfig.addEventListener('click', AniWorld.MainConfig.validateConfig);
|
|
}
|
|
|
|
const resetConfig = document.getElementById('reset-config');
|
|
if (resetConfig) {
|
|
resetConfig.addEventListener('click', handleResetConfig);
|
|
}
|
|
|
|
const saveMain = document.getElementById('save-main-config');
|
|
if (saveMain) {
|
|
saveMain.addEventListener('click', AniWorld.MainConfig.save);
|
|
}
|
|
|
|
const resetMain = document.getElementById('reset-main-config');
|
|
if (resetMain) {
|
|
resetMain.addEventListener('click', AniWorld.MainConfig.reset);
|
|
}
|
|
|
|
const testConnection = document.getElementById('test-connection');
|
|
if (testConnection) {
|
|
testConnection.addEventListener('click', AniWorld.MainConfig.testConnection);
|
|
}
|
|
|
|
const browseDirectory = document.getElementById('browse-directory');
|
|
if (browseDirectory) {
|
|
browseDirectory.addEventListener('click', AniWorld.MainConfig.browseDirectory);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle reset config with modal refresh
|
|
*/
|
|
async function handleResetConfig() {
|
|
const success = await AniWorld.MainConfig.resetAllConfig();
|
|
if (success) {
|
|
setTimeout(function() {
|
|
hideConfigModal();
|
|
showConfigModal();
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show the configuration modal
|
|
*/
|
|
async function showConfigModal() {
|
|
const modal = document.getElementById('config-modal');
|
|
|
|
try {
|
|
// Load current status
|
|
const response = await AniWorld.ApiClient.get(API.ANIME_STATUS);
|
|
if (!response) return;
|
|
const data = await response.json();
|
|
|
|
document.getElementById('anime-directory-input').value = data.directory || '';
|
|
document.getElementById('series-count-input').value = data.series_count || '0';
|
|
|
|
// Load all configuration sections
|
|
await AniWorld.SchedulerConfig.load();
|
|
await AniWorld.LoggingConfig.load();
|
|
await AniWorld.AdvancedConfig.load();
|
|
await AniWorld.NFOConfig.load();
|
|
|
|
modal.classList.remove('hidden');
|
|
} catch (error) {
|
|
console.error('Error loading configuration:', error);
|
|
AniWorld.UI.showToast('Failed to load configuration', 'error');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hide the configuration modal
|
|
*/
|
|
function hideConfigModal() {
|
|
document.getElementById('config-modal').classList.add('hidden');
|
|
}
|
|
|
|
/**
|
|
* Hide status panel
|
|
*/
|
|
function hideStatus() {
|
|
document.getElementById('status-panel').classList.add('hidden');
|
|
}
|
|
|
|
// Public API
|
|
return {
|
|
init: init,
|
|
showConfigModal: showConfigModal,
|
|
hideConfigModal: hideConfigModal,
|
|
hideStatus: hideStatus
|
|
};
|
|
})();
|