Add year support to anime folder names

- Add year property to Serie entity with name_with_year
- Add year column to AnimeSeries database model
- Add get_year() method to AniworldLoader provider
- Extract year from folder names before fetching from API
- Update SerieScanner to populate year during rescan
- Update add_series endpoint to fetch and store year
- Optimize: check folder name for year before API call
This commit is contained in:
2026-01-11 19:47:47 +01:00
parent ccbd9768a2
commit 40ffb99c97
7 changed files with 241 additions and 28 deletions

View File

@@ -22,6 +22,7 @@ class Serie:
e.g., "Attack on Titan (2013)")
episodeDict: Dictionary mapping season numbers to
lists of episode numbers
year: Release year of the series (optional)
Raises:
ValueError: If key is None or empty string
@@ -33,7 +34,8 @@ class Serie:
name: str,
site: str,
folder: str,
episodeDict: dict[int, list[int]]
episodeDict: dict[int, list[int]],
year: int | None = None
):
if not key or not key.strip():
raise ValueError("Serie key cannot be None or empty")
@@ -43,13 +45,15 @@ class Serie:
self._site = site
self._folder = folder
self._episodeDict = episodeDict
self._year = year
def __str__(self):
"""String representation of Serie object"""
year_str = f", year={self.year}" if self.year else ""
return (
f"Serie(key='{self.key}', name='{self.name}', "
f"site='{self.site}', folder='{self.folder}', "
f"episodeDict={self.episodeDict})"
f"episodeDict={self.episodeDict}{year_str})"
)
@property
@@ -129,29 +133,65 @@ class Serie:
def episodeDict(self, value: dict[int, list[int]]):
self._episodeDict = value
@property
def year(self) -> int | None:
"""
Release year of the series.
Returns:
int or None: The year the series was released, or None if unknown
"""
return self._year
@year.setter
def year(self, value: int | None):
"""Set the release year of the series."""
self._year = value
@property
def name_with_year(self) -> str:
"""
Get the series name with year appended if available.
Returns a name in the format "Name (Year)" if year is available,
otherwise returns just the name. This should be used for creating
filesystem folders to distinguish series with the same name.
Returns:
str: Name with year in format "Name (Year)", or just name if no year
Example:
>>> serie = Serie("dororo", "Dororo", ..., year=2025)
>>> serie.name_with_year
'Dororo (2025)'
"""
if self._year:
return f"{self._name} ({self._year})"
return self._name
@property
def sanitized_folder(self) -> str:
"""
Get a filesystem-safe folder name derived from the display name.
Get a filesystem-safe folder name derived from the display name with year.
This property returns a sanitized version of the series name
suitable for use as a filesystem folder name. It removes/replaces
characters that are invalid for filesystems while preserving
This property returns a sanitized version of the series name with year
(if available) suitable for use as a filesystem folder name. It removes/
replaces characters that are invalid for filesystems while preserving
Unicode characters.
Use this property when creating folders for the series on disk.
The `folder` property stores the actual folder name used.
Returns:
str: Filesystem-safe folder name based on display name
str: Filesystem-safe folder name based on display name with year
Example:
>>> serie = Serie("attack-on-titan", "Attack on Titan: Final", ...)
>>> serie = Serie("attack-on-titan", "Attack on Titan: Final", ..., year=2025)
>>> serie.sanitized_folder
'Attack on Titan Final'
'Attack on Titan Final (2025)'
"""
# Use name if available, fall back to folder, then key
name_to_sanitize = self._name or self._folder or self._key
# Use name_with_year if available, fall back to folder, then key
name_to_sanitize = self.name_with_year or self._folder or self._key
try:
return sanitize_folder_name(name_to_sanitize)
except ValueError:
@@ -167,7 +207,8 @@ class Serie:
"folder": self.folder,
"episodeDict": {
str(k): list(v) for k, v in self.episodeDict.items()
}
},
"year": self.year
}
@staticmethod
@@ -182,7 +223,8 @@ class Serie:
data["name"],
data["site"],
data["folder"],
episode_dict
episode_dict,
data.get("year") # Optional year field for backward compatibility
)
def save_to_file(self, filename: str):