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.
|
**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:
|
**Solution:** Updated all NFO-related API calls in the JavaScript modules to:
|
||||||
|
|
||||||
1. Check if response exists (`if (!response)`)
|
1. Check if response exists (`if (!response)`)
|
||||||
2. Parse the JSON response (`const data = await response.json()`)
|
2. Parse the JSON response (`const data = await response.json()`)
|
||||||
3. Access properties on the parsed data object (`data.message`, `data.content`, etc.)
|
3. Access properties on the parsed data object (`data.message`, `data.content`, etc.)
|
||||||
|
|
||||||
**Files Modified:**
|
**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-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()`
|
- [src/server/web/static/js/index/nfo-config.js](../src/server/web/static/js/index/nfo-config.js) - Fixed `load()`, `testTMDBConnection()`
|
||||||
|
|
||||||
**Verification:**
|
**Verification:**
|
||||||
|
|
||||||
- NFO creation now works correctly from the web UI
|
- NFO creation now works correctly from the web UI
|
||||||
- Error messages are properly displayed with details from the API
|
- Error messages are properly displayed with details from the API
|
||||||
- All NFO operations (create, refresh, view) function as expected
|
- All NFO operations (create, refresh, view) function as expected
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -6,6 +7,8 @@ from typing import Optional
|
|||||||
|
|
||||||
from src.server.utils.filesystem import sanitize_folder_name
|
from src.server.utils.filesystem import sanitize_folder_name
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Serie:
|
class Serie:
|
||||||
"""
|
"""
|
||||||
@@ -290,6 +293,36 @@ class Serie:
|
|||||||
# Fallback to key if name cannot be sanitized
|
# Fallback to key if name cannot be sanitized
|
||||||
return sanitize_folder_name(self._key)
|
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):
|
def to_dict(self):
|
||||||
"""Convert Serie object to dictionary for JSON serialization."""
|
"""Convert Serie object to dictionary for JSON serialization."""
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ async def check_nfo(
|
|||||||
detail=f"Series not found: {serie_id}"
|
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
|
# Check NFO
|
||||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
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}"
|
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
|
# Check if NFO already exists
|
||||||
if not request.overwrite_existing:
|
if not request.overwrite_existing:
|
||||||
@@ -217,7 +222,7 @@ async def create_nfo(
|
|||||||
nfo_path = await nfo_service.create_tvshow_nfo(
|
nfo_path = await nfo_service.create_tvshow_nfo(
|
||||||
serie_name=serie_name,
|
serie_name=serie_name,
|
||||||
serie_folder=serie_folder,
|
serie_folder=serie_folder,
|
||||||
year=request.year,
|
year=year,
|
||||||
download_poster=request.download_poster,
|
download_poster=request.download_poster,
|
||||||
download_logo=request.download_logo,
|
download_logo=request.download_logo,
|
||||||
download_fanart=request.download_fanart
|
download_fanart=request.download_fanart
|
||||||
@@ -290,7 +295,8 @@ async def update_nfo(
|
|||||||
detail=f"Series not found: {serie_id}"
|
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
|
# Check if NFO exists
|
||||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
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}"
|
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
|
# Check if NFO exists
|
||||||
nfo_path = (
|
nfo_path = (
|
||||||
@@ -494,7 +501,8 @@ async def download_media(
|
|||||||
detail=f"Series not found: {serie_id}"
|
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)
|
# Check if NFO exists (needed for TMDB ID)
|
||||||
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
||||||
@@ -575,7 +583,8 @@ async def batch_create_nfo(
|
|||||||
message="Series not found"
|
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
|
# Check if NFO exists
|
||||||
if request.skip_existing:
|
if request.skip_existing:
|
||||||
@@ -664,7 +673,8 @@ async def get_missing_nfo(
|
|||||||
if not serie_id:
|
if not serie_id:
|
||||||
continue
|
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)
|
has_nfo = await nfo_service.check_nfo_exists(serie_folder)
|
||||||
|
|
||||||
if not has_nfo:
|
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