Commit Graph

162 Commits

Author SHA1 Message Date
8887f9a7cb fix(nfo): pass anime_service to _create_or_update_nfo in anime endpoints
POST /api/anime/{key}/regenerate-nfo and PUT /api/anime/{key}/settings
(both of which can regenerate NFO when apply_to_nfo=True) were calling
_create_or_update_nfo without the required anime_service argument,
producing HTTP 500 with 'missing 1 required positional argument:
anime_service' on the anime-settings page.

Also drops the unused series_data parameter from
_create_or_update_nfo's signature — the value was constructed at every
call site but never read inside the function body. All four callers
in anime.py and nfo.py are updated to match.
2026-09-04 19:18:39 +02:00
AniWorld Dev
9f52ea03fb fix(anime-settings): restore GET /api/nfo/{key}/content for 'View NFO XML' button
The Anime Settings page (src/server/web/static/js/pages/anime-settings.js)
calls GET /api/nfo/{key}/content from its 'View NFO XML' button, but that
endpoint was removed during the NFO refactor (commits 21af502, a8e5487).
The frontend was never updated, so every click on the button 404'd.

Fix:
- Add NfoContentResponse model (key, folder, content, file_size,
  last_modified) to src/server/models/nfo.py.
- Add GET /api/nfo/{key}/content handler to src/server/api/nfo.py that
  reads <anime_directory>/<folder>/tvshow.nfo and returns it as
  {"content": "<xml>", ...} — matching what anime-settings.js
  viewNfoContent() already expects (data.content).
- Expose viewNfoContent on AniWorld.AnimeSettingsManager so it is
  consistent with the other public methods and directly callable from
  tests / other modules.

Tests:
- tests/api/test_nfo_endpoints.py: 4 new tests (auth-required, happy
  path returning XML, 404 on unknown series, 404 on missing tvshow.nfo).
  Also remove the file-local autouse 'reset_auth' fixture that wiped
  the conftest's master-password setup and made any login-based test
  fail with a stale-hash 'invalid credentials' error — that fixture
  was pre-existing and is a no-op now that conftest.py handles reset.
- tests/frontend/unit/anime_settings.test.js: 3 new tests for
  viewNfoContent (URL + auth header, writes <pre>, error toast on
  404) and an assertion in the public-API surface test.
2026-09-04 19:10:27 +02:00
a7ed2c999c added delete option 2026-08-16 19:53:38 +02:00
5f46d2e802 feat: add folder naming service to fix missing years in anime folder names
Runs after NFO refresh during scheduled rescans. Renames folders that
are missing a year (e.g. 'Naruto' → 'Naruto (1999)') using the year
from the database record.

Safety: _build_target_folder() always strips any existing year suffix
first, preventing double/triple year accumulation like
'Naruto (1999) (1999) (1999)'.

Changes:
- New FolderNamingService (folder_naming_service.py) with safe target
  name construction, DB update, and in-memory cache update
- New SchedulerConfig field: folder_naming_after_nfo_scan (default True)
- Integrated as step 3 in scheduler _perform_rescan() after NFO scan
- Runtime UI: existing 'folder-scan-enabled' checkbox in index.html
  now wired to toggle the feature (app.js + scheduler-config.js)
- Setup screen: new checkbox in setup.html Scheduler Settings section
- API: scheduler config endpoint returns all scan toggles
- Tests: 39 unit tests covering static helpers, rename logic, safety
  guard, and integration cases (folder_naming_service.py)
