Update app.py
Browse files
app.py
CHANGED
|
@@ -284,34 +284,39 @@ def process_video_frames_and_upload(extracted_rar_folder: str, processed_video_c
|
|
| 284 |
|
| 285 |
log_message(f"π¬ Processing videos in extracted RAR folder: {course_folder_name}")
|
| 286 |
|
| 287 |
-
|
| 288 |
for root, _, files in os.walk(extracted_rar_folder):
|
| 289 |
for file in files:
|
| 290 |
-
|
| 291 |
-
|
|
|
|
| 292 |
|
| 293 |
-
if not
|
| 294 |
-
log_message(f"β οΈ No
|
| 295 |
return False # Indicate no video processing was done
|
| 296 |
|
| 297 |
course_video_extract_dir = os.path.join(VIDEO_FRAMES_EXTRACT_FOLDER, course_folder_name)
|
| 298 |
os.makedirs(course_video_extract_dir, exist_ok=True)
|
| 299 |
|
| 300 |
-
|
| 301 |
-
|
|
|
|
| 302 |
# Create a unique output folder for frames from this video within the course's frame directory
|
| 303 |
video_output_folder = os.path.join(course_video_extract_dir, video_basename)
|
| 304 |
|
| 305 |
-
if
|
| 306 |
-
|
|
|
|
|
|
|
| 307 |
# Clean up partially extracted frames for this video
|
| 308 |
if os.path.exists(video_output_folder):
|
| 309 |
shutil.rmtree(video_output_folder)
|
| 310 |
|
| 311 |
# Check if any frames were extracted for the entire course folder
|
| 312 |
-
if
|
| 313 |
log_message(f"β οΈ No frames extracted for any video in {course_folder_name}. Skipping zipping and upload to BG3.")
|
| 314 |
-
|
|
|
|
| 315 |
return False
|
| 316 |
|
| 317 |
course_zip_path = os.path.join(ZIPPED_FRAMES_FOLDER, f"{course_folder_name}_frames.zip")
|
|
@@ -345,24 +350,32 @@ def extract_and_upload_rar(rar_path: str, processed_rars_set: set, uploaded_fold
|
|
| 345 |
current_extract_folder = os.path.join(EXTRACT_FOLDER, f"{folder_name}_extracted")
|
| 346 |
|
| 347 |
# Check if RAR is already processed (uploaded to BG2 or video frames processed)
|
| 348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
log_message(f"β© {filename} already fully processed, skipping.")
|
| 350 |
return True
|
| 351 |
|
| 352 |
-
# Generate folder name and hash for tracking
|
| 353 |
-
folder_hash = get_folder_hash(folder_name)
|
| 354 |
-
|
| 355 |
# If BG2 upload is enabled and folder already uploaded to BG2, skip RAR extraction/upload to BG2
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
#
|
| 361 |
-
if not os.path.exists(current_extract_folder):
|
| 362 |
-
log_message(f"β οΈ Extracted folder {current_extract_folder} not found for video processing.
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
|
| 367 |
log_message(f"π¦ Attempting to extract: {filename}")
|
| 368 |
os.makedirs(current_extract_folder, exist_ok=True)
|
|
@@ -399,31 +412,50 @@ def extract_and_upload_rar(rar_path: str, processed_rars_set: set, uploaded_fold
|
|
| 399 |
log_message(f"β¬οΈ Uploading to BG2: {path_in_repo}")
|
| 400 |
|
| 401 |
try:
|
| 402 |
-
upload_file_to_hf(
|
| 403 |
local_path=local_path,
|
| 404 |
path_in_repo=path_in_repo,
|
| 405 |
repo_id=DEST_REPO_ID_RAR
|
| 406 |
-
)
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
except Exception as upload_error:
|
| 409 |
log_message(f"β Failed to upload {path_in_repo} to BG2: {upload_error}")
|
| 410 |
-
raise
|
| 411 |
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
|
|
|
| 420 |
else:
|
| 421 |
log_message("Skipping upload to BG2 as DEST_REPO_ID_RAR is not set.")
|
| 422 |
|
| 423 |
# Now process video frames from the extracted content and upload to BG3
|
| 424 |
-
process_video_frames_and_upload(current_extract_folder, processed_video_courses_set)
|
| 425 |
|
| 426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
|
| 428 |
except subprocess.CalledProcessError as e:
|
| 429 |
error_msg = f"RAR extraction failed (exit {e.returncode}): {e.stderr.strip()}"
|
|
@@ -471,49 +503,51 @@ def continuous_processing(start_download_index: Optional[int] = None):
|
|
| 471 |
downloaded_rar_paths, next_download_index = download_rar_files(download_start_index, CHUNK_SIZE)
|
| 472 |
save_download_state(next_download_index)
|
| 473 |
|
| 474 |
-
if not downloaded_rar_paths:
|
| 475 |
-
# Check if there are any local RAR files to process
|
| 476 |
-
all_local_rars = sorted([os.path.join(DOWNLOAD_FOLDER, f) for f in os.listdir(DOWNLOAD_FOLDER) if f.endswith(".rar")])
|
| 477 |
-
processed_rars = load_processed_files_state()
|
| 478 |
-
unprocessed_rars = [rar for rar in all_local_rars if os.path.basename(rar) not in processed_rars]
|
| 479 |
-
|
| 480 |
-
if not unprocessed_rars:
|
| 481 |
-
log_message("β
No more RAR files to download. Stopping...")
|
| 482 |
-
break
|
| 483 |
-
else:
|
| 484 |
-
log_message(f"π Found {len(unprocessed_rars)} unprocessed local RAR files")
|
| 485 |
-
|
| 486 |
# 2. Process all available RAR files (downloaded + existing)
|
| 487 |
all_local_rars = sorted([os.path.join(DOWNLOAD_FOLDER, f) for f in os.listdir(DOWNLOAD_FOLDER) if f.endswith(".rar")])
|
| 488 |
processed_rars = load_processed_files_state()
|
| 489 |
processing_status["total_files"] = len(all_local_rars)
|
|
|
|
| 490 |
processing_status["processed_files"] = len(processed_rars)
|
| 491 |
|
|
|
|
|
|
|
| 492 |
for rar_file_path in all_local_rars:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
if not processing_status["is_running"]:
|
| 494 |
break
|
| 495 |
|
| 496 |
filename = os.path.basename(rar_file_path)
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
save_processed_files_state(processed_rars)
|
| 502 |
-
processing_status["processed_files"] += 1
|
| 503 |
-
|
| 504 |
-
# Delete the RAR file after successful processing
|
| 505 |
-
log_message(f"ποΈ Deleting processed RAR: {filename}")
|
| 506 |
-
try:
|
| 507 |
-
os.remove(rar_file_path)
|
| 508 |
-
log_message(f"β
Deleted RAR file: {filename}")
|
| 509 |
-
except Exception as e:
|
| 510 |
-
log_message(f"β οΈ Could not delete {rar_file_path}: {e}")
|
| 511 |
|
| 512 |
-
#
|
| 513 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 514 |
|
| 515 |
# If no new files were downloaded and all local files are processed, we're done
|
| 516 |
-
if not downloaded_rar_paths:
|
| 517 |
break
|
| 518 |
|
| 519 |
except Exception as e:
|
|
@@ -531,8 +565,8 @@ async def root():
|
|
| 531 |
<html>
|
| 532 |
<head>
|
| 533 |
<title>RAR & Video Processing Service</title>
|
| 534 |
-
<meta charset
|
| 535 |
-
<meta name
|
| 536 |
<style>
|
| 537 |
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
|
| 538 |
.container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
@@ -546,59 +580,59 @@ async def root():
|
|
| 546 |
.stats { display: flex; gap: 20px; margin: 20px 0; }
|
| 547 |
.stat-item { background: #f0f0f0; padding: 10px; border-radius: 5px; text-align: center; flex: 1; }
|
| 548 |
.start-form { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 5px; background: #f9f9f9; }
|
| 549 |
-
.start-form input[type
|
| 550 |
.start-form button { padding: 8px 15px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
| 551 |
.start-form button:hover { background: #45a049; }
|
| 552 |
</style>
|
| 553 |
</head>
|
| 554 |
<body>
|
| 555 |
-
<div class
|
| 556 |
<h1>π RAR & Video Processing Service</h1>
|
| 557 |
<p>Automated extraction and upload of RAR files from BG1 to BG2 dataset, and video frame extraction/upload to BG3 dataset</p>
|
| 558 |
|
| 559 |
-
<div class
|
| 560 |
-
<h3>Status: <span id
|
| 561 |
-
<p>Current File: <span id
|
| 562 |
-
<p>Last Update: <span id
|
| 563 |
</div>
|
| 564 |
|
| 565 |
-
<div class
|
| 566 |
-
<div class
|
| 567 |
<h4>Total Files (RARs)</h4>
|
| 568 |
-
<span id
|
| 569 |
</div>
|
| 570 |
-
<div class
|
| 571 |
<h4>Processed (RARs)</h4>
|
| 572 |
-
<span id
|
| 573 |
</div>
|
| 574 |
-
<div class
|
| 575 |
<h4>Uploaded Folders (BG2)</h4>
|
| 576 |
-
<span id
|
| 577 |
</div>
|
| 578 |
-
<div class
|
| 579 |
<h4>Uploaded Video Courses (BG3)</h4>
|
| 580 |
-
<span id
|
| 581 |
</div>
|
| 582 |
-
<div class
|
| 583 |
<h4>Failed</h4>
|
| 584 |
-
<span id
|
| 585 |
</div>
|
| 586 |
</div>
|
| 587 |
|
| 588 |
-
<div class
|
| 589 |
<h3>Start Processing from Specific Download Index</h3>
|
| 590 |
-
<input type
|
| 591 |
-
<button onclick
|
| 592 |
</div>
|
| 593 |
|
| 594 |
<div>
|
| 595 |
-
<button class
|
| 596 |
-
<button class
|
| 597 |
-
<button class
|
| 598 |
</div>
|
| 599 |
|
| 600 |
<h3>Logs</h3>
|
| 601 |
-
<div class
|
| 602 |
</div>
|
| 603 |
|
| 604 |
<script>
|
|
@@ -615,7 +649,7 @@ async def root():
|
|
| 615 |
|
| 616 |
async function startProcessingWithIndex() {
|
| 617 |
const index = document.getElementById(\"start-index-input\").value;
|
| 618 |
-
if (index === "" || isNaN(index)) {
|
| 619 |
alert(\"Please enter a valid number for the start index.\");
|
| 620 |
return;
|
| 621 |
}
|
|
@@ -733,4 +767,6 @@ async def get_processed_video_courses():
|
|
| 733 |
return {"processed_video_course_count": len(processed_video_courses), "course_names": list(processed_video_courses)}
|
| 734 |
|
| 735 |
if __name__ == "__main__":
|
| 736 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|
|
|
|
| 284 |
|
| 285 |
log_message(f"π¬ Processing videos in extracted RAR folder: {course_folder_name}")
|
| 286 |
|
| 287 |
+
video_files_found = []
|
| 288 |
for root, _, files in os.walk(extracted_rar_folder):
|
| 289 |
for file in files:
|
| 290 |
+
# Check for common video file extensions
|
| 291 |
+
if file.lower().endswith(('.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv')):
|
| 292 |
+
video_files_found.append(os.path.join(root, file))
|
| 293 |
|
| 294 |
+
if not video_files_found:
|
| 295 |
+
log_message(f"β οΈ No video files found in {course_folder_name}. Skipping video frame extraction.")
|
| 296 |
return False # Indicate no video processing was done
|
| 297 |
|
| 298 |
course_video_extract_dir = os.path.join(VIDEO_FRAMES_EXTRACT_FOLDER, course_folder_name)
|
| 299 |
os.makedirs(course_video_extract_dir, exist_ok=True)
|
| 300 |
|
| 301 |
+
frames_extracted_count = 0
|
| 302 |
+
for video_path in video_files_found:
|
| 303 |
+
video_basename = os.path.splitext(os.path.basename(video_path))[0]
|
| 304 |
# Create a unique output folder for frames from this video within the course's frame directory
|
| 305 |
video_output_folder = os.path.join(course_video_extract_dir, video_basename)
|
| 306 |
|
| 307 |
+
if extract_frames(video_path, video_output_folder, VIDEO_FRAME_FPS):
|
| 308 |
+
frames_extracted_count += 1
|
| 309 |
+
else:
|
| 310 |
+
log_message(f"β Failed to extract frames from {os.path.basename(video_path)}. Continuing with other videos.")
|
| 311 |
# Clean up partially extracted frames for this video
|
| 312 |
if os.path.exists(video_output_folder):
|
| 313 |
shutil.rmtree(video_output_folder)
|
| 314 |
|
| 315 |
# Check if any frames were extracted for the entire course folder
|
| 316 |
+
if frames_extracted_count == 0:
|
| 317 |
log_message(f"β οΈ No frames extracted for any video in {course_folder_name}. Skipping zipping and upload to BG3.")
|
| 318 |
+
if os.path.exists(course_video_extract_dir):
|
| 319 |
+
shutil.rmtree(course_video_extract_dir)
|
| 320 |
return False
|
| 321 |
|
| 322 |
course_zip_path = os.path.join(ZIPPED_FRAMES_FOLDER, f"{course_folder_name}_frames.zip")
|
|
|
|
| 350 |
current_extract_folder = os.path.join(EXTRACT_FOLDER, f"{folder_name}_extracted")
|
| 351 |
|
| 352 |
# Check if RAR is already processed (uploaded to BG2 or video frames processed)
|
| 353 |
+
# This logic needs to be careful. If BG2 is not set, we only care about video processing.
|
| 354 |
+
# If video processing is not needed, we only care about BG2 upload.
|
| 355 |
+
is_bg2_processed = (not DEST_REPO_ID_RAR) or (get_folder_hash(folder_name) in uploaded_folders_set)
|
| 356 |
+
is_bg3_processed = (folder_name in processed_video_courses_set)
|
| 357 |
+
|
| 358 |
+
if filename in processed_rars_set and is_bg2_processed and is_bg3_processed:
|
| 359 |
log_message(f"β© {filename} already fully processed, skipping.")
|
| 360 |
return True
|
| 361 |
|
|
|
|
|
|
|
|
|
|
| 362 |
# If BG2 upload is enabled and folder already uploaded to BG2, skip RAR extraction/upload to BG2
|
| 363 |
+
# but still proceed to video processing if not already done.
|
| 364 |
+
if DEST_REPO_ID_RAR and get_folder_hash(folder_name) in uploaded_folders_set and not is_bg3_processed:
|
| 365 |
+
log_message(f"π Folder \'{folder_name}\' already uploaded to BG2 (hash: {get_folder_hash(folder_name)[:8]}...), skipping RAR upload.")
|
| 366 |
+
# If the extracted folder doesn't exist, we can't process videos from it.
|
| 367 |
+
# This scenario might happen if the previous run was interrupted after BG2 upload but before video processing cleanup.
|
| 368 |
+
if not os.path.exists(current_extract_folder):
|
| 369 |
+
log_message(f"β οΈ Extracted folder {current_extract_folder} not found for video processing. Attempting re-extraction for video processing.")
|
| 370 |
+
# Fall through to re-extract and process videos
|
| 371 |
+
else:
|
| 372 |
+
# Proceed to video processing if not already done
|
| 373 |
+
log_message(f"Continuing with video processing for {filename}.")
|
| 374 |
+
video_processed = process_video_frames_and_upload(current_extract_folder, processed_video_courses_set)
|
| 375 |
+
if video_processed:
|
| 376 |
+
processed_rars_set.add(filename)
|
| 377 |
+
save_processed_files_state(processed_rars_set)
|
| 378 |
+
return video_processed
|
| 379 |
|
| 380 |
log_message(f"π¦ Attempting to extract: {filename}")
|
| 381 |
os.makedirs(current_extract_folder, exist_ok=True)
|
|
|
|
| 412 |
log_message(f"β¬οΈ Uploading to BG2: {path_in_repo}")
|
| 413 |
|
| 414 |
try:
|
| 415 |
+
if upload_file_to_hf(
|
| 416 |
local_path=local_path,
|
| 417 |
path_in_repo=path_in_repo,
|
| 418 |
repo_id=DEST_REPO_ID_RAR
|
| 419 |
+
):
|
| 420 |
+
upload_count += 1
|
| 421 |
+
else:
|
| 422 |
+
log_message(f"β Failed to upload {path_in_repo} to BG2. Skipping remaining uploads for this RAR.")
|
| 423 |
+
# Consider if you want to fail the whole RAR processing here or continue.
|
| 424 |
+
# For now, we'll continue but log the failure.
|
| 425 |
+
|
| 426 |
except Exception as upload_error:
|
| 427 |
log_message(f"β Failed to upload {path_in_repo} to BG2: {upload_error}")
|
| 428 |
+
# Don't re-raise, allow other files to be attempted
|
| 429 |
|
| 430 |
+
if upload_count > 0: # Only mark as uploaded if at least one file was successfully uploaded
|
| 431 |
+
log_message(f"β
Successfully uploaded {upload_count} files from {filename} to BG2")
|
| 432 |
+
# Mark folder as uploaded to BG2 using hash
|
| 433 |
+
uploaded_folders_set.add(folder_hash)
|
| 434 |
+
save_uploaded_folders(uploaded_folders_set)
|
| 435 |
+
processing_status["uploaded_rar_folders"] = len(uploaded_folders_set)
|
| 436 |
+
log_message(f"π Folder \'{folder_name}\' locked in BG2 repo (hash: {folder_hash[:8]}...)")
|
| 437 |
+
else:
|
| 438 |
+
log_message(f"β οΈ No files were successfully uploaded from {filename} to BG2.")
|
| 439 |
else:
|
| 440 |
log_message("Skipping upload to BG2 as DEST_REPO_ID_RAR is not set.")
|
| 441 |
|
| 442 |
# Now process video frames from the extracted content and upload to BG3
|
| 443 |
+
video_processed = process_video_frames_and_upload(current_extract_folder, processed_video_courses_set)
|
| 444 |
|
| 445 |
+
# Mark RAR as processed only if both BG2 (if enabled) and BG3 processing are successful
|
| 446 |
+
# Or if BG2 is not enabled, only BG3 processing needs to be successful
|
| 447 |
+
if (not DEST_REPO_ID_RAR or (folder_hash in uploaded_folders_set)) and video_processed:
|
| 448 |
+
return True
|
| 449 |
+
elif DEST_REPO_ID_RAR and not (folder_hash in uploaded_folders_set):
|
| 450 |
+
log_message(f"β RAR processing failed for {filename}: BG2 upload was not successful.")
|
| 451 |
+
return False
|
| 452 |
+
elif not video_processed:
|
| 453 |
+
log_message(f"β RAR processing failed for {filename}: Video frame processing was not successful.")
|
| 454 |
+
return False
|
| 455 |
+
else:
|
| 456 |
+
# This case should ideally not be reached if the above logic is exhaustive
|
| 457 |
+
log_message(f"β RAR processing failed for {filename}: Unknown reason.")
|
| 458 |
+
return False
|
| 459 |
|
| 460 |
except subprocess.CalledProcessError as e:
|
| 461 |
error_msg = f"RAR extraction failed (exit {e.returncode}): {e.stderr.strip()}"
|
|
|
|
| 503 |
downloaded_rar_paths, next_download_index = download_rar_files(download_start_index, CHUNK_SIZE)
|
| 504 |
save_download_state(next_download_index)
|
| 505 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
# 2. Process all available RAR files (downloaded + existing)
|
| 507 |
all_local_rars = sorted([os.path.join(DOWNLOAD_FOLDER, f) for f in os.listdir(DOWNLOAD_FOLDER) if f.endswith(".rar")])
|
| 508 |
processed_rars = load_processed_files_state()
|
| 509 |
processing_status["total_files"] = len(all_local_rars)
|
| 510 |
+
# Recalculate processed_files based on actual processed_rars_set to be accurate
|
| 511 |
processing_status["processed_files"] = len(processed_rars)
|
| 512 |
|
| 513 |
+
# Filter out RARs that are already fully processed based on current state
|
| 514 |
+
rars_to_process = []
|
| 515 |
for rar_file_path in all_local_rars:
|
| 516 |
+
filename = os.path.basename(rar_file_path)
|
| 517 |
+
folder_name = filename.replace(".rar", "")
|
| 518 |
+
is_bg2_processed = (not DEST_REPO_ID_RAR) or (get_folder_hash(folder_name) in uploaded_folders)
|
| 519 |
+
is_bg3_processed = (folder_name in processed_video_courses)
|
| 520 |
+
|
| 521 |
+
if not (filename in processed_rars and is_bg2_processed and is_bg3_processed):
|
| 522 |
+
rars_to_process.append(rar_file_path)
|
| 523 |
+
|
| 524 |
+
if not downloaded_rar_paths and not rars_to_process:
|
| 525 |
+
log_message("β
No more RAR files to download or process. Stopping...")
|
| 526 |
+
break
|
| 527 |
+
|
| 528 |
+
for rar_file_path in rars_to_process:
|
| 529 |
if not processing_status["is_running"]:
|
| 530 |
break
|
| 531 |
|
| 532 |
filename = os.path.basename(rar_file_path)
|
| 533 |
+
success = extract_and_upload_rar(rar_file_path, processed_rars, uploaded_folders, processed_video_courses)
|
| 534 |
+
if success:
|
| 535 |
+
# processed_rars.add(filename) is handled inside extract_and_upload_rar now for better atomicity
|
| 536 |
+
# processing_status["processed_files"] += 1 is also handled inside
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
|
| 538 |
+
# Delete the RAR file after successful processing
|
| 539 |
+
log_message(f"ποΈ Deleting processed RAR: {filename}")
|
| 540 |
+
try:
|
| 541 |
+
os.remove(rar_file_path)
|
| 542 |
+
log_message(f"β
Deleted RAR file: {filename}")
|
| 543 |
+
except Exception as e:
|
| 544 |
+
log_message(f"β οΈ Could not delete {rar_file_path}: {e}")
|
| 545 |
+
|
| 546 |
+
# Add delay between processing files
|
| 547 |
+
time.sleep(PROCESSING_DELAY)
|
| 548 |
|
| 549 |
# If no new files were downloaded and all local files are processed, we're done
|
| 550 |
+
if not downloaded_rar_paths and not rars_to_process:
|
| 551 |
break
|
| 552 |
|
| 553 |
except Exception as e:
|
|
|
|
| 565 |
<html>
|
| 566 |
<head>
|
| 567 |
<title>RAR & Video Processing Service</title>
|
| 568 |
+
<meta charset=\"utf-8\">
|
| 569 |
+
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
| 570 |
<style>
|
| 571 |
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
|
| 572 |
.container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
|
|
| 580 |
.stats { display: flex; gap: 20px; margin: 20px 0; }
|
| 581 |
.stat-item { background: #f0f0f0; padding: 10px; border-radius: 5px; text-align: center; flex: 1; }
|
| 582 |
.start-form { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 5px; background: #f9f9f9; }
|
| 583 |
+
.start-form input[type=\"number\"] { width: calc(100% - 120px); padding: 8px; margin-right: 10px; border: 1px solid #ccc; border-radius: 4px; }
|
| 584 |
.start-form button { padding: 8px 15px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
| 585 |
.start-form button:hover { background: #45a049; }
|
| 586 |
</style>
|
| 587 |
</head>
|
| 588 |
<body>
|
| 589 |
+
<div class=\"container\">
|
| 590 |
<h1>π RAR & Video Processing Service</h1>
|
| 591 |
<p>Automated extraction and upload of RAR files from BG1 to BG2 dataset, and video frame extraction/upload to BG3 dataset</p>
|
| 592 |
|
| 593 |
+
<div class=\"status-card\">
|
| 594 |
+
<h3>Status: <span id=\"status\">Stopped</span></h3>
|
| 595 |
+
<p>Current File: <span id=\"current-file\">None</span></p>
|
| 596 |
+
<p>Last Update: <span id=\"last-update\">Never</span></p>
|
| 597 |
</div>
|
| 598 |
|
| 599 |
+
<div class=\"stats\">
|
| 600 |
+
<div class=\"stat-item\">
|
| 601 |
<h4>Total Files (RARs)</h4>
|
| 602 |
+
<span id=\"total-files\">0</span>
|
| 603 |
</div>
|
| 604 |
+
<div class=\"stat-item\">
|
| 605 |
<h4>Processed (RARs)</h4>
|
| 606 |
+
<span id=\"processed-files\">0</span>
|
| 607 |
</div>
|
| 608 |
+
<div class=\"stat-item\">
|
| 609 |
<h4>Uploaded Folders (BG2)</h4>
|
| 610 |
+
<span id=\"uploaded-rar-folders\">0</span>
|
| 611 |
</div>
|
| 612 |
+
<div class=\"stat-item\">
|
| 613 |
<h4>Uploaded Video Courses (BG3)</h4>
|
| 614 |
+
<span id=\"uploaded-video-courses\">0</span>
|
| 615 |
</div>
|
| 616 |
+
<div class=\"stat-item\">
|
| 617 |
<h4>Failed</h4>
|
| 618 |
+
<span id=\"failed-files\">0</span>
|
| 619 |
</div>
|
| 620 |
</div>
|
| 621 |
|
| 622 |
+
<div class=\"start-form\">
|
| 623 |
<h3>Start Processing from Specific Download Index</h3>
|
| 624 |
+
<input type=\"number\" id=\"start-index-input\" placeholder=\"Enter start index (e.g., 0)\" value=\"0\">
|
| 625 |
+
<button onclick=\"startProcessingWithIndex()\">Start from Index</button>
|
| 626 |
</div>
|
| 627 |
|
| 628 |
<div>
|
| 629 |
+
<button class=\"button\" onclick=\"startProcessing()\" id=\"start-btn\">Start Processing (from last saved index)</button>
|
| 630 |
+
<button class=\"button stop-button\" onclick=\"stopProcessing()\" id=\"stop-btn\" disabled>Stop Processing</button>
|
| 631 |
+
<button class=\"button\" onclick=\"refreshStatus()\">Refresh Status</button>
|
| 632 |
</div>
|
| 633 |
|
| 634 |
<h3>Logs</h3>
|
| 635 |
+
<div class=\"logs\" id=\"logs\">Loading...</div>
|
| 636 |
</div>
|
| 637 |
|
| 638 |
<script>
|
|
|
|
| 649 |
|
| 650 |
async function startProcessingWithIndex() {
|
| 651 |
const index = document.getElementById(\"start-index-input\").value;
|
| 652 |
+
if (index === \"\" || isNaN(index)) {
|
| 653 |
alert(\"Please enter a valid number for the start index.\");
|
| 654 |
return;
|
| 655 |
}
|
|
|
|
| 767 |
return {"processed_video_course_count": len(processed_video_courses), "course_names": list(processed_video_courses)}
|
| 768 |
|
| 769 |
if __name__ == "__main__":
|
| 770 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
| 771 |
+
|
| 772 |
+
|