fix: support missing/no-episodes library filters (API, UI, docs, tests)

This commit is contained in:
2026-03-16 21:01:59 +01:00
parent e44a8190d0
commit 151a08e033
8 changed files with 227 additions and 99 deletions

View File

@@ -16,7 +16,7 @@ AniWorld.SeriesManager = (function() {
// State
let seriesData = [];
let filteredSeriesData = [];
let showMissingOnly = false;
let filterMode = 'all'; // 'all' | 'missing_episodes' | 'no_episodes'
let sortAlphabetical = false;
/**
@@ -24,15 +24,16 @@ AniWorld.SeriesManager = (function() {
*/
function init() {
bindEvents();
updateFilterButtonUI();
}
/**
* Bind UI events for filtering and sorting
*/
function bindEvents() {
const missingOnlyBtn = document.getElementById('show-missing-only');
if (missingOnlyBtn) {
missingOnlyBtn.addEventListener('click', toggleMissingOnlyFilter);
const filterBtn = document.getElementById('show-missing-only');
if (filterBtn) {
filterBtn.addEventListener('click', toggleFilterMode);
}
const sortBtn = document.getElementById('sort-alphabetical');
@@ -49,7 +50,10 @@ AniWorld.SeriesManager = (function() {
try {
AniWorld.UI.showLoading();
const response = await AniWorld.ApiClient.get(API.ANIME_LIST);
const url = filterMode && filterMode !== 'all'
? `${API.ANIME_LIST}?filter=${encodeURIComponent(filterMode)}`
: API.ANIME_LIST;
const response = await AniWorld.ApiClient.get(url);
if (!response) {
return [];
@@ -111,28 +115,28 @@ AniWorld.SeriesManager = (function() {
}
/**
* Toggle missing episodes only filter
* Cycle through filter modes:
* - all: Show all series
* - missing_episodes: Show only series with missing episodes
* - no_episodes: Show only series with zero downloaded episodes
*/
function toggleMissingOnlyFilter() {
showMissingOnly = !showMissingOnly;
async function toggleFilterMode() {
const button = document.getElementById('show-missing-only');
button.setAttribute('data-active', showMissingOnly);
button.classList.toggle('active', showMissingOnly);
const icon = button.querySelector('i');
const text = button.querySelector('span');
if (showMissingOnly) {
icon.className = 'fas fa-filter-circle-xmark';
text.textContent = 'Show All Series';
// Cycle through modes
if (filterMode === 'all') {
filterMode = 'missing_episodes';
} else if (filterMode === 'missing_episodes') {
filterMode = 'no_episodes';
} else {
icon.className = 'fas fa-filter';
text.textContent = 'Missing Episodes Only';
filterMode = 'all';
}
applyFiltersAndSort();
renderSeries();
// Update button UI and reload list based on new filter.
updateFilterButtonUI();
await loadSeries();
// Clear selection when filter changes
if (AniWorld.SelectionManager) {
@@ -140,6 +144,34 @@ AniWorld.SeriesManager = (function() {
}
}
/**
* Update the filter button UI to reflect current filter mode
*/
function updateFilterButtonUI() {
const button = document.getElementById('show-missing-only');
if (!button) {
return;
}
const icon = button.querySelector('i');
const text = button.querySelector('span');
const isActive = filterMode !== 'all';
button.setAttribute('data-active', isActive);
button.classList.toggle('active', isActive);
if (filterMode === 'missing_episodes') {
icon.className = 'fas fa-filter';
text.textContent = 'Missing Episodes Only';
} else if (filterMode === 'no_episodes') {
icon.className = 'fas fa-ban';
text.textContent = 'No Episodes';
} else {
icon.className = 'fas fa-filter-circle-xmark';
text.textContent = 'Show All Series';
}
}
/**
* Toggle alphabetical sorting
*/
@@ -193,13 +225,6 @@ AniWorld.SeriesManager = (function() {
}
});
// Apply missing episodes filter
if (showMissingOnly) {
filtered = filtered.filter(function(serie) {
return serie.missing_episodes > 0;
});
}
filteredSeriesData = filtered;
}
@@ -212,9 +237,14 @@ AniWorld.SeriesManager = (function() {
(seriesData.length > 0 ? seriesData : []);
if (dataToRender.length === 0) {
const message = showMissingOnly ?
'No series with missing episodes found.' :
'No series found. Try searching for anime or rescanning your directory.';
let message;
if (filterMode === 'missing_episodes') {
message = 'No series with missing episodes found.';
} else if (filterMode === 'no_episodes') {
message = 'No series with zero downloaded episodes found.';
} else {
message = 'No series found. Try searching for anime or rescanning your directory.';
}
grid.innerHTML =
'<div class="text-center" style="grid-column: 1 / -1; padding: 2rem;">' +