feat: Add NFO configuration settings (Task 7)
- 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)
This commit is contained in:
@@ -54,6 +54,43 @@ class LoggingConfig(BaseModel):
|
||||
return lvl
|
||||
|
||||
|
||||
class NFOConfig(BaseModel):
|
||||
"""NFO metadata configuration."""
|
||||
|
||||
tmdb_api_key: Optional[str] = Field(
|
||||
default=None, description="TMDB API key for metadata scraping"
|
||||
)
|
||||
auto_create: bool = Field(
|
||||
default=False, description="Auto-create NFO files for new series"
|
||||
)
|
||||
update_on_scan: bool = Field(
|
||||
default=False, description="Update existing NFO files on rescan"
|
||||
)
|
||||
download_poster: bool = Field(
|
||||
default=True, description="Download poster.jpg"
|
||||
)
|
||||
download_logo: bool = Field(
|
||||
default=True, description="Download logo.png"
|
||||
)
|
||||
download_fanart: bool = Field(
|
||||
default=True, description="Download fanart.jpg"
|
||||
)
|
||||
image_size: str = Field(
|
||||
default="original", description="Image size (original or w500)"
|
||||
)
|
||||
|
||||
@field_validator("image_size")
|
||||
@classmethod
|
||||
def validate_image_size(cls, v: str) -> str:
|
||||
allowed = {"original", "w500"}
|
||||
size = (v or "").lower()
|
||||
if size not in allowed:
|
||||
raise ValueError(
|
||||
f"invalid image size: {v}. Must be 'original' or 'w500'"
|
||||
)
|
||||
return size
|
||||
|
||||
|
||||
class ValidationResult(BaseModel):
|
||||
"""Result of a configuration validation attempt."""
|
||||
|
||||
@@ -77,6 +114,7 @@ class AppConfig(BaseModel):
|
||||
)
|
||||
logging: LoggingConfig = Field(default_factory=LoggingConfig)
|
||||
backup: BackupConfig = Field(default_factory=BackupConfig)
|
||||
nfo: NFOConfig = Field(default_factory=NFOConfig)
|
||||
other: Dict[str, object] = Field(
|
||||
default_factory=dict, description="Arbitrary other settings"
|
||||
)
|
||||
@@ -114,6 +152,7 @@ class ConfigUpdate(BaseModel):
|
||||
scheduler: Optional[SchedulerConfig] = None
|
||||
logging: Optional[LoggingConfig] = None
|
||||
backup: Optional[BackupConfig] = None
|
||||
nfo: Optional[NFOConfig] = None
|
||||
other: Optional[Dict[str, object]] = None
|
||||
|
||||
def apply_to(self, current: AppConfig) -> AppConfig:
|
||||
@@ -128,6 +167,8 @@ class ConfigUpdate(BaseModel):
|
||||
data["logging"] = self.logging.model_dump()
|
||||
if self.backup is not None:
|
||||
data["backup"] = self.backup.model_dump()
|
||||
if self.nfo is not None:
|
||||
data["nfo"] = self.nfo.model_dump()
|
||||
if self.other is not None:
|
||||
merged = dict(current.other or {})
|
||||
merged.update(self.other)
|
||||
|
||||
Reference in New Issue
Block a user