# API Specification - Media Downloader Web GUI ## Overview RESTful API with WebSocket support for real-time updates. **Base URL:** `http://localhost:8000/api/v1` **Authentication:** JWT Bearer Token **Content-Type:** `application/json` --- ## Authentication Endpoints ### POST /auth/login Login with username and password. **Request:** ```json { "username": "admin", "password": "secretpassword" } ``` **Response (200 OK):** ```json { "access_token": "eyJhbGciOiJIUzI1NiIs...", "refresh_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "bearer", "expires_in": 900, "user": { "id": 1, "username": "admin", "email": "admin@example.com", "role": "admin" } } ``` **Error Response (401 Unauthorized):** ```json { "detail": "Incorrect username or password" } ``` --- ### POST /auth/refresh Refresh access token using refresh token. **Request:** ```json { "refresh_token": "eyJhbGciOiJIUzI1NiIs..." } ``` **Response (200 OK):** ```json { "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "bearer", "expires_in": 900 } ``` --- ### GET /auth/me Get current authenticated user. **Headers:** ``` Authorization: Bearer eyJhbGciOiJIUzI1NiIs... ``` **Response (200 OK):** ```json { "id": 1, "username": "admin", "email": "admin@example.com", "role": "admin", "created_at": "2025-10-01T10:00:00Z", "last_login": "2025-10-13T14:30:00Z" } ``` --- ## Download Endpoints ### GET /downloads List downloads with filtering and pagination. **Query Parameters:** - `page` (int): Page number (default: 1) - `per_page` (int): Items per page (default: 50, max: 200) - `platform` (str): Filter by platform (instagram, tiktok, forum) - `source` (str): Filter by source (username/forum name) - `status` (str): Filter by status (completed, failed) - `date_from` (date): Filter from date (YYYY-MM-DD) - `date_to` (date): Filter to date (YYYY-MM-DD) - `search` (str): Search in URLs and filenames **Example Request:** ``` GET /downloads?platform=instagram&source=evalongoria&page=1&per_page=20 ``` **Response (200 OK):** ```json { "items": [ { "id": 1885, "url": "https://instagram.com/p/ABC123/", "url_hash": "a1b2c3d4e5f6...", "platform": "instagram", "source": "evalongoria", "content_type": "post", "filename": "evalongoria_20251012_141523_123456789.jpg", "file_path": "/opt/media-downloader/downloads/fastdl/evalongoria/evalongoria_20251012_141523_123456789.jpg", "file_size": 2457600, "file_hash": "sha256:abc123...", "post_date": "2025-10-12T14:15:23Z", "download_date": "2025-10-12T14:20:45Z", "status": "completed", "attempts": 1, "metadata": { "media_id": "123456789", "resolution": "640x640", "upgraded": false } } ], "total": 1885, "page": 1, "per_page": 20, "total_pages": 95 } ``` --- ### GET /downloads/{id} Get single download by ID. **Response (200 OK):** ```json { "id": 1885, "url": "https://instagram.com/p/ABC123/", "platform": "instagram", "source": "evalongoria", "content_type": "post", "filename": "evalongoria_20251012_141523_123456789.jpg", "file_path": "/opt/media-downloader/downloads/fastdl/evalongoria/evalongoria_20251012_141523_123456789.jpg", "file_size": 2457600, "file_hash": "sha256:abc123...", "post_date": "2025-10-12T14:15:23Z", "download_date": "2025-10-12T14:20:45Z", "status": "completed", "attempts": 1, "metadata": { "media_id": "123456789", "resolution": "640x640", "upgraded": false }, "thumbnail_url": "/api/v1/downloads/1885/thumbnail" } ``` --- ### DELETE /downloads/{id} Delete download record (optionally delete file). **Query Parameters:** - `delete_file` (bool): Also delete the physical file (default: false) **Response (204 No Content)** --- ### GET /downloads/stats Get download statistics. **Query Parameters:** - `period` (str): Time period (today, week, month, year, all) - `group_by` (str): Group by field (platform, source, content_type) **Response (200 OK):** ```json { "total_downloads": 1885, "completed": 1870, "failed": 15, "success_rate": 99.2, "total_size_bytes": 45678901234, "by_platform": { "instagram": 333, "fastdl": 18, "tiktok": 12, "forum": 1522 }, "by_source": { "evalongoria": 186, "PicturePub": 1332, "HQCelebCorner": 190 }, "timeline": [ {"date": "2025-10-06", "count": 15}, {"date": "2025-10-07", "count": 23}, {"date": "2025-10-08", "count": 31} ] } ``` --- ### POST /downloads/bulk Bulk operations on downloads. **Request:** ```json { "action": "delete", // delete, retry, mark_upgraded "ids": [1, 2, 3, 4, 5], "delete_files": false } ``` **Response (200 OK):** ```json { "success": 5, "failed": 0, "errors": [] } ``` --- ## Queue Endpoints ### GET /queue Get download queue items. **Query Parameters:** - `status` (str): Filter by status (pending, downloading, completed, failed) - `platform` (str): Filter by platform - `page` (int): Page number - `per_page` (int): Items per page **Response (200 OK):** ```json { "items": [ { "id": 2731, "url": "https://instagram.com/evalongoria", "platform": "forum", "source": "PicturePub", "referer": null, "save_path": "/opt/media-downloader/downloads/forum/PicturePub", "priority": 5, "status": "pending", "attempts": 0, "max_attempts": 3, "created_date": "2025-10-13T10:30:00Z", "started_at": null, "download_date": null, "progress": 0, "estimated_completion": null, "assigned_worker": null, "error_message": null, "metadata": { "thread_id": "thread-12345", "content_type": "images" } } ], "total": 2731, "pending": 2731, "downloading": 0, "completed": 0, "failed": 0 } ``` --- ### POST /queue Add item to download queue. **Request:** ```json { "url": "https://instagram.com/evalongoria", "platform": "instagram", "source": "evalongoria", "content_type": "posts", "priority": 5, "max_downloads": 15, "metadata": { "downloader": "fastdl" } } ``` **Response (201 Created):** ```json { "id": 2732, "url": "https://instagram.com/evalongoria", "platform": "instagram", "source": "evalongoria", "status": "pending", "created_date": "2025-10-13T15:45:00Z", "task_id": "celery-task-uuid-here" } ``` --- ### PATCH /queue/{id} Update queue item. **Request:** ```json { "priority": 1, "status": "paused" } ``` **Response (200 OK):** ```json { "id": 2732, "status": "paused", "priority": 1 } ``` --- ### DELETE /queue/{id} Remove item from queue. **Response (204 No Content)** --- ### POST /queue/{id}/retry Retry failed download. **Response (200 OK):** ```json { "id": 2732, "status": "pending", "attempts": 1, "task_id": "celery-task-uuid-here" } ``` --- ### POST /queue/clear Clear completed/failed items from queue. **Request:** ```json { "status": ["completed", "failed"] } ``` **Response (200 OK):** ```json { "deleted": 125 } ``` --- ### GET /queue/stats Get queue statistics. **Response (200 OK):** ```json { "total": 2731, "pending": 2700, "downloading": 5, "completed": 20, "failed": 6, "avg_wait_time_seconds": 120, "estimated_completion": "2025-10-13T18:30:00Z", "active_workers": 4 } ``` --- ## Scheduler Endpoints ### GET /scheduler/jobs List all scheduled jobs. **Response (200 OK):** ```json { "jobs": [ { "id": "instagram-evalongoria-posts", "name": "Eva Longoria Instagram Posts", "platform": "instagram", "source": "evalongoria", "content_type": "posts", "schedule": "0 */4 * * *", // Every 4 hours "schedule_human": "Every 4 hours", "enabled": true, "last_run": "2025-10-13T12:00:00Z", "last_run_status": "success", "last_run_items": 8, "next_run": "2025-10-13T16:00:00Z", "total_runs": 245, "success_count": 240, "failure_count": 5, "config": { "max_downloads": 15, "downloader": "fastdl" } } ] } ``` --- ### POST /scheduler/jobs Create new scheduled job. **Request:** ```json { "name": "Eva Longoria Stories", "platform": "instagram", "source": "evalongoria", "content_type": "stories", "schedule": "0 */6 * * *", "enabled": true, "config": { "max_downloads": 50, "downloader": "fastdl" } } ``` **Response (201 Created):** ```json { "id": "instagram-evalongoria-stories", "name": "Eva Longoria Stories", "next_run": "2025-10-13T18:00:00Z", "enabled": true } ``` --- ### PATCH /scheduler/jobs/{id} Update scheduled job. **Request:** ```json { "schedule": "0 */8 * * *", "enabled": false } ``` **Response (200 OK):** ```json { "id": "instagram-evalongoria-stories", "schedule": "0 */8 * * *", "enabled": false, "next_run": null } ``` --- ### DELETE /scheduler/jobs/{id} Delete scheduled job. **Response (204 No Content)** --- ### POST /scheduler/jobs/{id}/run Manually trigger job execution. **Response (202 Accepted):** ```json { "task_id": "celery-task-uuid", "status": "queued", "message": "Job execution queued" } ``` --- ### GET /scheduler/history Get job execution history. **Query Parameters:** - `job_id` (str): Filter by job ID - `status` (str): Filter by status (success, failure) - `limit` (int): Number of records (default: 100) **Response (200 OK):** ```json { "history": [ { "id": 1234, "job_id": "instagram-evalongoria-posts", "started_at": "2025-10-13T12:00:00Z", "completed_at": "2025-10-13T12:03:45Z", "duration_seconds": 225, "status": "success", "items_downloaded": 8, "error_message": null } ] } ``` --- ## Platform Endpoints ### GET /platforms List all supported platforms. **Response (200 OK):** ```json { "platforms": [ { "name": "instagram", "display_name": "Instagram", "enabled": true, "downloaders": [ { "name": "fastdl", "display_name": "FastDL (640x640)", "enabled": true }, { "name": "toolzu", "display_name": "Toolzu (1920x1440)", "enabled": true } ], "content_types": ["posts", "stories", "reels"], "features": ["quality_upgrade", "date_filtering", "limit_downloads"], "status": "operational", "last_successful_download": "2025-10-13T14:30:00Z" }, { "name": "tiktok", "display_name": "TikTok", "enabled": true, "content_types": ["videos"], "status": "operational" } ] } ``` --- ### POST /platforms/instagram/download Start Instagram download. **Request:** ```json { "username": "evalongoria", "content_type": "posts", "downloader": "fastdl", "max_downloads": 15, "days_back": 7, "priority": 5 } ``` **Response (202 Accepted):** ```json { "queue_id": 2733, "task_id": "celery-task-uuid", "status": "queued", "message": "Download queued successfully" } ``` --- ### POST /platforms/tiktok/download Start TikTok download. **Request:** ```json { "username": "evalongoria", "max_downloads": 10, "priority": 5 } ``` **Response (202 Accepted):** ```json { "queue_id": 2734, "task_id": "celery-task-uuid", "status": "queued" } ``` --- ### POST /platforms/forum/monitor Start forum thread monitoring. **Request:** ```json { "forum_name": "PicturePub", "thread_url": "https://example.com/thread/123", "thread_title": "Celebrity Photos", "monitor_days": 30 } ``` **Response (201 Created):** ```json { "thread_id": "thread-123", "status": "active", "monitor_until": "2025-11-12T15:00:00Z" } ``` --- ## Settings Endpoints ### GET /settings Get all application settings. **Response (200 OK):** ```json { "general": { "download_directory": "/opt/media-downloader/downloads", "concurrent_downloads": 4, "retry_attempts": 3, "default_priority": 5, "storage_limit_gb": 500, "auto_cleanup_days": 180 }, "platforms": { "instagram": { "fastdl": { "enabled": true, "rate_limit_per_hour": 100 }, "toolzu": { "enabled": true, "auto_upgrade": true, "captcha_api_key": "***" } }, "tiktok": { "enabled": true, "quality": "hd" } }, "notifications": { "email": { "enabled": false, "smtp_host": "", "smtp_port": 587 }, "browser": { "enabled": true } } } ``` --- ### PATCH /settings Update settings. **Request:** ```json { "general": { "concurrent_downloads": 6 }, "platforms": { "instagram": { "toolzu": { "auto_upgrade": false } } } } ``` **Response (200 OK):** ```json { "message": "Settings updated successfully", "updated_fields": 2 } ``` --- ## Logs Endpoints ### GET /logs Get application logs. **Query Parameters:** - `level` (str): Filter by level (DEBUG, INFO, WARNING, ERROR) - `module` (str): Filter by module (Instagram, TikTok, Scheduler, etc.) - `search` (str): Search in log messages - `date_from` (datetime): From timestamp - `date_to` (datetime): To timestamp - `limit` (int): Number of records (default: 100, max: 1000) **Response (200 OK):** ```json { "logs": [ { "id": 12345, "timestamp": "2025-10-13T15:45:23.456Z", "level": "INFO", "module": "Instagram", "message": "Downloaded 8 posts from evalongoria", "metadata": { "username": "evalongoria", "count": 8, "duration_seconds": 45 } } ], "total": 12345, "filtered": 100 } ``` --- ### GET /logs/download Download log file. **Query Parameters:** - `date` (date): Log file date (YYYY-MM-DD) - `format` (str): Format (json, text) **Response (200 OK):** ``` Content-Type: application/octet-stream Content-Disposition: attachment; filename="media_downloader_20251013.log" [Log file content] ``` --- ### DELETE /logs Clear old logs. **Query Parameters:** - `older_than_days` (int): Delete logs older than N days **Response (200 OK):** ```json { "deleted_files": 15, "deleted_size_bytes": 52428800 } ``` --- ## Statistics Endpoints ### GET /stats/overview Get dashboard overview statistics. **Response (200 OK):** ```json { "downloads": { "today": 45, "week": 312, "month": 1205, "total": 1885 }, "queue": { "pending": 2731, "downloading": 5, "failed": 6 }, "success_rate": { "today": 97.8, "week": 98.5, "month": 99.2 }, "storage": { "used_bytes": 45678901234, "used_human": "42.5 GB", "limit_bytes": 536870912000, "limit_human": "500 GB", "percent": 8.5 }, "platforms": { "instagram": { "status": "operational", "downloads_today": 35 }, "tiktok": { "status": "operational", "downloads_today": 2 }, "forum": { "status": "operational", "downloads_today": 8 } }, "next_scheduled_task": { "job_id": "instagram-evalongoria-posts", "job_name": "Eva Longoria Instagram Posts", "scheduled_time": "2025-10-13T16:00:00Z", "in_seconds": 873 } } ``` --- ### GET /stats/timeline Get downloads over time. **Query Parameters:** - `period` (str): Period (day, week, month, year) - `group_by` (str): Group by (hour, day, week, month) **Response (200 OK):** ```json { "timeline": [ { "timestamp": "2025-10-06T00:00:00Z", "downloads": 45, "success": 44, "failed": 1 }, { "timestamp": "2025-10-07T00:00:00Z", "downloads": 52, "success": 52, "failed": 0 } ] } ``` --- ### GET /stats/platforms Get breakdown by platform. **Response (200 OK):** ```json { "platforms": [ { "platform": "instagram", "downloads": 351, "success": 348, "failed": 3, "success_rate": 99.1, "total_size_bytes": 15678901234 }, { "platform": "forum", "downloads": 1522, "success": 1520, "failed": 2, "success_rate": 99.9, "total_size_bytes": 28678901234 } ] } ``` --- ## WebSocket Events ### Connection ``` WS ws://localhost:8000/ws/downloads?token=JWT_TOKEN ``` ### Download Progress Event ```json { "type": "download_progress", "timestamp": "2025-10-13T15:45:23.456Z", "data": { "queue_id": 2733, "url": "https://instagram.com/evalongoria", "platform": "instagram", "source": "evalongoria", "status": "downloading", "progress": 65, "items_downloaded": 13, "items_total": 20, "current_item": "evalongoria_20251012_141523_123456789.jpg", "speed_mbps": 2.5, "eta_seconds": 45 } } ``` ### Download Complete Event ```json { "type": "download_completed", "timestamp": "2025-10-13T15:48:15.123Z", "data": { "queue_id": 2733, "platform": "instagram", "source": "evalongoria", "items_downloaded": 20, "duration_seconds": 172, "status": "completed" } } ``` ### Queue Update Event ```json { "type": "queue_updated", "timestamp": "2025-10-13T15:45:00.000Z", "data": { "action": "added", "item": { "id": 2734, "platform": "tiktok", "source": "evalongoria", "status": "pending" } } } ``` ### Log Event ```json { "type": "log", "timestamp": "2025-10-13T15:45:23.456Z", "data": { "level": "INFO", "module": "Instagram", "message": "Started downloading posts from evalongoria" } } ``` ### System Notification Event ```json { "type": "notification", "timestamp": "2025-10-13T15:48:15.123Z", "data": { "level": "success", "title": "Download Complete", "message": "Downloaded 20 posts from evalongoria", "action": { "label": "View Downloads", "link": "/history?source=evalongoria" }, "auto_dismiss_seconds": 5 } } ``` --- ## Error Responses All errors follow this format: ```json { "detail": "Error message", "error_code": "SPECIFIC_ERROR_CODE", "timestamp": "2025-10-13T15:45:23.456Z", "request_id": "uuid-here" } ``` ### Common HTTP Status Codes - `200 OK` - Success - `201 Created` - Resource created - `202 Accepted` - Request accepted (async) - `204 No Content` - Success with no response body - `400 Bad Request` - Invalid input - `401 Unauthorized` - Authentication required - `403 Forbidden` - Insufficient permissions - `404 Not Found` - Resource not found - `409 Conflict` - Resource conflict (duplicate) - `422 Unprocessable Entity` - Validation error - `429 Too Many Requests` - Rate limit exceeded - `500 Internal Server Error` - Server error - `503 Service Unavailable` - Service temporarily unavailable --- ## Rate Limiting **Headers:** ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1697203200 ``` **Limits:** - Public endpoints: 100 requests/hour - Authenticated endpoints: 1000 requests/hour - WebSocket connections: 10 per user --- ## Pagination All list endpoints support pagination: **Request:** ``` GET /downloads?page=2&per_page=50 ``` **Response Headers:** ``` X-Total-Count: 1885 X-Page: 2 X-Per-Page: 50 X-Total-Pages: 38 Link: ; rel="first", ; rel="next" ```