fix: downloaded episodes no longer appear as missing

Use the database as the authoritative source for missing-episode lists so
that episodes marked is_downloaded=True are never shown as missing, even
when the in-memory state is stale.

Key changes:
- EpisodeService.get_by_series() gains only_missing flag
- AnimeService uses DB-backed episodeDict and preserves downloaded episodes
  during sync, skipping them when adding/removing missing episodes
- DownloadService broadcasts series_updated after marking an episode downloaded
  so the frontend reflects the change immediately
- Frontend filters out series with zero missing episodes client-side and
  fixes renderSeries to respect the active filter
- Unit tests updated to assert the broadcast is sent
This commit is contained in:
2026-05-25 21:30:31 +02:00
parent a336733ea9
commit 9a81b04b65
5 changed files with 161 additions and 18 deletions

View File

@@ -203,6 +203,17 @@ AniWorld.SeriesManager = (function() {
function applyFiltersAndSort() {
let filtered = seriesData.slice();
// Apply client-side filter so that real-time WebSocket updates
// (e.g. an episode being marked downloaded) are immediately
// reflected without a full server reload.
if (filterMode === 'missing_episodes') {
filtered = filtered.filter(function(s) {
return s.missing_episodes > 0;
});
}
// 'no_episodes' filter state is maintained server-side;
// don't try to replicate it client-side here.
// Sort based on the current sorting mode
filtered.sort(function(a, b) {
if (sortAlphabetical) {
@@ -233,8 +244,12 @@ AniWorld.SeriesManager = (function() {
*/
function renderSeries() {
const grid = document.getElementById('series-grid');
const dataToRender = filteredSeriesData.length > 0 ? filteredSeriesData :
(seriesData.length > 0 ? seriesData : []);
// Always use filteredSeriesData — applyFiltersAndSort() is always
// called before renderSeries(), so filteredSeriesData is current.
// The old fallback to seriesData was incorrect: when a filter is
// active and filteredSeriesData is empty it must show the empty-state
// message, not fall through to unfiltered seriesData.
const dataToRender = filteredSeriesData;
if (dataToRender.length === 0) {
let message;