VeuReu commited on
Commit
bb2010b
·
verified ·
1 Parent(s): e1847a8

Update storage/pending_videos_routers.py

Browse files
Files changed (1) hide show
  1. storage/pending_videos_routers.py +215 -0
storage/pending_videos_routers.py CHANGED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import shutil
4
+
5
+ import sqlite3
6
+
7
+ from pathlib import Path
8
+
9
+ from fastapi import APIRouter, UploadFile, File, Query, HTTPException
10
+ from fastapi.responses import FileResponse, JSONResponse
11
+
12
+
13
+ from storage.files.file_manager import FileManager
14
+ from storage.common import validate_token
15
+
16
+ router = APIRouter(prefix="/peding_videos", tags=["Pending Videos Manager"])
17
+ MEDIA_ROOT = Path("/data/peding_videos")
18
+ file_manager = FileManager(MEDIA_ROOT)
19
+ HF_TOKEN = os.getenv("HF_TOKEN")
20
+
21
+
22
+ @router.delete("/clear_pending_videos", tags=["Pending Videos Manager"])
23
+ def clear_media(token: str = Query(..., description="Token required for authorization")):
24
+ """
25
+ Delete all contents of the /data/peding_videos folder.
26
+ Steps:
27
+ - Validate the token.
28
+ - Ensure the folder exists.
29
+ - Delete all files and subfolders inside /data/peding_videos.
30
+ - Return a JSON response confirming the deletion.
31
+ Warning: This will remove all stored videos, clips, and cast CSV files.
32
+ """
33
+ validate_token(token)
34
+
35
+ if not MEDIA_ROOT.exists() or not MEDIA_ROOT.is_dir():
36
+ raise HTTPException(status_code=404, detail="/data/peding_videos folder does not exist")
37
+
38
+ # Delete contents
39
+ for item in MEDIA_ROOT.iterdir():
40
+ try:
41
+ if item.is_dir():
42
+ shutil.rmtree(item)
43
+ else:
44
+ item.unlink()
45
+ except Exception as e:
46
+ raise HTTPException(status_code=500, detail=f"Failed to delete {item}: {e}")
47
+
48
+ return {"status": "ok", "message": "All peding_videos files deleted successfully"}
49
+
50
+
51
+ @router.post("/upload_peding_video", tags=["Pending Videos Manager"])
52
+ async def upload_video(
53
+ video: UploadFile = File(...),
54
+ token: str = Query(..., description="Token required for authorization")
55
+ ):
56
+ """
57
+ Saves an uploaded video by hashing it with SHA1 and placing it under:
58
+ /data/media/<sha1>/<original_filename>
59
+ Behavior:
60
+ - Compute SHA1 of the uploaded video.
61
+ - Ensure folder structure exists.
62
+ - Delete any existing .mp4 files under sha1.
63
+ - Save the uploaded video in the folder.
64
+ """
65
+ # Read content into memory (needed to compute hash twice)
66
+ file_bytes = await video.read()
67
+
68
+ # Create an in-memory file handler for hashing
69
+ file_handler = io.BytesIO(file_bytes)
70
+
71
+ # Compute SHA1
72
+ try:
73
+ sha1 = file_manager.compute_sha1(file_handler)
74
+ except Exception as exc:
75
+ raise HTTPException(status_code=500, detail=f"SHA1 computation failed: {exc}")
76
+
77
+ # Ensure /data/media exists
78
+ MEDIA_ROOT.mkdir(parents=True, exist_ok=True)
79
+
80
+ # Path: /data/media/<sha1>
81
+ video_root = MEDIA_ROOT / sha1
82
+ video_root.mkdir(parents=True, exist_ok=True)
83
+
84
+ # Delete old MP4 files
85
+ try:
86
+ for old_mp4 in video_root.glob("*.mp4"):
87
+ old_mp4.unlink()
88
+ except Exception as exc:
89
+ raise HTTPException(status_code=500, detail=f"Failed to delete old videos: {exc}")
90
+
91
+ # Save new video path
92
+ final_path = video_root / video.filename
93
+
94
+ # Save file
95
+ save_result = file_manager.upload_file(io.BytesIO(file_bytes), final_path)
96
+
97
+ if not save_result["operation_success"]:
98
+ raise HTTPException(status_code=500, detail=save_result["error"])
99
+
100
+ return JSONResponse(
101
+ status_code=200,
102
+ content={
103
+ "status": "ok",
104
+ "sha1": sha1,
105
+ "saved_to": str(final_path)
106
+ }
107
+ )
108
+
109
+
110
+ @router.get("/download_peding_video", tags=["Pending Videos Manager"])
111
+ def download_video(
112
+ sha1: str,
113
+ token: str = Query(..., description="Token required for authorization")
114
+ ):
115
+ """
116
+ Download a stored video by its SHA-1 directory name.
117
+ This endpoint looks for a video stored under the path:
118
+ /data/media/<sha1>/clip/
119
+ and returns the first MP4 file found in that folder.
120
+ The method performs the following steps:
121
+ - Checks if the SHA-1 folder exists inside the media root.
122
+ - Validates that the "clip" subfolder exists.
123
+ - Searches for the first .mp4 file inside the clip folder.
124
+ - Uses the FileManager.get_file method to ensure the file is accessible.
125
+ - Returns the video directly as a FileResponse.
126
+ Parameters
127
+ ----------
128
+ sha1 : str
129
+ The SHA-1 hash corresponding to the directory where the video is stored.
130
+ Returns
131
+ -------
132
+ FileResponse
133
+ A streaming response containing the MP4 video.
134
+ Raises
135
+ ------
136
+ HTTPException
137
+ - 404 if the SHA-1 folder does not exist.
138
+ - 404 if the clip folder is missing.
139
+ - 404 if no MP4 files are found.
140
+ - 404 if the file cannot be retrieved using FileManager.
141
+ """
142
+ sha1_folder = MEDIA_ROOT / sha1
143
+
144
+ if not sha1_folder.exists() or not sha1_folder.is_dir():
145
+ raise HTTPException(status_code=404, detail="SHA1 folder not found")
146
+
147
+ # Find first MP4 file
148
+ mp4_files = list(sha1_folder.glob("*.mp4"))
149
+ if not mp4_files:
150
+ raise HTTPException(status_code=404, detail="No MP4 files found")
151
+
152
+ video_path = mp4_files[0]
153
+
154
+ # Convert to relative path for FileManager
155
+ relative_path = video_path.relative_to(MEDIA_ROOT)
156
+
157
+ handler = file_manager.get_file(relative_path)
158
+ if handler is None:
159
+ raise HTTPException(status_code=404, detail="Video not accessible")
160
+
161
+ handler.close()
162
+
163
+ return FileResponse(
164
+ path=video_path,
165
+ media_type="video/mp4",
166
+ filename=video_path.name
167
+ )
168
+
169
+ @router.get("/list_peding_videos", tags=["Pending Videos Manager"])
170
+ def list_all_videos(
171
+ token: str = Query(..., description="Token required for authorization")
172
+ ):
173
+ """
174
+ List all videos stored under /data/media.
175
+ For each SHA1 folder, the endpoint returns:
176
+ - sha1: folder name
177
+ - video_files: list of mp4 files inside /clip
178
+ - latest_video: the most recently modified mp4
179
+ - video_count: total number of mp4 files
180
+ Notes:
181
+ - Videos may not have a /clip folder.
182
+ - SHA1 folders without mp4 files are still returned.
183
+ """
184
+ validate_token(token)
185
+
186
+ results = []
187
+
188
+ # If media root does not exist, return empty list
189
+ if not MEDIA_ROOT.exists():
190
+ return []
191
+
192
+ for sha1_dir in MEDIA_ROOT.iterdir():
193
+ if not sha1_dir.is_dir():
194
+ continue # skip non-folders
195
+
196
+ videos = []
197
+ latest_video = None
198
+
199
+ if sha1_dir.exists() and sha1_dir.is_dir():
200
+ mp4_files = list(sha1_dir.glob("*.mp4"))
201
+
202
+ # Sort by modification time (newest first)
203
+ mp4_files.sort(key=lambda f: f.stat().st_mtime, reverse=True)
204
+
205
+ videos = [f.name for f in mp4_files]
206
+
207
+ if mp4_files:
208
+ latest_video = mp4_files[0].name
209
+
210
+ results.append({
211
+ "sha1": sha1_dir.name,
212
+ "video_name": latest_video
213
+ })
214
+
215
+ return results