xplhack1 commited on
Commit
1a721d3
·
verified ·
1 Parent(s): 294eb7e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -40
app.py CHANGED
@@ -1,57 +1,90 @@
1
  import gradio as gr
2
  import os
3
  import subprocess
4
- from huggingface_hub import HfApi, hf_hub_download, list_repo_files
5
  import spaces
6
 
7
  api = HfApi()
8
 
9
  @spaces.GPU
10
- def process_batch_videos(token, source_dataset, target_dataset, folder_path):
11
  if not token or not source_dataset or not target_dataset or not folder_path:
12
- return "❌ Error: Faltan datos obligatorios."
 
13
 
 
 
 
 
 
 
 
14
  try:
15
  folder_path = folder_path.strip().rstrip('/')
 
16
 
17
- # 1. Listar todos los archivos del repo origen
18
  all_files = list_repo_files(repo_id=source_dataset, repo_type="dataset", token=token)
19
 
20
- # Filtrar los archivos mp4 dentro de la carpeta especificada
21
- mp4_files = [
22
  f for f in all_files
23
- if f.startswith(folder_path) and f.endswith('.mp4')
24
  ]
25
 
26
- # Ordenar para consistencia y tomar estrictamente los primeros 3
27
- mp4_files = sorted(mp4_files)[:3]
28
-
29
- if not mp4_files:
30
- return f"⚠️ No se encontraron archivos .mp4 en la ruta: {folder_path}"
31
 
32
- results = []
33
- results.append(f"📁 Encontrados {len(mp4_files)} archivos para procesar (Modo WIP - Primeros 3):")
34
 
35
- for idx, file_path in enumerate(mp4_files, 1):
36
- results.append(f"\n--- Procesando [{idx}/3]: {file_path} ---")
 
 
 
 
 
 
 
 
 
37
 
38
- # Descargar archivo original
39
- local_path = hf_hub_download(
 
40
  repo_id=source_dataset,
41
  filename=file_path,
42
  repo_type="dataset",
43
  token=token
44
  )
45
 
