Fix NFO folder naming to include year
- Add Serie.ensure_folder_with_year() method to ensure folder names include year - Update all NFO API endpoints to call ensure_folder_with_year() before operations - Folder format is now 'Name (Year)' when year is available - Add comprehensive tests for ensure_folder_with_year() method - All 5 tests passing
This commit is contained in:
@@ -130,15 +130,18 @@ All tasks completed! Recent issues have been resolved.
|
||||
**Root Cause:** The `AniWorld.ApiClient.request()` function returns a native `Response` object from the Fetch API, not the parsed JSON data. The code was attempting to access properties like `response.message` and `response.content` directly without first calling `response.json()` to parse the response body.
|
||||
|
||||
**Solution:** Updated all NFO-related API calls in the JavaScript modules to:
|
||||
|
||||
1. Check if response exists (`if (!response)`)
|
||||
2. Parse the JSON response (`const data = await response.json()`)
|
||||
3. Access properties on the parsed data object (`data.message`, `data.content`, etc.)
|
||||
|
||||
**Files Modified:**
|
||||
|
||||
- [src/server/web/static/js/index/nfo-manager.js](../src/server/web/static/js/index/nfo-manager.js) - Fixed `createNFO()`, `refreshNFO()`, `viewNFO()`, `getSeriesWithoutNFO()`
|
||||
- [src/server/web/static/js/index/nfo-config.js](../src/server/web/static/js/index/nfo-config.js) - Fixed `load()`, `testTMDBConnection()`
|
||||
|
||||
**Verification:**
|
||||
|
||||
- NFO creation now works correctly from the web UI
|
||||
- Error messages are properly displayed with details from the API
|
||||
- All NFO operations (create, refresh, view) function as expected
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
@@ -6,6 +7,8 @@ from typing import Optional
|
||||
|
||||
from src.server.utils.filesystem import sanitize_folder_name
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Serie:
|
||||
"""
|
||||
@@ -290,6 +293,36 @@ class Serie:
|
||||
# Fallback to key if name cannot be sanitized
|
||||
return sanitize_folder_name(self._key)
|
||||
|
||||
def ensure_folder_with_year(self) -> str:
|
||||
"""Ensure folder name includes year if available.
|
||||
|
||||
If the serie has a year and the current folder name doesn't include it,
|
||||
updates the folder name to include the year in format "Name (Year)".
|
||||
|
||||
This method should be called before creating folders or NFO files to
|
||||
ensure consistent naming across the application.
|
||||
|
||||
Returns:
|
||||
str: The folder name (updated if needed)
|
||||
|
||||
Example:
|
||||
>>> serie = Serie("perfect-blue", "Perfect Blue", ..., folder="Perfect Blue", year=1997)
|
||||
>>> serie.ensure_folder_with_year()
|
||||
'Perfect Blue (1997)'
|
||||
>>> serie.folder # folder property is updated
|
||||
'Perfect Blue (1997)'
|
||||
"""
|
||||
if self._year:
|
||||
# Check if folder already has year format
|
||||
year_pattern = f"({self._year})"
|
||||
if year_pattern not in self._folder:
|
||||
# Update folder to include year
|
||||
self._folder = self.sanitized_folder
|
||||
logger.info(
|
||||
f"Updated folder name for '{self._key}' to include year: {self._folder}"
|
||||
)
|
||||
return self._folder
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert Serie object to dictionary for JSON serialization."""
|
||||
return {
|
||||
|
||||
@@ -133,7 +133,8 @@ async def check_nfo(
|
||||
detail=f"Series not found: {serie_id}"
|
||||
)
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
|
||||
# Check NFO
|
||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
||||
@@ -201,7 +202,11 @@ async def create_nfo(
|
||||
detail=f"Series not found: {serie_id}"
|
||||
)
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
|
||||
# If year not provided in request but serie has year, use it
|
||||
year = request.year or serie.year
|
||||
|
||||
# Check if NFO already exists
|
||||
if not request.overwrite_existing:
|
||||
@@ -217,7 +222,7 @@ async def create_nfo(
|
||||
nfo_path = await nfo_service.create_tvshow_nfo(
|
||||
serie_name=serie_name,
|
||||
serie_folder=serie_folder,
|
||||
year=request.year,
|
||||
year=year,
|
||||
download_poster=request.download_poster,
|
||||
download_logo=request.download_logo,
|
||||
download_fanart=request.download_fanart
|
||||
@@ -290,7 +295,8 @@ async def update_nfo(
|
||||
detail=f"Series not found: {serie_id}"
|
||||
)
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
|
||||
# Check if NFO exists
|
||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
||||
@@ -371,7 +377,8 @@ async def get_nfo_content(
|
||||
detail=f"Series not found: {serie_id}"
|
||||
)
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
|
||||
# Check if NFO exists
|
||||
nfo_path = (
|
||||
@@ -494,7 +501,8 @@ async def download_media(
|
||||
detail=f"Series not found: {serie_id}"
|
||||
)
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
|
||||
# Check if NFO exists (needed for TMDB ID)
|
||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
||||
@@ -575,7 +583,8 @@ async def batch_create_nfo(
|
||||
message="Series not found"
|
||||
)
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
|
||||
# Check if NFO exists
|
||||
if request.skip_existing:
|
||||
@@ -664,7 +673,8 @@ async def get_missing_nfo(
|
||||
if not serie_id:
|
||||
continue
|
||||
|
||||
serie_folder = serie.folder
|
||||
# Ensure folder name includes year if available
|
||||
serie_folder = serie.ensure_folder_with_year()
|
||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
||||
|
||||
if not has_nfo:
|
||||
|
||||
94
tests/unit/test_serie_folder_with_year.py
Normal file
94
tests/unit/test_serie_folder_with_year.py
Normal file
@@ -0,0 +1,94 @@
|
||||
"""Tests for Serie.ensure_folder_with_year() method."""
|
||||
|
||||
import pytest
|
||||
from src.core.entities.series import Serie
|
||||
|
||||
|
||||
class TestSerieEnsureFolderWithYear:
|
||||
"""Test suite for ensure_folder_with_year method."""
|
||||
|
||||
def test_ensure_folder_with_year_adds_year(self):
|
||||
"""Test that ensure_folder_with_year adds year to folder name."""
|
||||
serie = Serie(
|
||||
key="perfect-blue",
|
||||
name="Perfect Blue",
|
||||
site="aniworld.to",
|
||||
folder="Perfect Blue",
|
||||
episodeDict={1: [1, 2, 3]},
|
||||
year=1997
|
||||
)
|
||||
|
||||
result = serie.ensure_folder_with_year()
|
||||
|
||||
assert result == "Perfect Blue (1997)"
|
||||
assert serie.folder == "Perfect Blue (1997)"
|
||||
|
||||
def test_ensure_folder_with_year_already_has_year(self):
|
||||
"""Test that ensure_folder_with_year doesn't duplicate year."""
|
||||
serie = Serie(
|
||||
key="blue-exorcist",
|
||||
name="Blue Exorcist",
|
||||
site="aniworld.to",
|
||||
folder="Blue Exorcist (2011)",
|
||||
episodeDict={1: [1, 2, 3]},
|
||||
year=2011
|
||||
)
|
||||
|
||||
result = serie.ensure_folder_with_year()
|
||||
|
||||
assert result == "Blue Exorcist (2011)"
|
||||
assert serie.folder == "Blue Exorcist (2011)"
|
||||
|
||||
def test_ensure_folder_with_year_no_year_available(self):
|
||||
"""Test that ensure_folder_with_year returns folder unchanged if no year."""
|
||||
serie = Serie(
|
||||
key="unknown-anime",
|
||||
name="Unknown Anime",
|
||||
site="aniworld.to",
|
||||
folder="Unknown Anime",
|
||||
episodeDict={1: [1, 2, 3]},
|
||||
year=None
|
||||
)
|
||||
|
||||
result = serie.ensure_folder_with_year()
|
||||
|
||||
assert result == "Unknown Anime"
|
||||
assert serie.folder == "Unknown Anime"
|
||||
|
||||
def test_ensure_folder_with_year_sanitizes_name(self):
|
||||
"""Test that ensure_folder_with_year uses sanitized_folder property."""
|
||||
serie = Serie(
|
||||
key="attack-on-titan",
|
||||
name="Attack on Titan: Final Season",
|
||||
site="aniworld.to",
|
||||
folder="Attack on Titan Final", # Old folder without year
|
||||
episodeDict={1: [1, 2, 3]},
|
||||
year=2020
|
||||
)
|
||||
|
||||
result = serie.ensure_folder_with_year()
|
||||
|
||||
# Should use sanitized version of name_with_year
|
||||
assert "(2020)" in result
|
||||
assert serie.folder == result
|
||||
# Colon should be removed by sanitization
|
||||
assert ":" not in result
|
||||
|
||||
def test_ensure_folder_with_year_updates_folder_property(self):
|
||||
"""Test that folder property is updated when year is added."""
|
||||
serie = Serie(
|
||||
key="dororo",
|
||||
name="Dororo",
|
||||
site="aniworld.to",
|
||||
folder="Dororo",
|
||||
episodeDict={1: [1, 2, 3]},
|
||||
year=2019
|
||||
)
|
||||
|
||||
original_folder = serie.folder
|
||||
result = serie.ensure_folder_with_year()
|
||||
|
||||
assert original_folder == "Dororo"
|
||||
assert result == "Dororo (2019)"
|
||||
assert serie.folder == "Dororo (2019)"
|
||||
assert serie.folder != original_folder
|
||||
Reference in New Issue
Block a user