feat: add anime metadata editing and NFO diagnostics

- Add PUT /anime/{key} endpoint for updating anime key, tmdb_id, tvdb_id
- Add NFO diagnostics and repair endpoints (GET/POST /nfo/diagnostics)
- Add edit modal UI with context menu integration
- Add frontend JS modules for context-menu and edit-modal
- Add comprehensive tests for edit, rename, and NFO repair flows
This commit is contained in:
2026-05-31 18:31:56 +02:00
parent 5517ccbab0
commit 6021cdef28
14 changed files with 1988 additions and 1 deletions

View File

@@ -83,6 +83,30 @@ class AnimeSeriesResponse(BaseModel):
return v
class AnimeMetadataUpdate(BaseModel):
"""Request model for updating anime metadata (key, tmdb_id, tvdb_id)."""
key: Optional[str] = Field(None, description="New series key (URL-safe, lowercase)")
tmdb_id: Optional[int] = Field(None, ge=1, description="TMDB ID (positive integer)")
tvdb_id: Optional[int] = Field(None, ge=1, description="TVDB ID (positive integer)")
@field_validator('key', mode='before')
@classmethod
def validate_key_format(cls, v: Optional[str]) -> Optional[str]:
"""Validate key is URL-safe lowercase with hyphens only."""
if v is None:
return v
v = v.strip().lower()
if not v:
raise ValueError("Key cannot be empty")
if not KEY_PATTERN.match(v):
raise ValueError(
"Key must contain only lowercase letters, numbers, and hyphens. "
"Cannot start or end with a hyphen."
)
return v
class SearchRequest(BaseModel):
"""Request payload for searching series."""

View File

@@ -355,3 +355,29 @@ class NFOMissingResponse(BaseModel):
...,
description="List of series missing NFO"
)
class NfoDiagnosticsResponse(BaseModel):
"""Response for NFO diagnostics showing missing required tags."""
has_nfo: bool = Field(..., description="Whether tvshow.nfo exists")
nfo_path: Optional[str] = Field(None, description="Path to NFO file if exists")
missing_tags: List[str] = Field(
default_factory=list,
description="List of missing required tag names"
)
required_tags: List[str] = Field(
default_factory=list,
description="All required tag names for reference"
)
class NfoRepairResponse(BaseModel):
"""Response after NFO repair attempt."""
success: bool = Field(..., description="Whether repair succeeded")
message: str = Field(..., description="Human-readable result message")
repaired_tags: List[str] = Field(
default_factory=list,
description="Tags that were missing before repair"
)