46
- # Procesar con FFmpeg (Remux y Faststart)
47
- output_path = f"video_arreglado_{idx}.mp4"
48
- command = [
49
- "ffmpeg", "-y", "-i", local_path,
50
- "-c", "copy", "-movflags", "+faststart", output_path
51
- ]
52
- subprocess.run(command, check=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- # Subir al dataset destino limpio
 
55
  api.upload_file(
56
  path_or_fileobj=output_path,
57
  path_in_repo=file_path,
@@ -60,22 +93,21 @@ def process_batch_videos(token, source_dataset, target_dataset, folder_path):
60
  token=token
61
  )
62
 
63
- # Limpieza local
64
  if os.path.exists(output_path):
65
  os.remove(output_path)
66
 
67
- results.append(f"✅ ¡Reparado y subido con éxito a {target_dataset}!")
68
 
69
- results.append("\n🎉 ¡Lote de prueba de los primeros 3 completado exitosamente!")
70
- return "\n".join(results)
71
 
72
  except Exception as e:
73
- return f"❌ Algo falló en el proceso por lotes: {str(e)}"
74
 
75
- # Interfaz gráfica adaptada para procesamiento por lotes (WIP)
76
  with gr.Blocks() as demo:
77
- gr.Markdown("# 🛠️ Migrador y Reparador Masivo (Modo WIP - Primeros 3)")
78
- gr.Markdown("Escanea la carpeta, verifica y repara únicamente los primeros 3 archivos MP4 encontrados.")
79
 
80
  token_input = gr.Textbox(label="Tu HF_TOKEN (Con permisos de WRITE)", type="password")
81
 
@@ -84,13 +116,20 @@ with gr.Blocks() as demo:
84
  target_input = gr.Textbox(label="Dataset DESTINO", value="orglatamsrc/latamsrcfixed")
85
 
86
  folder_input = gr.Textbox(
87
- label="Carpeta a escanear",
88
- value="SERIES/EN_EMISION/Rivales_2024/TEMPORADA1"
89
  )
90
 
91
- btn = gr.Button("Verificar y Reparar Primeros 3 🚀", variant="primary")
92
- output = gr.Textbox(label="Estado del proceso / Log", lines=15)
 
 
 
 
 
 
93
 
94
- btn.click(fn=process_batch_videos, inputs=[token_input, source_input, target_input, folder_input], outputs=output)
 
95
 
96
- demo.launch(theme=gr.themes.Soft())
 
1
  import gradio as gr
2
  import os
3
  import subprocess
4
+ from huggingface_hub import HfApi, hf_hub_url, list_repo_files, hf_hub_download
5
  import spaces
6
 
7
  api = HfApi()
8
 
9
  @spaces.GPU
10
+ def process_full_migration(token, source_dataset, target_dataset, folder_path):
11
  if not token or not source_dataset or not target_dataset or not folder_path:
12
+ yield "❌ Error: Faltan datos obligatorios."
13
+ return
14
 
15
+ log_output = ""
16
+ def log(msg):
17
+ nonlocal log_output
18
+ log_output += msg + "\n"
19
+ print(msg, flush=True)
20
+ yield log_output
21
+
22
  try:
23
  folder_path = folder_path.strip().rstrip('/')
24
+ yield from log(f"🔍 Escaneando archivos de video (.mp4 y .mkv) en toda la ruta: {folder_path}...")
25
 
 
26
  all_files = list_repo_files(repo_id=source_dataset, repo_type="dataset", token=token)
27
 
28
+ video_files = [
 
29
  f for f in all_files
30
+ if f.startswith(folder_path) and (f.endswith('.mp4') or f.endswith('.mkv'))
31
  ]
32
 
33
+ total_files = len(video_files)
34
+ if total_files == 0:
35
+ yield from log(f"⚠️ No se encontraron archivos de video en la ruta: {folder_path}")
36
+ return
 
37
 
38
+ yield from log(f"📁 ¡Se encontraron {total_files} videos en total para verificar y migrar!\n")
 
39
 
40
+ for idx, file_path in enumerate(video_files, 1):
41
+ yield from log(f"==================================================")
42
+ yield from log(f"🎬 Procesando [{idx}/{total_files}]: {file_path}")
43
+ yield from log(f"==================================================")
44
+
45
+ is_mkv = file_path.endswith('.mkv')
46
+ temp_local_path = "temp_download.mkv" if is_mkv else "temp_download.mp4"
47
+ output_ext = ".mkv" if is_mkv else ".mp4"
48
+ output_path = f"video_arreglado{output_ext}"
49
+
50
+ file_url = hf_hub_url(repo_id=source_dataset, filename=file_path, repo_type="dataset")
51
 
52
+ # Descarga estándar por caché de Hugging Face (se aloja temporalmente en el disco local de la VPS)
53
+ yield from log("📥 Descargando archivo al disco local de la VPS...")
54
+ temp_local_path = hf_hub_download(
55
  repo_id=source_dataset,
56
  filename=file_path,
57
  repo_type="dataset",
58
  token=token
59
  )
60
 
61
+ # Procesar con FFmpeg
62
+ if is_mkv:
63
+ yield from log("⚙️ Verificando y limpiando contenedor MKV con FFmpeg (-c copy)...")
64
+ command = [
65
+ "ffmpeg", "-y", "-i", temp_local_path,
66
+ "-c", "copy", output_path
67
+ ]
68
+ else:
69
+ yield from log("⚙️ Aplicando fix moov atom a MP4/TS con FFmpeg (-c copy -movflags +faststart)...")
70
+ command = [
71
+ "ffmpeg", "-y", "-i", temp_local_path,
72
+ "-c", "copy", "-movflags", "+faststart", output_path
73
+ ]
74
+
75
+ try:
76
+ subprocess.run(command, check=True)
77
+ except subprocess.CalledProcessError:
78
+ yield from log("⚠️ ¡Aviso! El copiado directo falló debido a corrupción interna en el archivo. Intentando re-codificación de emergencia...")
79
+ if is_mkv:
80
+ command_fallback = ["ffmpeg", "-y", "-i", temp_local_path, output_path]
81
+ else:
82
+ command_fallback = ["ffmpeg", "-y", "-i", temp_local_path, "-movflags", "+faststart", output_path]
83
+ subprocess.run(command_fallback, check=True)
84
+ yield from log("✅ Re-codificación de emergencia completada con éxito.")
85
 
86
+ # Subir el archivo resultante limpio al dataset de destino
87
+ yield from log(f"☁️ Subiendo video optimizado a {target_dataset} ({file_path})...")
88
  api.upload_file(
89
  path_or_fileobj=output_path,
90
  path_in_repo=file_path,
 
93
  token=token
94
  )
95
 
96
+ # Limpieza local exhaustiva del disco temporal generado
97
  if os.path.exists(output_path):
98
  os.remove(output_path)
99
 
100
+ yield from log(f"🎉 ¡Video [{idx}/{total_files}] procesado y subido con éxito!\n")
101
 
102
+ yield from log("🏆 ¡Recorrido masivo total finalizado! Ningún archivo fue omitido y todos están limpios.")
 
103
 
104
  except Exception as e:
105
+ yield from log(f"❌ Error crítico en el recorrido: {str(e)}")
106
 
107
+ # Interfaz gráfica de control total con botón de Cancelar/Detener
108
  with gr.Blocks() as demo:
109
+ gr.Markdown("# 🛠️ Migrador y Reparador Masivo Total (.MP4, .MKV y Fakes TS)")
110
+ gr.Markdown("Recorre de forma recursiva todas las temporadas, descarga al disco local, repara fallos y migra limpio a tu organización.")
111
 
112
  token_input = gr.Textbox(label="Tu HF_TOKEN (Con permisos de WRITE)", type="password")
113
 
 
116
  target_input = gr.Textbox(label="Dataset DESTINO", value="orglatamsrc/latamsrcfixed")
117
 
118
  folder_input = gr.Textbox(
119
+ label="Carpeta principal a escanear",
120
+ value="SERIES/EN_EMISION/Rivales_2024"
121
  )
122
 
123
+ with gr.Row():
124
+ btn = gr.Button("Iniciar Migración Masiva Total 🔥", variant="primary")
125
+ stop_btn = gr.Button("Detener Proceso ⏹️", variant="stop")
126
+
127
+ output = gr.Textbox(label="Consola de Logs en Tiempo Real", lines=22)
128
+
129
+ # Evento de inicio del proceso
130
+ watcher = btn.click(fn=process_full_migration, inputs=[token_input, source_input, target_input, folder_input], outputs=output)
131
 
132
+ # Evento del botón de detener para cancelar la ejecución al instante si lo deseas
133
+ stop_btn.click(fn=None, inputs=None, outputs=None, cancels=[watcher])
134
 
135
+ demo.launch(theme=gr.themes.Soft(), server_name="0.0.0.0", server_port=7860)