fix(delete): prune in-memory SerieList cache after delete

delete_series() removed the row from the database and the folder
from disk, but never evicted the entry from SerieList.keyDict — the
in-memory cache that list_series_with_filters() reads from via
SeriesApp.list.GetList(). As a result /api/anime kept returning the
deleted series on every page reload (the 'Beyblade Burst still listed
after delete' bug).

Changes:
* Add SerieList.remove(key) so the cache has a proper eviction API.
* In delete_series(), call it (or fall back to keyDict.pop) after a
  successful DB delete.
* Broadcast a broader series_list_changed event so any client that
  missed the specific series_deleted event can re-sync by re-fetching
  /api/anime. Front-end: new SERIES_LIST_CHANGED constant, handler
  that triggers SeriesManager.reloadSeries().
* Two new regression tests: one asserting the in-memory cache is
  pruned, one asserting the broader broadcast fires.
This commit is contained in:
2026-09-04 20:16:31 +02:00
parent 62b4ca5ffc
commit 35a733d36f
7 changed files with 249 additions and 3 deletions

View File

@@ -584,6 +584,17 @@ AniWorld.SeriesManager = (function() {
}
}
/**
* Re-fetch the series list from the server. Used as a durable
* backstop when receiving the broader series_list_changed WS event
* so local state cannot drift from the server's in-memory cache.
* @returns {Promise<void>}
*/
function reloadSeries() {
console.info('[SeriesManager] Reloading series from server');
return loadSeries();
}
// Public API
return {
init: init,
@@ -596,6 +607,7 @@ AniWorld.SeriesManager = (function() {
updateSeriesLoadingStatus: updateSeriesLoadingStatus,
updateSingleSeries: updateSingleSeries,
updateSeriesKey: updateSeriesKey,
removeSeries: removeSeries
removeSeries: removeSeries,
reloadSeries: reloadSeries
};
})();

View File

@@ -169,6 +169,17 @@ AniWorld.IndexSocketHandler = (function() {
}
});
// Series list membership changed (delete, bulk import, rescan, …).
// Re-fetch /api/anime so local state cannot drift from the server's
// in-memory cache. Acts as a durable backstop when the more specific
// series_deleted event does not reach the client.
socket.on(WS_EVENTS.SERIES_LIST_CHANGED, function(data) {
console.info('[SocketHandler] Series list changed:', data);
if (AniWorld.SeriesManager && AniWorld.SeriesManager.reloadSeries) {
AniWorld.SeriesManager.reloadSeries();
}
});
// Download events
socket.on(WS_EVENTS.DOWNLOAD_STARTED, function(data) {
isDownloading = true;

View File

@@ -105,6 +105,10 @@ AniWorld.Constants = (function() {
SERIES_UPDATED: 'series_updated',
SERIES_LOADING_UPDATE: 'series_loading_update',
SERIES_DELETED: 'series_deleted',
// Fires when the membership of the series list changes (delete,
// bulk import, rescan completion, …). Clients should re-fetch
// /api/anime to resync with the server's in-memory cache.
SERIES_LIST_CHANGED: 'series_list_changed',
// Scheduled scan events
SCHEDULED_RESCAN_STARTED: 'scheduled_rescan_started',