Spaces:
Sleeping
Sleeping
Update server.py
Browse files
server.py
CHANGED
|
@@ -195,7 +195,7 @@ async def load_progress_file() -> Dict:
|
|
| 195 |
return progress
|
| 196 |
except Exception as e:
|
| 197 |
print(f"⊘ No existing progress file or load failed: {str(e)[:100]}")
|
| 198 |
-
return {"compressed": [], "failed": [], "last_updated": datetime.now().isoformat()}
|
| 199 |
|
| 200 |
|
| 201 |
async def save_progress_file(progress: Dict):
|
|
@@ -238,8 +238,46 @@ async def scan_and_compress_videos():
|
|
| 238 |
compressed_files = {item["path"] for item in progress.get("compressed", [])}
|
| 239 |
failed_files = progress.get("failed", [])
|
| 240 |
failed_paths = {item["path"] for item in failed_files}
|
|
|
|
|
|
|
| 241 |
|
| 242 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
|
| 244 |
print("\n" + "="*80)
|
| 245 |
print("RETRYING PREVIOUSLY FAILED FILES")
|
|
@@ -264,6 +302,16 @@ async def scan_and_compress_videos():
|
|
| 264 |
"file_name": failed_item["file_name"]
|
| 265 |
}
|
| 266 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
try:
|
| 268 |
# Download
|
| 269 |
print(f"\nRetrying: {video_info['path']}")
|
|
@@ -307,8 +355,8 @@ async def scan_and_compress_videos():
|
|
| 307 |
compression_state["total_uploaded"] += 1
|
| 308 |
compression_state["total_space_saved_mb"] += compression_stats["saved_mb"]
|
| 309 |
|
| 310 |
-
# Remove from
|
| 311 |
-
progress["
|
| 312 |
progress["compressed"].append({
|
| 313 |
"path": video_info["path"],
|
| 314 |
"file_name": video_info["file_name"],
|
|
@@ -329,13 +377,18 @@ async def scan_and_compress_videos():
|
|
| 329 |
|
| 330 |
except Exception as e:
|
| 331 |
print(f"✗ Retry failed: {e}")
|
| 332 |
-
#
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
|
| 340 |
# Save progress after each retry attempt
|
| 341 |
await save_progress_file(progress)
|
|
@@ -378,6 +431,11 @@ async def scan_and_compress_videos():
|
|
| 378 |
print(f" ⊘ {f.split('/')[-1]} (queued for retry next scan)")
|
| 379 |
continue
|
| 380 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
try:
|
| 382 |
# Parse file path: ready_videos/moviename/segment-XX.mp4
|
| 383 |
parts = f.split("/")
|
|
@@ -405,6 +463,15 @@ async def scan_and_compress_videos():
|
|
| 405 |
for video_info in video_files:
|
| 406 |
compression_state["current_video"] = video_info["file_name"]
|
| 407 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
try:
|
| 409 |
# Download
|
| 410 |
print(f"\nDownloading: {video_info['path']}")
|
|
@@ -463,7 +530,8 @@ async def scan_and_compress_videos():
|
|
| 463 |
compression_state["total_uploaded"] += 1
|
| 464 |
compression_state["total_space_saved_mb"] += compression_stats["saved_mb"]
|
| 465 |
|
| 466 |
-
#
|
|
|
|
| 467 |
progress["compressed"].append({
|
| 468 |
"path": video_info["path"],
|
| 469 |
"file_name": video_info["file_name"],
|
|
@@ -485,10 +553,13 @@ async def scan_and_compress_videos():
|
|
| 485 |
except Exception as e:
|
| 486 |
print(f"✗ Error: {e}")
|
| 487 |
compression_state["last_error"] = str(e)
|
|
|
|
|
|
|
| 488 |
progress["failed"].append({
|
| 489 |
"path": video_info["path"],
|
| 490 |
"file_name": video_info["file_name"],
|
| 491 |
"error": str(e),
|
|
|
|
| 492 |
"timestamp": datetime.now().isoformat()
|
| 493 |
})
|
| 494 |
await save_progress_file(progress)
|
|
@@ -573,6 +644,21 @@ async def get_status():
|
|
| 573 |
})
|
| 574 |
|
| 575 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 576 |
@app.post("/scan")
|
| 577 |
async def trigger_scan():
|
| 578 |
"""Manually trigger a scan and compression run."""
|
|
|
|
| 195 |
return progress
|
| 196 |
except Exception as e:
|
| 197 |
print(f"⊘ No existing progress file or load failed: {str(e)[:100]}")
|
| 198 |
+
return {"compressed": [], "failed": [], "processing": [], "last_updated": datetime.now().isoformat()}
|
| 199 |
|
| 200 |
|
| 201 |
async def save_progress_file(progress: Dict):
|
|
|
|
| 238 |
compressed_files = {item["path"] for item in progress.get("compressed", [])}
|
| 239 |
failed_files = progress.get("failed", [])
|
| 240 |
failed_paths = {item["path"] for item in failed_files}
|
| 241 |
+
processing_files = progress.get("processing", [])
|
| 242 |
+
processing_paths = {item["path"] for item in processing_files}
|
| 243 |
|
| 244 |
+
# Clean up stale processing files (>4 hours old = likely crashed server)
|
| 245 |
+
print("\n" + "="*80)
|
| 246 |
+
print("CHECKING FOR STALE PROCESSING FILES")
|
| 247 |
+
print("="*80)
|
| 248 |
+
|
| 249 |
+
current_time = datetime.now()
|
| 250 |
+
stale_threshold = 4 * 3600 # 4 hours in seconds
|
| 251 |
+
stale_files = []
|
| 252 |
+
|
| 253 |
+
for processing_item in processing_files:
|
| 254 |
+
started_at = datetime.fromisoformat(processing_item["started_at"])
|
| 255 |
+
elapsed_seconds = (current_time - started_at).total_seconds()
|
| 256 |
+
|
| 257 |
+
if elapsed_seconds > stale_threshold:
|
| 258 |
+
print(f" ⚠ {processing_item['file_name']} (stale, {elapsed_seconds/3600:.1f}h old)")
|
| 259 |
+
stale_files.append(processing_item)
|
| 260 |
+
|
| 261 |
+
# Move stale files back to failed for retry
|
| 262 |
+
if stale_files:
|
| 263 |
+
print(f"\nRecovering {len(stale_files)} stale processing files...")
|
| 264 |
+
for stale_item in stale_files:
|
| 265 |
+
progress["processing"] = [f for f in progress["processing"] if f["path"] != stale_item["path"]]
|
| 266 |
+
progress["failed"].append({
|
| 267 |
+
"path": stale_item["path"],
|
| 268 |
+
"file_name": stale_item["file_name"],
|
| 269 |
+
"error": "Server crash detected (stale processing)",
|
| 270 |
+
"retry_count": 0,
|
| 271 |
+
"timestamp": datetime.now().isoformat()
|
| 272 |
+
})
|
| 273 |
+
await save_progress_file(progress)
|
| 274 |
+
# Reload processing paths after cleanup
|
| 275 |
+
processing_files = progress.get("processing", [])
|
| 276 |
+
processing_paths = {item["path"] for item in processing_files}
|
| 277 |
+
else:
|
| 278 |
+
print("✓ No stale processing files")
|
| 279 |
+
|
| 280 |
+
print(f"Current state: {len(compressed_files)} compressed, {len(failed_files)} failed, {len(processing_paths)} processing")
|
| 281 |
|
| 282 |
print("\n" + "="*80)
|
| 283 |
print("RETRYING PREVIOUSLY FAILED FILES")
|
|
|
|
| 302 |
"file_name": failed_item["file_name"]
|
| 303 |
}
|
| 304 |
|
| 305 |
+
# Mark as processing
|
| 306 |
+
progress["failed"] = [f for f in progress["failed"] if f["path"] != video_info["path"]]
|
| 307 |
+
progress["processing"].append({
|
| 308 |
+
"path": video_info["path"],
|
| 309 |
+
"file_name": video_info["file_name"],
|
| 310 |
+
"status": "retrying",
|
| 311 |
+
"started_at": datetime.now().isoformat()
|
| 312 |
+
})
|
| 313 |
+
await save_progress_file(progress)
|
| 314 |
+
|
| 315 |
try:
|
| 316 |
# Download
|
| 317 |
print(f"\nRetrying: {video_info['path']}")
|
|
|
|
| 355 |
compression_state["total_uploaded"] += 1
|
| 356 |
compression_state["total_space_saved_mb"] += compression_stats["saved_mb"]
|
| 357 |
|
| 358 |
+
# Remove from processing and add to compressed
|
| 359 |
+
progress["processing"] = [f for f in progress["processing"] if f["path"] != video_info["path"]]
|
| 360 |
progress["compressed"].append({
|
| 361 |
"path": video_info["path"],
|
| 362 |
"file_name": video_info["file_name"],
|
|
|
|
| 377 |
|
| 378 |
except Exception as e:
|
| 379 |
print(f"✗ Retry failed: {e}")
|
| 380 |
+
# Remove from processing and re-add to failed with incremented retry count
|
| 381 |
+
progress["processing"] = [f for f in progress["processing"] if f["path"] != video_info["path"]]
|
| 382 |
+
retry_count = failed_item.get("retry_count", 0) + 1
|
| 383 |
+
progress["failed"].append({
|
| 384 |
+
"path": video_info["path"],
|
| 385 |
+
"file_name": video_info["file_name"],
|
| 386 |
+
"error": str(e),
|
| 387 |
+
"retry_count": retry_count,
|
| 388 |
+
"last_error": str(e),
|
| 389 |
+
"last_attempt": datetime.now().isoformat(),
|
| 390 |
+
"timestamp": failed_item.get("timestamp", datetime.now().isoformat())
|
| 391 |
+
})
|
| 392 |
|
| 393 |
# Save progress after each retry attempt
|
| 394 |
await save_progress_file(progress)
|
|
|
|
| 431 |
print(f" ⊘ {f.split('/')[-1]} (queued for retry next scan)")
|
| 432 |
continue
|
| 433 |
|
| 434 |
+
# Skip if currently being processed by another server
|
| 435 |
+
if f in processing_paths:
|
| 436 |
+
print(f" ⟳ {f.split('/')[-1]} (currently processing)")
|
| 437 |
+
continue
|
| 438 |
+
|
| 439 |
try:
|
| 440 |
# Parse file path: ready_videos/moviename/segment-XX.mp4
|
| 441 |
parts = f.split("/")
|
|
|
|
| 463 |
for video_info in video_files:
|
| 464 |
compression_state["current_video"] = video_info["file_name"]
|
| 465 |
|
| 466 |
+
# Mark as processing
|
| 467 |
+
progress["processing"].append({
|
| 468 |
+
"path": video_info["path"],
|
| 469 |
+
"file_name": video_info["file_name"],
|
| 470 |
+
"status": "compressing",
|
| 471 |
+
"started_at": datetime.now().isoformat()
|
| 472 |
+
})
|
| 473 |
+
await save_progress_file(progress)
|
| 474 |
+
|
| 475 |
try:
|
| 476 |
# Download
|
| 477 |
print(f"\nDownloading: {video_info['path']}")
|
|
|
|
| 530 |
compression_state["total_uploaded"] += 1
|
| 531 |
compression_state["total_space_saved_mb"] += compression_stats["saved_mb"]
|
| 532 |
|
| 533 |
+
# Remove from processing and add to compressed
|
| 534 |
+
progress["processing"] = [f for f in progress["processing"] if f["path"] != video_info["path"]]
|
| 535 |
progress["compressed"].append({
|
| 536 |
"path": video_info["path"],
|
| 537 |
"file_name": video_info["file_name"],
|
|
|
|
| 553 |
except Exception as e:
|
| 554 |
print(f"✗ Error: {e}")
|
| 555 |
compression_state["last_error"] = str(e)
|
| 556 |
+
# Remove from processing and add to failed
|
| 557 |
+
progress["processing"] = [f for f in progress["processing"] if f["path"] != video_info["path"]]
|
| 558 |
progress["failed"].append({
|
| 559 |
"path": video_info["path"],
|
| 560 |
"file_name": video_info["file_name"],
|
| 561 |
"error": str(e),
|
| 562 |
+
"retry_count": 0,
|
| 563 |
"timestamp": datetime.now().isoformat()
|
| 564 |
})
|
| 565 |
await save_progress_file(progress)
|
|
|
|
| 644 |
})
|
| 645 |
|
| 646 |
|
| 647 |
+
@app.get("/progress")
|
| 648 |
+
async def get_progress():
|
| 649 |
+
"""Get full progress file state with counts and details."""
|
| 650 |
+
progress = await load_progress_file()
|
| 651 |
+
return JSONResponse({
|
| 652 |
+
"compressed_count": len(progress.get("compressed", [])),
|
| 653 |
+
"failed_count": len(progress.get("failed", [])),
|
| 654 |
+
"processing_count": len(progress.get("processing", [])),
|
| 655 |
+
"compressed": progress.get("compressed", []),
|
| 656 |
+
"failed": progress.get("failed", []),
|
| 657 |
+
"processing": progress.get("processing", []),
|
| 658 |
+
"last_updated": progress.get("last_updated")
|
| 659 |
+
})
|
| 660 |
+
|
| 661 |
+
|
| 662 |
@app.post("/scan")
|
| 663 |
async def trigger_scan():
|
| 664 |
"""Manually trigger a scan and compression run."""
|