fix: Correct series filter logic for no_episodes
Critical bug fix: The filter was returning the wrong series because of a misunderstanding of the episode table semantics. ISSUE: - Episodes table contains MISSING episodes (from episodeDict) - is_downloaded=False means episode file not found in folder - Original query logic was backwards - returned series with NO missing episodes instead of series WITH missing episodes SOLUTION: - Simplified query to directly check for episodes with is_downloaded=False - Changed from complex join with count aggregation to simple subquery - Now correctly returns series that have at least one undownloaded episode CHANGES: - src/server/database/service.py: Rewrote get_series_with_no_episodes() method with corrected logic and clearer documentation - tests/unit/test_series_filter.py: Updated test expectations to match corrected behavior with detailed comments explaining episode semantics - docs/API.md: Enhanced documentation explaining filter behavior and episode table meaning TESTS: All 5 unit tests pass with corrected logic
This commit is contained in:
@@ -337,10 +337,8 @@ async def list_anime(
|
||||
# Get all series from database to fetch NFO metadata
|
||||
# and episode counts
|
||||
from src.server.database.connection import get_sync_session
|
||||
from src.server.database.models import (
|
||||
AnimeSeries as DBAnimeSeries,
|
||||
Episode
|
||||
)
|
||||
from src.server.database.models import AnimeSeries as DBAnimeSeries
|
||||
from src.server.database.models import Episode
|
||||
|
||||
session = get_sync_session()
|
||||
try:
|
||||
|
||||
@@ -26,7 +26,7 @@ import logging
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy import delete, select, update
|
||||
from sqlalchemy import Integer, delete, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
@@ -258,11 +258,15 @@ class AnimeSeriesService:
|
||||
limit: Optional[int] = None,
|
||||
offset: int = 0,
|
||||
) -> List[AnimeSeries]:
|
||||
"""Get anime series that have no downloaded episodes in folder.
|
||||
"""Get anime series that have no episodes found in folder.
|
||||
|
||||
Returns series where either:
|
||||
- No episodes exist in the database, OR
|
||||
- All episodes have is_downloaded=False
|
||||
Since episodes in the database represent MISSING episodes
|
||||
(from episodeDict), this returns series that have episodes
|
||||
in the DB with is_downloaded=False, meaning they have missing
|
||||
episodes and no files were found in the folder for those episodes.
|
||||
|
||||
Returns series where:
|
||||
- At least one episode exists in database with is_downloaded=False
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
@@ -270,31 +274,20 @@ class AnimeSeriesService:
|
||||
offset: Offset for pagination
|
||||
|
||||
Returns:
|
||||
List of AnimeSeries instances with no downloaded episodes
|
||||
List of AnimeSeries with missing episodes (not in folder)
|
||||
"""
|
||||
from sqlalchemy import func, or_
|
||||
|
||||
# Subquery to count downloaded episodes per series
|
||||
downloaded_count = (
|
||||
select(
|
||||
Episode.series_id,
|
||||
func.count(Episode.id).label('downloaded_count')
|
||||
)
|
||||
.where(Episode.is_downloaded.is_(True))
|
||||
.group_by(Episode.series_id)
|
||||
# Subquery to find series IDs with at least one undownloaded episode
|
||||
undownloaded_series_ids = (
|
||||
select(Episode.series_id)
|
||||
.where(Episode.is_downloaded == False)
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# Select series that either have no episodes or no downloaded episodes
|
||||
# Select series that have undownloaded episodes
|
||||
query = (
|
||||
select(AnimeSeries)
|
||||
.outerjoin(downloaded_count, AnimeSeries.id == downloaded_count.c.series_id)
|
||||
.where(
|
||||
or_(
|
||||
downloaded_count.c.downloaded_count == None,
|
||||
downloaded_count.c.downloaded_count == 0
|
||||
)
|
||||
)
|
||||
.where(AnimeSeries.id.in_(select(undownloaded_series_ids.c.series_id)))
|
||||
.order_by(AnimeSeries.name)
|
||||
.offset(offset)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user