- Docs: testing guide updated with FolderNamingService examples
2026-07-26 21:45:08 +02:00
a384072901 fix: queue background loading after folder resolve; extract year from NFO 2026-07-26 20:02:02 +02:00
04175a2bd6 fix: update docs and fix multiple Robot test failures
- scheduler.py: fix get_anime_service import, success as string
- download.robot: fix queue endpoint path, retry needs list
- logging.robot: fix JSON path access for config
- nfo.robot: accept 400 when TMDB not configured
- anime_settings.robot: Execute JavaScript -> Evaluate JavaScript
2026-07-02 20:50:32 +02:00
b845744c9d fix: add admin reset endpoint for test isolation
- Add /api/config/admin/reset unauthenticated endpoint for tests
- Add auth_service.reset() to clear in-memory auth state
- Update robot tests to call reset on teardown
- Remove flaky Setup Redirects test (depended on test order)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-28 19:44:28 +02:00
aeffb882dc Allow empty schedule_days; add success flag to rescan endpoint
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-28 16:38:48 +02:00
4687a06374 Refactor trigger_rescan to use anime_service
- Use anime_service.rescan() instead of direct trigger_rescan import
- Change Optional[Any] to Optional[Dict[str, Any]] in ConfigUpdate for better type hints
- Add ValidationError handling in ConfigUpdate.apply_to
- Update tests to match new implementation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-27 15:46:22 +02:00
ad2320dbbb Add NFO scan endpoint and fix scheduler test payload
- Implement /api/nfo/scan endpoint returning scan results
- Fix Robot Framework scheduler test: use Evaluate+json.loads instead of Create Dictionary for nested data
- Remove completed task docs
2026-06-27 15:14:56 +02:00
eea9272de4 Refactor NFO TMDB calls to use tmdb_client
- Replace TMDBProvider with tmdb_client in nfo.py
- Add anime_service param to repair functions
- Add null guard for empty series name lookup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-27 14:57:19 +02:00
c8f0c6fcb1 Make cleanup_logs payload optional; fix duplicate Optional import
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-27 14:43:18 +02:00
c6d787c2c7 Fix log download Content-Type to application/octet-stream
Browser auto-download requires binary MIME type, not text/plain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-27 14:34:11 +02:00
30c0499869 Add level field to logging config response 2026-06-27 14:22:06 +02:00
8b98c6d84e Add uptime field to detailed health check endpoint
- Added uptime field to DetailedHealthStatus model
- Calculate uptime as time since startup
- Removed obsolete task entries from Docs/tasks.md
2026-06-27 14:20:25 +02:00
fd84a18b30 fix config: handle stringified JSON in API requests
ConfigUpdate fields (scheduler, logging, backup, nfo, other) arrive as
strings from frontend. Parse JSON or ast.literal_eval before validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-27 13:56:18 +02:00
6c502e2014 fix: scan episodes synchronously and disable test mode rate limiting
- Always scan missing episodes sync in add_series to avoid race condition
- Add db fallback in get_anime when in-memory episodeDict empty
- Add with_episodes param to AnimeSeriesService.get_by_key
- Disable auth rate limiting and lockout in test mode (ANIWORLD_TESTING=1)
- Simplify responsive.robot tests: fix setup, remove fragile width checks
2026-06-27 13:42:09 +02:00
313bd1ebf3 auth: fix rate limit bypass, improve error messages
- Disable rate limiting when rate_limit_per_minute = 0
- Add IP lockout mention to 429 response
- Lowercase error messages for consistency
- Raise test mode rate limit 100 -> 10 (more realistic)
2026-06-26 20:46:10 +02:00
d00e80e240 simplify queue ops, handle broken pipe errors
- Add OSError errno 32 (broken pipe) handling in progress broadcast
- Remove progress service calls from add/clear queue operations
- Add pending_by_episode cleanup on clear
- Update tests accordingly
2026-06-26 19:50:13 +02:00
5028d4ea27 feat(api): add /resume endpoint for queue processing
Add POST /api/queue/resume endpoint. Alias for start_queue that provides
semantic clarity for resume action after pause/stop.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 18:40:48 +02:00
e7d5df3a90 fix: parse string-encoded JSON in episode fields + return success for empty queue
- Add field validators to parse season/episode/title from JSON strings
- Add episodes list parser handling string-encoded dicts
- Return 200 with message instead of 400 when queue empty
- Remove completed tasks 8+9 from Docs
2026-06-26 18:39:02 +02:00
c6f01ca985 wrap backups list in dict response
Task 4 done: config backup list endpoint now returns {backups: [...]} structure. API contract changed to match expected format.
2026-06-26 17:24:20 +02:00
ea59db302d fix: return 201 on backup create
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 17:13:57 +02:00
a6e103889f fix: resolve race conditions in auth and episode retrieval
- models.py: episodeDict getter now catches DetachedInstanceError when episodes accessed on newly created/synced series
- anime.py: added error logging for failed series detail retrieval
- fastapi_app.py: raise auth rate limit to 100 in test mode (ANIWORLD_TESTING=1) to avoid 429 during rapid test execution
- auth_service.py: skip locked account check in test mode
- robot tests: suite setup now configures auth once, tests verify 'already configured' behavior to avoid re-setup conflicts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 16:57:22 +02:00
572aa0fc78 fix(logging): replace structlog with stdlib logging to prevent broken pipe crashes
structlog fails with BrokenPipeError when stdout is redirected (e.g., background
processes, Docker logs). Replace all structlog.get_logger() calls with
logging.getLogger() and convert keyword-style log calls to %-format strings.

Also removes stale Docs/tasks.md (2028 lines) and updates Robot Framework
tests to match current API behavior.
2026-06-21 20:14:31 +02:00
eabce18e41 feat(anime): rename NFO Diagnostics to Anime Settings + add edit endpoints
Replaces the read-only 'NFO Diagnostics' page with a full per-anime
Settings page reached from the right-click context menu on series cards.
Users can now view and edit key, name, folder, tmdb_id, tvdb_id and site
for each anime; changes are persisted to the DB and optionally written
back to the NFO file or used to regenerate it.

Backend
- Rename NfoDiagnosticsResponse -> NfoSettingsResponse,
  NfoSeriesDiagnostics -> NfoSeriesSettings
- Rename get_nfo_diagnostics -> get_nfo_settings,
  repair_nfo -> repair_nfo_settings
- Fix nfo.py bug: repair was calling non-existent
  update_series_nfo_status(); now uses update_nfo_status() and an
  explicit AnimeSeriesService.update(nfo_path=...)
- New endpoints on /api/anime/{key}:
    GET  /settings            -> AnimeSettingsResponse
    PUT  /settings            -> AnimeSettingsResponse
                                 (body: name/folder/tmdb_id/tvdb_id/site,
                                  options: apply_to_nfo, rename_disk)
    POST /regenerate-nfo      -> AnimeSettingsRegenerateNfoResponse
- New Pydantic models: AnimeSettingsResponse,
  AnimeSettingsUpdateRequest, AnimeSettingsRegenerateNfoResponse
- /anime/settings page route; /settings/nfo now 301-redirects to it

Frontend
- New AniWorld.AnimeSettingsManager JS module (single-page form,
  no tabs) with public API init/loadSeries/saveSettings/regenerateNfo/
  validateField/populateForm/showSaveSuccess/showError
- New anime-settings.html template + anime-settings.css
- Right-click menu: data-action 'nfo-diagnostics' replaced by
  'anime-settings' (label 'Anime Settings'), navigates to
  /anime/settings?key=...
- Library 'Open NFO Diagnostics' link renamed to 'Open Anime Settings'

Bug fix
- context-menu click handler was calling hide() BEFORE building the
  navigation URL, which cleared currentSeriesKey to null and produced
  /anime/settings?key=null. Captures the key into a local const first.
  Regression-locked by tests/frontend/unit/context_menu.test.js.

Tests
- 21 new pytest tests in tests/api/test_anime_settings_endpoints.py
  (GET/PUT/regenerate-nfo, auth, validation, nfo-repair bug regression)
- tests/api/test_nfo_endpoints.py trimmed to 6 focused tests
- 31 new Vitest unit tests for AnimeSettingsManager
- 5 new Vitest unit tests for ContextMenu (incl. source-invariant
  regression guard for the hide()-before-key bug)
- 5 new Playwright E2E tests covering right-click, direct nav,
  legacy /settings/nfo redirect, and context-menu labels
- New vitest.config.js (environment: happy-dom)

Docs
- Docs/API.md: new section 'Anime Settings Endpoints'
- Docs/CHANGELOG.md: documents the rename and the context-menu bug fix

Verified
- pytest: 27/27 (21 new + 6 trimmed nfo)
- vitest: 36/36 (31 anime-settings + 5 context-menu)
- playwright e2e: 5/5
2026-06-21 07:52:22 +02:00
e050f6fa2d refactor: remove Edit Metadata right-click option
Removes the Edit Metadata feature from the anime context menu and
deletes all related backend/frontend code:

Backend:
- DELETE PUT /api/anime/{anime_key} endpoint
- DELETE AnimeMetadataUpdate model and KEY_PATTERN regex
- DELETE MAX_INPUT_LENGTH constant

Frontend:
- DELETE edit-modal.js component
- DELETE edit metadata modal HTML from index.html
- DELETE edit-modal.js script tag
- DELETE edit-only CSS (.edit-modal-content, .edit-section,
  .field-error, .input-error, .key-warning, .info-grid,
  .info-item, .input-with-action, .btn-fetch-tmdb, .tmdb-*)
- REMOVE 'Edit Metadata' item from context menu (NFO Diagnostics
  preserved)

Tests:
- DELETE test_anime_edit_endpoints.py
- DELETE test_edit_modal.py
- DELETE test_anime_key_rename.py
2026-06-20 21:02:22 +02:00
a8e54876e3 refactor: overhaul NFO settings UI and backend
- Rework nfo-settings page with improved styling and layout
- Update edit-modal and context-menu with enhanced functionality
- Refactor NFO API endpoints and models
- Remove deprecated test_nfo_diagnostics_repair.py
- Clean up tasks.md documentation
2026-06-20 20:32:46 +02:00
6dc3cda810 feat(nfo): implement NFO diagnostics and repair
- Add NFO API endpoints: diagnostics, repair, validate, needs-repair
- Create /settings/nfo page with full NFO management UI
- Add NFO status section to edit modal with repair functionality
- Add anime details API for edit modal pre-fill data
- Fix auth test fixtures in test_nfo_diagnostics_repair.py

Implements NFO diagnostics when editing anime series via right-click menu.
Users can now check NFO status, see missing tags, and repair NFOs
directly from the edit modal or the dedicated NFO settings page.
2026-06-14 19:34:58 +02:00
08f7f7453c refactor: remove legacy data file sync functionality
Series now loaded directly from database. Removed:
- sync_legacy_series_to_db() from anime_service.py
- Corresponding sync call after directory update in config.py
- Safety nets in initialization_service.py for missing progress IDs
2026-06-10 18:23:01 +02:00
e0be00dce6 refactor: move import to module level and extract event handler
- Move ProgressType import to top-level in auth.py
- Extract suggestion link click handler into attachSuggestionLinkEvents() function
- Reuse handler after search results load
2026-06-07 21:51:49 +02:00
de250bdd37 fix(middleware): prevent premature redirect to /login during loading
Users were incorrectly redirected to /login during the initial loading phase
before the loading was actually complete. Added loading_started and
loading_complete flags to properly track the initialization state so
the setup redirect middleware knows when it's safe to redirect.
2026-06-07 20:23:11 +02:00
07c311c1cd feat(setup): separate NFO scan into dedicated phase
- Add /nfo-scan-phase endpoint to trigger NFO scan independently
- Move NFO scan out of initial setup into separate post-unresolved phase
- Add phase query param handling for /loading page (?phase=initial, ?phase=nfo)
- Update setup redirect middleware to handle phase-based redirects
- Update auth setup to pass phase=initial to loading page
2026-06-07 17:37:32 +02:00
275aeb4544 feat(setup): add done button and integrate NFO scan into initialization
- Add /api/setup/unresolved/done endpoint to mark phase complete
- NFO scan now runs after series sync during initialization
- Middleware redirects to /login after setup complete (was /loading)
- Done button allows skipping folder resolution with redirect to NFO scan phase
2026-06-06 23:47:48 +02:00
be7b210959 feat: add custom query support for unresolved folder re-search
- Add SearchFolderRequest model for optional custom search query
- Update search endpoint to use custom query if provided
- Add search-again input field in UI for custom queries
- Increment search_attempts counter on re-search
2026-06-06 23:31:25 +02:00
109d3c8ac9 fix: streamline initialization flow after setup
- Remove nfo_scan and media_scan from loading page steps (no longer shown in UI)
- Remove perform_nfo_scan_if_needed calls from fastapi_app and auth.py
- Always redirect to /setup/unresolved after initialization completes
  instead of conditionally checking for unresolved folders
- Fix middleware to allow access to /loading page - let it handle
  its own redirect flow via WebSocket events

This ensures users always reach the unresolved folders page after
initial setup to manually configure any unmatched anime series.
2026-06-06 21:33:41 +02:00
a9084202e3 fixed missing import 2026-06-06 20:07:45 +02:00
ecef21eec4 feat(setup): track unresolved folders for manual key resolution
When SetupService cannot auto-resolve a provider key for an anime folder,
the folder is now tracked in the new 'unresolved_folders' table instead of
being silently skipped. Users can then resolve these via the new API:

- GET /api/setup/unresolved - list unresolved folders with search suggestions
- POST /api/setup/unresolved/{folder}/resolve - provide key to resolve folder

The SetupService.run() now:
- Tracks unresolved folders instead of skipping them
- Re-creates AnimeSeries for previously unresolved folders that are now resolved
- Includes unresolved count in logs

New files:
- src/server/api/setup_endpoints.py - API endpoints for unresolved management
- tests/unit/test_unresolved_folder_service.py - service and model tests

