From 627f8b0cc4aa63928b83bfac8d158875f133bd7e Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 30 Oct 2025 19:56:22 +0100 Subject: [PATCH] fix download --- data/analytics.json | 4 +- data/config.json | 2 +- .../config_backup_20251027_201521.json | 24 --- data/download_queue.json | 192 +++++++++--------- src/server/api/anime.py | 48 ----- src/server/web/static/js/app.js | 71 +++++-- .../frontend/test_existing_ui_integration.py | 2 +- 7 files changed, 159 insertions(+), 184 deletions(-) delete mode 100644 data/config_backups/config_backup_20251027_201521.json diff --git a/data/analytics.json b/data/analytics.json index 32bf232..75ea3d5 100644 --- a/data/analytics.json +++ b/data/analytics.json @@ -1,6 +1,6 @@ { - "created_at": "2025-10-27T20:15:18.690820", - "last_updated": "2025-10-27T20:15:18.690826", + "created_at": "2025-10-30T19:51:12.073703", + "last_updated": "2025-10-30T19:51:12.073709", "download_stats": { "total_downloads": 0, "successful_downloads": 0, diff --git a/data/config.json b/data/config.json index 86ca381..4baa9e7 100644 --- a/data/config.json +++ b/data/config.json @@ -17,7 +17,7 @@ "keep_days": 30 }, "other": { - "master_password_hash": "$pbkdf2-sha256$29000$hjDm/H8vRehdCyEkRGitVQ$JJC2Bxw8XeNA0NoG/e4rhw6PjZaN588mJ2SDY3ZPFNY", + "master_password_hash": "$pbkdf2-sha256$29000$yvlfq9V6z5kzBgDAuNfamw$yOIAkdvscVcnLca5C0CY/1rM3PblB.50gnmiYPycaAk", "anime_directory": "/home/lukas/Volume/serien/" }, "version": "1.0.0" diff --git a/data/config_backups/config_backup_20251027_201521.json b/data/config_backups/config_backup_20251027_201521.json deleted file mode 100644 index 07390a2..0000000 --- a/data/config_backups/config_backup_20251027_201521.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "Aniworld", - "data_dir": "data", - "scheduler": { - "enabled": true, - "interval_minutes": 60 - }, - "logging": { - "level": "INFO", - "file": null, - "max_bytes": null, - "backup_count": 3 - }, - "backup": { - "enabled": false, - "path": "data/backups", - "keep_days": 30 - }, - "other": { - "master_password_hash": "$pbkdf2-sha256$29000$qRWiNCaEEIKQkhKiFOLcWw$P1QqwKEJHzPszsU/nHmIzdxwbTMIV2iC4tbWUuhqZlo", - "anime_directory": "/home/lukas/Volume/serien/" - }, - "version": "1.0.0" -} \ No newline at end of file diff --git a/data/download_queue.json b/data/download_queue.json index 81ccf46..df172b6 100644 --- a/data/download_queue.json +++ b/data/download_queue.json @@ -1,7 +1,7 @@ { "pending": [ { - "id": "47335663-456f-44b6-a176-aa2c2ab74451", + "id": "c7f0d083-d220-4b77-8436-a63cb1a3cd41", "serie_id": "workflow-series", "serie_name": "Workflow Test Series", "episode": { @@ -11,7 +11,7 @@ }, "status": "pending", "priority": "high", - "added_at": "2025-10-27T19:15:24.278322Z", + "added_at": "2025-10-30T18:54:21.361837Z", "started_at": null, "completed_at": null, "progress": null, @@ -20,7 +20,7 @@ "source_url": null }, { - "id": "665e833d-b4b8-4fb2-810f-5a02ed1b3161", + "id": "9a7081cb-670e-4eb0-85be-f93ad2ee76ef", "serie_id": "series-2", "serie_name": "Series 2", "episode": { @@ -30,7 +30,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.825647Z", + "added_at": "2025-10-30T18:54:20.910955Z", "started_at": null, "completed_at": null, "progress": null, @@ -39,7 +39,7 @@ "source_url": null }, { - "id": "6d2d59b4-c4a7-4056-a386-d49f709f56ec", + "id": "f8218676-c3f8-4037-a8e2-7d7a92f5a220", "serie_id": "series-1", "serie_name": "Series 1", "episode": { @@ -49,7 +49,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.822544Z", + "added_at": "2025-10-30T18:54:20.908397Z", "started_at": null, "completed_at": null, "progress": null, @@ -58,7 +58,7 @@ "source_url": null }, { - "id": "eb43e2ce-b782-473f-aa5e-b29e07531034", + "id": "ddbcdfd8-1d09-48e0-8727-36682c773dae", "serie_id": "series-0", "serie_name": "Series 0", "episode": { @@ -68,7 +68,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.817448Z", + "added_at": "2025-10-30T18:54:20.906192Z", "started_at": null, "completed_at": null, "progress": null, @@ -77,7 +77,7 @@ "source_url": null }, { - "id": "f942fc20-2eb3-44fc-b2e1-5634d3749856", + "id": "835c59d2-7272-4ca3-b60c-0f564908d173", "serie_id": "series-high", "serie_name": "Series High", "episode": { @@ -87,7 +87,7 @@ }, "status": "pending", "priority": "high", - "added_at": "2025-10-27T19:15:23.494450Z", + "added_at": "2025-10-30T18:54:20.574207Z", "started_at": null, "completed_at": null, "progress": null, @@ -96,7 +96,7 @@ "source_url": null }, { - "id": "d91b4625-af9f-4f84-a223-a3a68a743a6f", + "id": "d02479b2-c831-4ff2-af0b-6aaedd502980", "serie_id": "test-series-2", "serie_name": "Another Series", "episode": { @@ -106,7 +106,7 @@ }, "status": "pending", "priority": "high", - "added_at": "2025-10-27T19:15:23.458331Z", + "added_at": "2025-10-30T18:54:20.507314Z", "started_at": null, "completed_at": null, "progress": null, @@ -115,7 +115,7 @@ "source_url": null }, { - "id": "020aa6c4-b969-4290-a9f3-3951a0ebf218", + "id": "b7ac0d47-2cd7-49cb-bbf3-9f3ba2490785", "serie_id": "test-series-1", "serie_name": "Test Anime Series", "episode": { @@ -125,7 +125,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.424005Z", + "added_at": "2025-10-30T18:54:20.465257Z", "started_at": null, "completed_at": null, "progress": null, @@ -134,7 +134,7 @@ "source_url": null }, { - "id": "67a98da0-544d-46c6-865c-0eea068ee47d", + "id": "e001144e-e536-4104-8a90-1ddd9916c32c", "serie_id": "test-series-1", "serie_name": "Test Anime Series", "episode": { @@ -144,7 +144,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.424103Z", + "added_at": "2025-10-30T18:54:20.465365Z", "started_at": null, "completed_at": null, "progress": null, @@ -153,7 +153,7 @@ "source_url": null }, { - "id": "bb811506-a40f-45e0-a517-9d12afa33759", + "id": "7315d49d-8e84-497d-acaa-b5b8b19980fe", "serie_id": "series-normal", "serie_name": "Series Normal", "episode": { @@ -163,7 +163,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.496680Z", + "added_at": "2025-10-30T18:54:20.576631Z", "started_at": null, "completed_at": null, "progress": null, @@ -172,7 +172,7 @@ "source_url": null }, { - "id": "2f8e6e85-7a1c-4d9b-aeaf-f4c9da6de8da", + "id": "50c70333-4d65-4a69-8b32-8f1644867681", "serie_id": "series-low", "serie_name": "Series Low", "episode": { @@ -182,7 +182,7 @@ }, "status": "pending", "priority": "low", - "added_at": "2025-10-27T19:15:23.498731Z", + "added_at": "2025-10-30T18:54:20.581167Z", "started_at": null, "completed_at": null, "progress": null, @@ -191,7 +191,7 @@ "source_url": null }, { - "id": "885b8873-8a97-439d-b2f3-93d50828baad", + "id": "4276f2e3-45e9-413d-87ab-e7ffd65f754e", "serie_id": "test-series", "serie_name": "Test Series", "episode": { @@ -201,7 +201,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.746489Z", + "added_at": "2025-10-30T18:54:20.841051Z", "started_at": null, "completed_at": null, "progress": null, @@ -210,7 +210,7 @@ "source_url": null }, { - "id": "15711557-66d2-4b7c-90f5-17600dfb0e40", + "id": "6f47264e-c7a7-4991-b5d3-569c99228580", "serie_id": "test-series", "serie_name": "Test Series", "episode": { @@ -220,7 +220,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.860548Z", + "added_at": "2025-10-30T18:54:20.948517Z", "started_at": null, "completed_at": null, "progress": null, @@ -229,7 +229,7 @@ "source_url": null }, { - "id": "e3b0ade0-b4bb-414e-a65d-9593dd3b27b9", + "id": "4135367a-cfe9-4d09-95be-a909805e66b7", "serie_id": "invalid-series", "serie_name": "Invalid Series", "episode": { @@ -239,7 +239,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.938644Z", + "added_at": "2025-10-30T18:54:21.031222Z", "started_at": null, "completed_at": null, "progress": null, @@ -248,7 +248,7 @@ "source_url": null }, { - "id": "41f5ce9e-f20c-4ad6-b074-ff06787463d5", + "id": "7005ac80-386a-43a3-ad6f-6a2b60aab3b3", "serie_id": "test-series", "serie_name": "Test Series", "episode": { @@ -258,7 +258,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:23.973361Z", + "added_at": "2025-10-30T18:54:21.072761Z", "started_at": null, "completed_at": null, "progress": null, @@ -267,45 +267,7 @@ "source_url": null }, { - "id": "3c84fcc6-3aa4-4531-bcc8-296c7eb36430", - "serie_id": "series-4", - "serie_name": "Series 4", - "episode": { - "season": 1, - "episode": 1, - "title": null - }, - "status": "pending", - "priority": "normal", - "added_at": "2025-10-27T19:15:24.075622Z", - "started_at": null, - "completed_at": null, - "progress": null, - "error": null, - "retry_count": 0, - "source_url": null - }, - { - "id": "650324c2-7028-46fb-bceb-9ed756f514c8", - "serie_id": "series-3", - "serie_name": "Series 3", - "episode": { - "season": 1, - "episode": 1, - "title": null - }, - "status": "pending", - "priority": "normal", - "added_at": "2025-10-27T19:15:24.076679Z", - "started_at": null, - "completed_at": null, - "progress": null, - "error": null, - "retry_count": 0, - "source_url": null - }, - { - "id": "8782d952-25c3-4907-85eb-205c216f0b35", + "id": "32e35da2-d255-405e-829a-02c1a5ba64a5", "serie_id": "series-2", "serie_name": "Series 2", "episode": { @@ -315,7 +277,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:24.077499Z", + "added_at": "2025-10-30T18:54:21.166090Z", "started_at": null, "completed_at": null, "progress": null, @@ -324,26 +286,7 @@ "source_url": null }, { - "id": "ba2e0be5-3d11-47df-892b-7df465824419", - "serie_id": "series-1", - "serie_name": "Series 1", - "episode": { - "season": 1, - "episode": 1, - "title": null - }, - "status": "pending", - "priority": "normal", - "added_at": "2025-10-27T19:15:24.078333Z", - "started_at": null, - "completed_at": null, - "progress": null, - "error": null, - "retry_count": 0, - "source_url": null - }, - { - "id": "7a64b375-aaad-494d-bcd1-1f2ae5c421f4", + "id": "28d8d198-2ae2-4e29-89e6-812a444cb5d2", "serie_id": "series-0", "serie_name": "Series 0", "episode": { @@ -353,7 +296,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:24.079175Z", + "added_at": "2025-10-30T18:54:21.169681Z", "started_at": null, "completed_at": null, "progress": null, @@ -362,7 +305,64 @@ "source_url": null }, { - "id": "c532886f-6dc2-45fa-92dd-3d46ef62a692", + "id": "f0776c79-a61c-4237-ac57-7eed248431c2", + "serie_id": "series-1", + "serie_name": "Series 1", + "episode": { + "season": 1, + "episode": 1, + "title": null + }, + "status": "pending", + "priority": "normal", + "added_at": "2025-10-30T18:54:21.171115Z", + "started_at": null, + "completed_at": null, + "progress": null, + "error": null, + "retry_count": 0, + "source_url": null + }, + { + "id": "57101762-1c77-48c6-b8ac-e21bf649f468", + "serie_id": "series-3", + "serie_name": "Series 3", + "episode": { + "season": 1, + "episode": 1, + "title": null + }, + "status": "pending", + "priority": "normal", + "added_at": "2025-10-30T18:54:21.171777Z", + "started_at": null, + "completed_at": null, + "progress": null, + "error": null, + "retry_count": 0, + "source_url": null + }, + { + "id": "9ef218df-b877-4ff9-be74-a770e5f865b5", + "serie_id": "series-4", + "serie_name": "Series 4", + "episode": { + "season": 1, + "episode": 1, + "title": null + }, + "status": "pending", + "priority": "normal", + "added_at": "2025-10-30T18:54:21.172560Z", + "started_at": null, + "completed_at": null, + "progress": null, + "error": null, + "retry_count": 0, + "source_url": null + }, + { + "id": "3fe68c06-4755-4f02-bdd5-a4760f79064f", "serie_id": "persistent-series", "serie_name": "Persistent Series", "episode": { @@ -372,7 +372,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:24.173243Z", + "added_at": "2025-10-30T18:54:21.254000Z", "started_at": null, "completed_at": null, "progress": null, @@ -381,7 +381,7 @@ "source_url": null }, { - "id": "0e6d4e1e-7714-4fb1-9ad1-3458c9c6d4e6", + "id": "bcd2328c-ba3b-4a5b-a364-1964963324c2", "serie_id": "ws-series", "serie_name": "WebSocket Series", "episode": { @@ -391,7 +391,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:24.241585Z", + "added_at": "2025-10-30T18:54:21.320033Z", "started_at": null, "completed_at": null, "progress": null, @@ -400,7 +400,7 @@ "source_url": null }, { - "id": "f10196c8-f093-4a15-a498-72c3bfe6f735", + "id": "83e98629-7fe4-46e5-ad15-d60b5e2c2d09", "serie_id": "pause-test", "serie_name": "Pause Test Series", "episode": { @@ -410,7 +410,7 @@ }, "status": "pending", "priority": "normal", - "added_at": "2025-10-27T19:15:24.426637Z", + "added_at": "2025-10-30T18:54:21.509480Z", "started_at": null, "completed_at": null, "progress": null, @@ -421,5 +421,5 @@ ], "active": [], "failed": [], - "timestamp": "2025-10-27T19:15:24.426898+00:00" + "timestamp": "2025-10-30T18:54:21.509760+00:00" } \ No newline at end of file diff --git a/src/server/api/anime.py b/src/server/api/anime.py index 1f9675d..e8da1a7 100644 --- a/src/server/api/anime.py +++ b/src/server/api/anime.py @@ -341,12 +341,6 @@ class AddSeriesRequest(BaseModel): name: str -class DownloadFoldersRequest(BaseModel): - """Request model for downloading missing episodes from folders.""" - - folders: List[str] - - def validate_search_query(query: str) -> str: """Validate and sanitize search query. @@ -594,48 +588,6 @@ async def add_series( ) from exc -@router.post("/download") -async def download_folders( - request: DownloadFoldersRequest, - _auth: dict = Depends(require_auth), - series_app: Any = Depends(get_series_app), -) -> dict: - """Start downloading missing episodes from the specified folders. - - Args: - request: Request containing list of folder names - _auth: Ensures the caller is authenticated (value unused) - series_app: Core `SeriesApp` instance provided via dependency - - Returns: - Dict[str, Any]: Status payload with success message - - Raises: - HTTPException: If download initiation fails - """ - try: - if not hasattr(series_app, "Download"): - raise HTTPException( - status_code=status.HTTP_501_NOT_IMPLEMENTED, - detail="Download functionality not available", - ) - - # Call Download with the folders and a no-op callback - series_app.Download(request.folders, lambda *args, **kwargs: None) - - return { - "status": "success", - "message": f"Download started for {len(request.folders)} series" - } - except HTTPException: - raise - except Exception as exc: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to start download: {str(exc)}", - ) from exc - - @router.get("/{anime_id}", response_model=AnimeDetail) async def get_anime( anime_id: str, diff --git a/src/server/web/static/js/app.js b/src/server/web/static/js/app.js index 83841e4..f137cda 100644 --- a/src/server/web/static/js/app.js +++ b/src/server/web/static/js/app.js @@ -912,22 +912,69 @@ class AniWorldApp { try { const folders = Array.from(this.selectedSeries); + let totalEpisodesAdded = 0; + let failedSeries = []; - const response = await this.makeAuthenticatedRequest('/api/anime/download', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ folders }) - }); + // For each selected series, get its missing episodes and add to queue + for (const folder of folders) { + const serie = this.seriesData.find(s => s.folder === folder); + if (!serie || !serie.episodeDict) { + failedSeries.push(folder); + continue; + } - if (!response) return; - const data = await response.json(); + // Convert episodeDict format {season: [episodes]} to episode identifiers + const episodes = []; + for (const [season, episodeNumbers] of Object.entries(serie.episodeDict)) { + if (Array.isArray(episodeNumbers)) { + for (const episode of episodeNumbers) { + episodes.push({ + season: parseInt(season), + episode: episode + }); + } + } + } - if (data.status === 'success') { - this.showToast('Download started', 'success'); + if (episodes.length === 0) { + continue; + } + + // Add episodes to download queue + const response = await this.makeAuthenticatedRequest('/api/queue/add', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + serie_id: serie.key, + serie_name: serie.name, + episodes: episodes, + priority: 'NORMAL' + }) + }); + + if (!response) { + failedSeries.push(folder); + continue; + } + + const data = await response.json(); + if (data.status === 'success') { + totalEpisodesAdded += episodes.length; + } else { + failedSeries.push(folder); + } + } + + // Show result message + if (totalEpisodesAdded > 0) { + const message = failedSeries.length > 0 + ? `Added ${totalEpisodesAdded} episode(s) to queue (${failedSeries.length} series failed)` + : `Added ${totalEpisodesAdded} episode(s) to download queue`; + this.showToast(message, 'success'); } else { - this.showToast(`Download error: ${data.message}`, 'error'); + this.showToast('Failed to add episodes to queue', 'error'); } } catch (error) { console.error('Download error:', error); diff --git a/tests/frontend/test_existing_ui_integration.py b/tests/frontend/test_existing_ui_integration.py index b0b5383..fbe2edf 100644 --- a/tests/frontend/test_existing_ui_integration.py +++ b/tests/frontend/test_existing_ui_integration.py @@ -197,7 +197,7 @@ class TestFrontendAnimeAPI: assert isinstance(data, list) # Search should return results (actual API call) if len(data) > 0: - assert "title" in data[0] + assert "name" in data[0] async def test_rescan_anime(self, authenticated_client): """Test POST /api/anime/rescan triggers rescan."""