Download app.py from Fred808/VSEEE2: direct link, hf CLI and curl.
- Browser
- Download file 5.86 kB
-
https://huggingface.co/spaces/Fred808/VSEEE2/resolve/main/app.py
- Command line
-
hf download hf://spaces/Fred808/VSEEE2/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Fred808/VSEEE2/resolve/main/app.py
5.86 kB
| from fastapi import FastAPI, UploadFile, File, HTTPException, BackgroundTasks, Query | |
| from fastapi.responses import FileResponse, JSONResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| import os | |
| import shutil | |
| import uuid | |
| import time | |
| from typing import Dict, List, Optional | |
| import threading | |
| import logging | |
| from pathlib import Path | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Import processing functions and variables | |
| from processing_logic import ( | |
| processing_status, | |
| uploaded_mp4s, | |
| log_message, | |
| process_hf_files_background, | |
| UPLOAD_DIRECTORY, | |
| MP4_OUTPUT_FOLDER, | |
| hf_api, | |
| DEFAULT_RAR_LIMIT | |
| ) | |
| app = FastAPI(title="MP4 Processing API", description="API for uploading, processing, and downloading MP4 files") | |
| # Configure CORS | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Define MP4_UPLOAD_FOLDER if not imported from processing_logic | |
| MP4_UPLOAD_FOLDER = os.path.join(UPLOAD_DIRECTORY, "uploads") if 'UPLOAD_DIRECTORY' in globals() else "uploads" | |
| os.makedirs(MP4_UPLOAD_FOLDER, exist_ok=True) | |
| os.makedirs(MP4_OUTPUT_FOLDER, exist_ok=True) | |
| processing_thread = None | |
| # ==== HELPER FUNCTIONS ==== | |
| def save_file(uploaded_file: UploadFile, save_path: str): | |
| os.makedirs(os.path.dirname(save_path), exist_ok=True) | |
| with open(save_path, "wb") as f: | |
| shutil.copyfileobj(uploaded_file.file, f) | |
| def log_request(endpoint: str, params: dict = None): | |
| """Log API requests for debugging""" | |
| logger.info(f"API Request: {endpoint} - Params: {params}") | |
| # === ROUTES === | |
| async def root(): | |
| """API root endpoint""" | |
| return { | |
| "message": "MP4 Processing API", | |
| "version": "1.0.0", | |
| "status": "running", | |
| "endpoints": { | |
| "upload": "POST /upload - Upload MP4 file", | |
| "download": "GET /download?course={course}&file={file} - Download MP4 file", | |
| "list": "GET /list - List uploaded files", | |
| "courses": "GET /courses - List all course folders", | |
| "images": "GET /images/{course_folder:path} - List MP4s in course", | |
| "debug": "GET /debug/structure - Debug file structure" | |
| } | |
| } | |
| async def get_courses(): | |
| """List all top-level course folders.""" | |
| try: | |
| courses = [d.name for d in Path(MP4_OUTPUT_FOLDER).iterdir() if d.is_dir()] | |
| return {"courses": courses, "total": len(courses)} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Failed to list courses: {e}") | |
| async def get_mp4_list(course_folder: str): | |
| """List all MP4 files within a specific course folder.""" | |
| course_path = Path(MP4_OUTPUT_FOLDER) / course_folder | |
| if not course_path.is_dir(): | |
| raise HTTPException(status_code=404, detail="Course folder not found") | |
| try: | |
| mp4_files = [f.name for f in course_path.iterdir() if f.is_file() and f.suffix.lower() == ".mp4"] | |
| return mp4_files | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Failed to list MP4s: {e}") | |
| async def download_mp4(course: str, file: str): | |
| """Download a specific MP4 file from a course folder.""" | |
| file_path = Path(MP4_OUTPUT_FOLDER) / course / file | |
| if not file_path.is_file(): | |
| raise HTTPException(status_code=404, detail="File not found") | |
| return FileResponse(path=file_path, media_type="video/mp4", filename=file) | |
| async def debug_structure(): | |
| """Debug endpoint to inspect the file structure and sizes.""" | |
| mp4_output_folder_path = Path(MP4_OUTPUT_FOLDER) | |
| structure = {} | |
| total_size_bytes = 0 | |
| total_mp4_files = 0 | |
| if not mp4_output_folder_path.exists(): | |
| return JSONResponse(content={ | |
| "mp4_output_folder": str(mp4_output_folder_path), | |
| "folder_exists": False, | |
| "total_mp4_files": 0, | |
| "total_size_bytes": 0, | |
| "structure": {} | |
| }) | |
| for root, dirs, files in os.walk(mp4_output_folder_path): | |
| current_path = Path(root) | |
| relative_path = str(current_path.relative_to(mp4_output_folder_path)) | |
| if relative_path == ".": | |
| relative_path = "/" | |
| structure[relative_path] = { | |
| "directories": [d for d in dirs], | |
| "mp4_files": [], | |
| "other_files": [] | |
| } | |
| for file in files: | |
| file_full_path = current_path / file | |
| file_size = file_full_path.stat().st_size | |
| total_size_bytes += file_size | |
| if file.lower().endswith(".mp4"): | |
| structure[relative_path]["mp4_files"].append({"name": file, "size": file_size}) | |
| total_mp4_files += 1 | |
| else: | |
| structure[relative_path]["other_files"].append({"name": file, "size": file_size}) | |
| return { | |
| "mp4_output_folder": str(mp4_output_folder_path), | |
| "folder_exists": mp4_output_folder_path.exists(), | |
| "total_mp4_files": total_mp4_files, | |
| "total_size_bytes": total_size_bytes, | |
| "structure": structure | |
| } | |
| async def startup_event(): | |
| """Run the processing loop in the background when the API starts""" | |
| global processing_thread | |
| logger.info("Starting up MP4 Processing API...") | |
| if not (processing_thread and processing_thread.is_alive()): | |
| logger.info("🚀 Starting background processing thread...") | |
| processing_thread = threading.Thread(target=process_hf_files_background) | |
| processing_thread.daemon = True | |
| processing_thread.start() | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=8000) |