Modified:
- src/server/database/models.py - add UnresolvedFolder model
- src/server/database/service.py - add UnresolvedFolderService
- src/server/services/setup_service.py - track unresolved folders
- src/server/fastapi_app.py - include setup router
2026-06-05 21:07:52 +02:00
2c47713339 feat(anime): add year to folder names on series add
- Add _compute_folder_name helper that deduplicates year (handles cases like 'Name (2023)' not becoming 'Name (2023) (2023)')
- Create anime folder on disk when adding series (not just DB + memory)
- Add rename_folder_if_needed to auto-rename existing folders without year
- Fetch year from aniworld_provider and include in folder as 'Name (YYYY)'

Closes: anime folders now include release year when available from provider
2026-06-05 19:17:44 +02:00
8b21f1243f backzup 2026-06-05 17:18:00 +02:00
3d33626546 Remove duplicate folder scanning feature
Delete folder_rename_service.py. Stub out get_duplicate_folders API to return
empty response. Update folder_scan_service and tests to skip rename step.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 16:33:52 +02:00
5526ab884a refactor: restructure core→server, split large entity files into database module
- Move src/core/ → src/server/
- Split SerieList.py (531 lines) and series.py (414 lines) into src/server/database/
- Add database/models.py for SQLAlchemy models
- Update all test imports to reflect new structure
- Remove deprecated test files (test_serie_class.py, test_serie_folder_with_year.py)
2026-06-04 21:11:53 +02:00
21af502184 refactor: simplify NFO handling, remove legacy services
- Drop nfo_factory, nfo_repair_service, nfo_service, series_manager_service
- Delete key_resolution_service, consolidate into folder_rename_service
- Remove bulk of NFO-related tests (coverage via integration tests)
- Streamline SeriesApp, background_loader, initialization services
- Add folder_rename_service to scheduler

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-04 18:54:31 +02:00
9c3f03d610 refactor(scheduler): separate scheduler logic from scan/rescan logic
- Extract rescan logic into new RescanService (src/server/services/rescan_service.py)
- SchedulerService now only handles APScheduler cron scheduling
- Move scheduler sub-services (folder_rename, folder_scan, key_resolution) to scheduler/ folder
- Keep RescanOrchestrator as backward-compatible alias
- Update all imports across api/, server/, and test files
2026-06-03 20:58:30 +02:00
246752e2fc Add dynamic version from Docker/VERSION file
- Create version.py utility to read version from Docker/VERSION
- Replace hardcoded version '1.0.1' with APP_VERSION from version.py
- Add version logging on FastAPI startup
- Use APP_VERSION in health endpoints and template context
2026-06-02 20:38:42 +02:00
6021cdef28 feat: add anime metadata editing and NFO diagnostics
- Add PUT /anime/{key} endpoint for updating anime key, tmdb_id, tvdb_id
- Add NFO diagnostics and repair endpoints (GET/POST /nfo/diagnostics)
- Add edit modal UI with context menu integration
- Add frontend JS modules for context-menu and edit-modal
- Add comprehensive tests for edit, rename, and NFO repair flows
2026-05-31 18:31:56 +02:00
5517ccbab0 style: reformat folder_rename_service import 2026-05-30 12:20:40 +02:00
94ed013172 Revert "feat: add manual TMDB/TVDB ID entry for failed lookups"
This reverts commit 30858f441c.
2026-05-30 12:17:48 +02:00
1ef59c5283 feat: add duplicate folder detection and /duplicate-folders API endpoint
- Add DuplicateFolderGroup and DuplicateFoldersResponse Pydantic models
- Add /duplicate-folders GET endpoint for listing pre-existing duplicates
- Add _scan_for_pre_existing_duplicates() function for NFO-based detection
- Add _try_merge_duplicate_group() for auto-merging empty/symlink-only duplicates
- Integrate duplicate detection into validate_and_rename_series_folders workflow
- Skip rename for flagged duplicates to prevent data loss during merge
2026-05-28 21:46:08 +02:00
30858f441c feat: add manual TMDB/TVDB ID entry for failed lookups
- Add PATCH /api/anime/{key}/metadata-ids endpoint to update IDs
- Add POST /api/anime/{key}/refresh-nfo endpoint to force NFO regeneration
- Add Edit Metadata IDs modal in frontend
- Add showEditMetadataModal, saveMetadataIds, refreshSeriesNfo JS functions
- Add edit-metadata-btn to series cards with database icon
- IDs validated as positive integers or null

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 18:38:34 +02:00