better db model

This commit is contained in:
2025-12-04 19:22:42 +01:00
parent 942f14f746
commit 798461a1ea
18 changed files with 551 additions and 2161 deletions

View File

@@ -540,7 +540,7 @@ class SerieScanner:
Save or update a series in the database.
Creates a new record if the series doesn't exist, or updates
the episode_dict if it has changed.
the episodes if they have changed.
Args:
serie: Serie instance to save
@@ -549,26 +549,53 @@ class SerieScanner:
Returns:
Created or updated AnimeSeries instance, or None if unchanged
"""
from src.server.database.service import AnimeSeriesService
from src.server.database.service import AnimeSeriesService, EpisodeService
# Check if series already exists
existing = await AnimeSeriesService.get_by_key(db, serie.key)
if existing:
# Update episode_dict if changed
if existing.episode_dict != serie.episodeDict:
updated = await AnimeSeriesService.update(
db,
existing.id,
episode_dict=serie.episodeDict,
folder=serie.folder
)
# Build existing episode dict from episodes for comparison
existing_episodes = await EpisodeService.get_by_series(
db, existing.id
)
existing_dict: dict[int, list[int]] = {}
for ep in existing_episodes:
if ep.season not in existing_dict:
existing_dict[ep.season] = []
existing_dict[ep.season].append(ep.episode_number)
for season in existing_dict:
existing_dict[season].sort()
# Update episodes if changed
if existing_dict != serie.episodeDict:
# Add new episodes
new_dict = serie.episodeDict or {}
for season, episode_numbers in new_dict.items():
existing_eps = set(existing_dict.get(season, []))
for ep_num in episode_numbers:
if ep_num not in existing_eps:
await EpisodeService.create(
db=db,
series_id=existing.id,
season=season,
episode_number=ep_num,
)
# Update folder if changed
if existing.folder != serie.folder:
await AnimeSeriesService.update(
db,
existing.id,
folder=serie.folder
)
logger.info(
"Updated series in database: %s (key=%s)",
serie.name,
serie.key
)
return updated
return existing
else:
logger.debug(
"Series unchanged in database: %s (key=%s)",
@@ -584,8 +611,19 @@ class SerieScanner:
name=serie.name,
site=serie.site,
folder=serie.folder,
episode_dict=serie.episodeDict,
)
# Create Episode records
if serie.episodeDict:
for season, episode_numbers in serie.episodeDict.items():
for ep_num in episode_numbers:
await EpisodeService.create(
db=db,
series_id=anime_series.id,
season=season,
episode_number=ep_num,
)
logger.info(
"Created series in database: %s (key=%s)",
serie.name,
@@ -608,7 +646,7 @@ class SerieScanner:
Returns:
Updated AnimeSeries instance, or None if not found
"""
from src.server.database.service import AnimeSeriesService
from src.server.database.service import AnimeSeriesService, EpisodeService
existing = await AnimeSeriesService.get_by_key(db, serie.key)
if not existing:
@@ -619,20 +657,43 @@ class SerieScanner:
)
return None
updated = await AnimeSeriesService.update(
# Update basic fields
await AnimeSeriesService.update(
db,
existing.id,
name=serie.name,
site=serie.site,
folder=serie.folder,
episode_dict=serie.episodeDict,
)
# Update episodes - add any new ones
if serie.episodeDict:
existing_episodes = await EpisodeService.get_by_series(
db, existing.id
)
existing_dict: dict[int, set[int]] = {}
for ep in existing_episodes:
if ep.season not in existing_dict:
existing_dict[ep.season] = set()
existing_dict[ep.season].add(ep.episode_number)
for season, episode_numbers in serie.episodeDict.items():
existing_eps = existing_dict.get(season, set())
for ep_num in episode_numbers:
if ep_num not in existing_eps:
await EpisodeService.create(
db=db,
series_id=existing.id,
season=season,
episode_number=ep_num,
)
logger.info(
"Updated series in database: %s (key=%s)",
serie.name,
serie.key
)
return updated
return existing
def __find_mp4_files(self) -> Iterator[tuple[str, list[str]]]:
"""Find all .mp4 files in the directory structure."""

View File

@@ -147,7 +147,7 @@ class SerieList:
if result:
print(f"Added series: {result.name}")
"""
from src.server.database.service import AnimeSeriesService
from src.server.database.service import AnimeSeriesService, EpisodeService
# Check if series already exists in DB
existing = await AnimeSeriesService.get_by_key(db, serie.key)
@@ -166,9 +166,19 @@ class SerieList:
name=serie.name,
site=serie.site,
folder=serie.folder,
episode_dict=serie.episodeDict,
)
# Create Episode records for each episode in episodeDict
if serie.episodeDict:
for season, episode_numbers in serie.episodeDict.items():
for episode_number in episode_numbers:
await EpisodeService.create(
db=db,
series_id=anime_series.id,
season=season,
episode_number=episode_number,
)
# Also add to in-memory collection
self.keyDict[serie.key] = serie
@@ -267,8 +277,10 @@ class SerieList:
# Clear existing in-memory data
self.keyDict.clear()
# Load all series from database
anime_series_list = await AnimeSeriesService.get_all(db)
# Load all series from database (with episodes for episodeDict)
anime_series_list = await AnimeSeriesService.get_all(
db, with_episodes=True
)
for anime_series in anime_series_list:
serie = self._convert_from_db(anime_series)
@@ -288,23 +300,22 @@ class SerieList:
Args:
anime_series: AnimeSeries model from database
(must have episodes relationship loaded)
Returns:
Serie entity instance
"""
# Convert episode_dict from JSON (string keys) to int keys
# Build episode_dict from episodes relationship
episode_dict: dict[int, list[int]] = {}
if anime_series.episode_dict:
for season_str, episodes in anime_series.episode_dict.items():
try:
season = int(season_str)
episode_dict[season] = list(episodes)
except (ValueError, TypeError):
logger.warning(
"Invalid season key '%s' in episode_dict for %s",
season_str,
anime_series.key
)
if anime_series.episodes:
for episode in anime_series.episodes:
season = episode.season
if season not in episode_dict:
episode_dict[season] = []
episode_dict[season].append(episode.episode_number)
# Sort episode numbers within each season
for season in episode_dict:
episode_dict[season].sort()
return Serie(
key=anime_series.key,
@@ -325,19 +336,11 @@ class SerieList:
Returns:
Dictionary suitable for AnimeSeriesService.create()
"""
# Convert episode_dict keys to strings for JSON storage
episode_dict = None
if serie.episodeDict:
episode_dict = {
str(k): list(v) for k, v in serie.episodeDict.items()
}
return {
"key": serie.key,
"name": serie.name,
"site": serie.site,
"folder": serie.folder,
"episode_dict": episode_dict,
}
async def contains_in_db(self, key: str, db: "AsyncSession") -> bool: