understanding commited on
Commit
5e53604
·
verified ·
1 Parent(s): ea30679

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -0
app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import httpx
2
+ import ffmpeg
3
+ import os
4
+ import sqlite3
5
+ import uvicorn
6
+ import uuid
7
+ from fastapi import FastAPI, BackgroundTasks
8
+ from pydantic import BaseModel
9
+ from starlette.responses import FileResponse, JSONResponse
10
+
11
+ # --- Configuration ---
12
+ app = FastAPI()
13
+ DOWNLOAD_DIR = "downloads"
14
+ ENCODED_DIR = "encoded"
15
+ DB_FILE = "jobs.db"
16
+ os.makedirs(DOWNLOAD_DIR, exist_ok=True)
17
+ os.makedirs(ENCODED_DIR, exist_ok=True)
18
+ # ---------------------
19
+
20
+ # --- Database Setup ---
21
+ def get_db():
22
+ conn = sqlite3.connect(DB_FILE)
23
+ conn.row_factory = sqlite3.Row
24
+ return conn
25
+
26
+ def init_db():
27
+ with get_db() as conn:
28
+ conn.execute('''
29
+ CREATE TABLE IF NOT EXISTS jobs (
30
+ task_id TEXT PRIMARY KEY,
31
+ status TEXT NOT NULL,
32
+ file_name TEXT,
33
+ error_message TEXT
34
+ )
35
+ ''')
36
+ conn.commit()
37
+
38
+ # --- Background Re-encoding Task ---
39
+ def process_video_task(url: str, task_id: str):
40
+ db = get_db()
41
+ temp_in_path = os.path.join(DOWNLOAD_DIR, f"{task_id}_in.mp4")
42
+ temp_out_path = os.path.join(ENCODED_DIR, f"{task_id}_out.mp4")
43
+
44
+ try:
45
+ # 1. Update DB: Downloading
46
+ db.execute("UPDATE jobs SET status = 'downloading' WHERE task_id = ?", (task_id,))
47
+ db.commit()
48
+
49
+ with httpx.stream("GET", url, follow_redirects=True, timeout=600.0) as r:
50
+ r.raise_for_status()
51
+ with open(temp_in_path, 'wb') as f:
52
+ for chunk in r.iter_bytes(chunk_size=8192):
53
+ f.write(chunk)
54
+
55
+ # 2. Update DB: Encoding
56
+ db.execute("UPDATE jobs SET status = 'encoding' WHERE task_id = ?", (task_id,))
57
+ db.commit()
58
+
59
+ # ⚠️ THIS IS THE 100% CPU RE-ENCODE YOU WANTED ⚠️
60
+ (
61
+ ffmpeg
62
+ .input(temp_in_path)
63
+ .output(temp_out_path, vcodec='libx264', crf=23, acodec='aac', movflags='+faststart')
64
+ .run(capture_stdout=True, capture_stderr=True)
65
+ )
66
+
67
+ # 3. Update DB: Complete
68
+ final_file_name = f"{task_id}_out.mp4"
69
+ db.execute("UPDATE jobs SET status = 'complete', file_name = ? WHERE task_id = ?", (final_file_name, task_id))
70
+ db.commit()
71
+
72
+ except Exception as e:
73
+ error_msg = str(e)
74
+ if hasattr(e, 'stderr'): # Get error from ffmpeg
75
+ error_msg = e.stderr.decode()
76
+ print(f"Error processing task {task_id}: {error_msg}")
77
+ db.execute("UPDATE jobs SET status = 'error', error_message = ? WHERE task_id = ?", (error_msg, task_id))
78
+ db.commit()
79
+ finally:
80
+ if os.path.exists(temp_in_path):
81
+ os.remove(temp_in_path)
82
+ db.close()
83
+
84
+ # --- API Endpoints ---
85
+ class VideoRequest(BaseModel):
86
+ url: str
87
+
88
+ @app.post("/process")
89
+ async def start_processing(request: VideoRequest, background_tasks: BackgroundTasks):
90
+ """ START the encoding job. """
91
+ task_id = str(uuid.uuid4())
92
+
93
+ with get_db() as db:
94
+ db.execute("INSERT INTO jobs (task_id, status) VALUES (?, 'queued')", (task_id,))
95
+ db.commit()
96
+
97
+ background_tasks.add_task(process_video_task, request.url, task_id)
98
+ return {"status": "queued", "task_id": task_id}
99
+
100
+ @app.get("/status/{task_id}")
101
+ async def get_status(task_id: str):
102
+ """ CHECK the status of the encoding job. """
103
+ with get_db() as db:
104
+ job = db.execute("SELECT * FROM jobs WHERE task_id = ?", (task_id,)).fetchone()
105
+
106
+ if not job:
107
+ return JSONResponse(status_code=404, content={"status": "not_found"})
108
+
109
+ return dict(job) # Convert DB row to a dict
110
+
111
+ @app.get("/download/{file_name}")
112
+ async def download_file(file_name: str):
113
+ """ DOWNLOAD the final re-encoded file. """
114
+ file_path = os.path.join(ENCODED_DIR, file_name)
115
+ if not os.path.exists(file_path):
116
+ return JSONResponse(status_code=404, content={"status": "file_not_found"})
117
+
118
+ return FileResponse(file_path, media_type='video/mp4', filename=file_name)
119
+
120
+ # --- Server Start ---
121
+ @app.on_event("startup")
122
+ async def startup_event():
123
+ init_db() # Create the database and table on startup
124
+ print("Database initialized.")
125
+
126
+ if __name__ == "__main__":
127
+ uvicorn.run(app, host="0.0.0.0", port=7860)