File size: 5,860 Bytes
298adbb 1c1d58b 298adbb 1c1d58b 298adbb 1c1d58b 298adbb 1c1d58b 298adbb 001c6f2 1c1d58b 001c6f2 298adbb 001c6f2 298adbb 1c1d58b 298adbb 001c6f2 1c1d58b 001c6f2 1c1d58b 001c6f2 1c1d58b 001c6f2 298adbb 1c1d58b 298adbb 1c1d58b 001c6f2 1c1d58b 001c6f2 1c1d58b 001c6f2 1c1d58b 298adbb 1c1d58b 298adbb 001c6f2 1c1d58b 001c6f2 1c1d58b 001c6f2 1c1d58b 298adbb 1c1d58b 298adbb 1c1d58b 298adbb 001c6f2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
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 ===
@app.get("/")
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"
}
}
@app.get("/courses")
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}")
@app.get("/images/{course_folder:path}")
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}")
@app.get("/download")
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)
@app.get("/debug/structure")
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
}
@app.on_event("startup")
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) |