Files
Aniworld/Docs/DELETE_ANIME_FEATURE.md
2026-08-16 19:53:38 +02:00

6.3 KiB

Delete Anime Feature

Overview

The Delete Anime feature allows authenticated users to remove an anime series from the Aniworld library. It supports three deletion modes: database only, folder only, or both. A mandatory typed-confirmation (delete) prevents accidental deletions.


Usage

How to Delete an Anime

  1. Right-click on any anime series card in the library grid.
  2. Select "Delete Anime" from the context menu.
  3. A confirmation modal appears with two options:
    • ☑️ Remove from database (recommended) — removes series and episodes from SQLite
    • Delete folder from filesystem — deletes the folder and all files inside
  4. Type delete in the confirmation text field to enable the Delete button.
  5. Click Delete to proceed.

What Gets Deleted

Option Effect
Database only Series, episodes, and queue entries removed from SQLite. Folder on disk is preserved. Downloaded episode files remain.
Folder only Entire folder and all files inside deleted from filesystem. Database record preserved with is_downloaded=True.
Both Full removal: database record deleted AND folder/files deleted from disk.

Architecture

Backend Components

File Role
src/server/api/anime.py DELETE /api/anime/{key} endpoint
src/server/services/anime_service.py AnimeService.delete_series() orchestrator
src/server/services/websocket_service.py broadcast_series_deleted() for real-time UI updates
src/server/database/service.py AnimeSeriesService.get_folder_path() + existing delete()
src/server/models/anime.py DeleteSeriesRequest / DeleteSeriesResult Pydantic models

Frontend Components

File Role
src/server/web/static/js/index/delete-modal.js Modal UI, confirm text validation, API calls
src/server/web/static/js/index/context-menu.js Right-click "Delete Anime" menu item
src/server/web/static/js/index/socket-handler.js SERIES_DELETED WebSocket event handler
src/server/web/static/js/index/series-manager.js removeSeries(key) — removes card from grid
src/server/web/static/js/index/app-init.js Initializes DeleteModal
src/server/web/static/css/components/modals.css Modal and context menu styles
src/server/web/templates/index.html Loads delete-modal.js before app-init.js

API Endpoint

DELETE /api/anime/{key}

Request body:

{
    "delete_database": true,
    "delete_folder": false,
    "confirm_text": "delete"
}

Success response (200):

{
    "success": true,
    "key": "attack-on-titan",
    "name": "Attack on Titan",
    "deleted_from_database": true,
    "deleted_folder": false,
    "folder_path": null,
    "database_error": null,
    "folder_error": null,
    "message": "Removed from database."
}

Error responses:

Status Condition
400 confirm_text != "delete" or neither flag is true
401 Not authenticated
404 Series key not found in database
500 Unexpected server error

WebSocket Event

After a successful delete, the server broadcasts a series_deleted event:

{
    "type": "series_deleted",
    "data": {
        "key": "attack-on-titan",
        "name": "Attack on Titan"
    }
}

All connected clients remove the card from their grid in real-time.


Safety Mechanisms

1. Typed Confirmation

Users must type exactly delete (case-sensitive) to unlock the Delete button. This prevents accidental clicks from triggering deletion.

2. Path Traversal Protection

Before deleting a folder, is_safe_path() validates the path stays within the configured anime base directory. Paths outside this boundary are rejected with a folder_error.

3. Granular Options

The two independent checkboxes ensure users consciously choose what to delete. Default is database only (recommended).

4. WebSocket Broadcast

All clients are notified immediately when a series is deleted, keeping multiple browser sessions in sync.

5. No Shell Injection

Series keys are never passed to shell commands. All file operations use pathlib.Path.


Logging

Backend Logs (Python/logging)

Event Level Message
Delete initiated INFO Delete anime initiated: key={key} delete_db={x} delete_folder={x}
Series not found WARNING Delete anime failed — series not found: key={key}
Path traversal attempt WARNING Delete anime blocked — path traversal attempt: key={key} path={path}
DB error ERROR Delete anime DB error: key={key} error={message}
Folder delete error ERROR Delete anime folder error: key={key} error={message}
Delete succeeded INFO Delete anime succeeded: key={key} deleted_db={x} deleted_folder={x}

Frontend Logs (JS/console)

Event Method
Modal opened console.info('[DeleteModal] Opening for key:', key)
Delete confirmed console.info('[DeleteModal] Initiating delete:', {...})
Delete succeeded console.info('[DeleteModal] Delete succeeded:', result)
API/network error console.error('[DeleteModal] Delete request failed:', err)
Series removed from grid console.info('[SeriesManager] Removed series from local state:', key)
WS event received console.info('[SocketHandler] Series deleted:', data)

Configuration

No new configuration options are required. The feature uses existing paths:

  • Anime base directory: settings.anime_directory (for path traversal validation)
  • Database path: series_app.database_path (for DB deletion)
  • Queue cleanup: AnimeSeriesService.delete(series_key) cascades to queue items

Testing

See:

  • tests/unit/test_delete_anime_service.py — unit tests for AnimeService.delete_series()
  • tests/api/test_delete_anime_endpoint.py — API endpoint tests including auth, validation, error cases
  • tests/frontend/test_delete_modal.py — frontend modal logic and DOM validation tests
  • tests/security/test_delete_anime_security.py — security tests for path traversal, XSS, auth bypass

Changelog

Date Change
2026-08-16 Feature added. DELETE /api/anime/{key}, right-click context menu, typed-confirmation modal, WebSocket sync.