pcdoido2 commited on
Commit
0dc9869
·
verified ·
1 Parent(s): 1d9f898

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -92
app.py CHANGED
@@ -305,96 +305,112 @@ if st.button("Gerar Vídeo(s)"):
305
  "-of", "default=noprint_wrappers=1:nokey=1", video_final_raw
306
  ], stdout=subprocess.PIPE)
307
  dur_video_real = float(dur_proc.stdout.decode().strip())
308
- progresso.progress(35 + n * 5)
309
-
310
- # Filtros no vídeo principal (zoom, espelho, borda, etc.)
311
- filtros_main = ["scale=720:1280:force_original_aspect_ratio=decrease"]
312
- if zoom != 1.0:
313
- filtros_main.append(f"scale=iw*{zoom}:ih*{zoom}")
314
- filtros_main.append(f"setpts=PTS/{velocidade_cortes}")
315
- if ativar_espelhar:
316
- filtros_main.append("hflip")
317
- if remover_borda and tamanho_borda > 0:
318
- filtros_main.append(f"crop=in_w-{tamanho_borda*2}:in_h-{tamanho_borda*2}")
319
- if ativar_filtro_cor:
320
- filtros_main.append("eq=contrast=1.1:saturation=1.2")
321
- if ativar_borda_personalizada:
322
- cor_ffmpeg = f"0x{cor_borda.lstrip('#')}FF"
323
- anim_map = {
324
- "Nenhuma": "",
325
- "Borda Pulsante": "enable='lt(mod(t,1),0.5)'",
326
- "Cor Animada": "enable='lt(mod(t,1),0.5)'",
327
- "Neon": "enable='lt(mod(t,0.5),0.25)'",
328
- "Ondulada": "enable='gt(sin(t*3.14),0)'"
329
- }
330
- drawbox = f"drawbox=x=0:y=0:w=iw:h=ih:color={cor_ffmpeg}:t=5"
331
- if anim_map[animacao_borda]:
332
- drawbox += f":{anim_map[animacao_borda]}"
333
- filtros_main.append(drawbox)
334
-
335
- # Fundo com filtros
336
- filtro_complex = f"[0:v]scale=720:1280:force_original_aspect_ratio=increase,crop=720:1280"
337
- if ativar_blur_fundo:
338
- filtro_complex += f",boxblur={blur_strength}:1"
339
- if ativar_sepia:
340
- filtro_complex += ",colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131"
341
- if ativar_granulado:
342
- filtro_complex += ",noise=alls=20:allf=t+u"
343
- if ativar_pb:
344
- filtro_complex += ",hue=s=0.3"
345
- if ativar_vignette:
346
- filtro_complex += ",vignette"
347
- filtro_complex += "[blur];[1:v]" + ",".join(filtros_main) + "[zoomed];[blur][zoomed]overlay=(W-w)/2:(H-h)/2[base]"
348
-
349
- if ativar_texto and texto_personalizado.strip():
350
- y_pos = "100" if posicao_texto == "Topo" else "(h-text_h)/2" if posicao_texto == "Centro" else "h-text_h-100"
351
- enable = f":enable='lt(t\\,{segundos_texto})'" if duracao_texto == "Apenas primeiros segundos" else ""
352
- texto_clean = texto_personalizado.replace(":", "\\:").replace("'", "\\'")
353
- filtro_complex += f";[base]drawtext=text='{texto_clean}':fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:fontcolor={cor_texto}:fontsize={tamanho_texto}:shadowcolor={cor_sombra}:shadowx=3:shadowy=3:x=(w-text_w)/2:y={y_pos}{enable}[final]"
354
  else:
355
- filtro_complex += ";[base]null[final]"
356
-
357
- video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
358
- subprocess.run([
359
- "ffmpeg", "-i", fundo_cortado, "-i", video_raw,
360
- "-filter_complex", filtro_complex,
361
- "-map", "[final]", "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
362
- video_editado
363
- ], check=True, stderr=subprocess.PIPE)
364
-
365
- # Acelerar vídeo final (sem áudio)
366
- video_acelerado = os.path.join(temp_dir, f"video_acelerado_{n}.mp4")
367
- subprocess.run([
368
- "ffmpeg", "-y", "-i", video_editado, "-an",
369
- "-filter:v", f"setpts=PTS/{velocidade_final}",
370
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
371
- video_acelerado
372
- ], check=True, stderr=subprocess.PIPE)
373
-
374
- progresso.progress(70)
375
-
376
- # Tutorial no meio (se enviado)
377
- video_final_raw = video_acelerado
378
- if video_tutorial:
379
- dur_proc = subprocess.run([
380
- "ffprobe", "-v", "error", "-show_entries", "format=duration",
381
- "-of", "default=noprint_wrappers=1:nokey=1", video_acelerado
382
- ], stdout=subprocess.PIPE)
383
- dur_f = float(dur_proc.stdout.decode().strip())
384
- pt = dur_f / 2 if dur_f < 10 else random.uniform(5, dur_f - 5)
385
- part1 = os.path.join(temp_dir, f"part1_{n}.mp4")
386
- part2 = os.path.join(temp_dir, f"part2_{n}.mp4")
387
- subprocess.run(["ffmpeg", "-i", video_acelerado, "-ss", "0", "-t", str(pt), "-c:v", "libx264", "-preset", "ultrafast", part1], check=True, stderr=subprocess.PIPE)
388
- subprocess.run(["ffmpeg", "-i", video_acelerado, "-ss", str(pt), "-c:v", "libx264", "-preset", "ultrafast", part2], check=True, stderr=subprocess.PIPE)
389
- final_txt = os.path.join(temp_dir, f"final_{n}.txt")
390
- with open(final_txt, "w") as f:
391
- f.write(f"file '{part1}'\nfile '{tutorial_mp4}'\nfile '{part2}'\n")
392
- video_final_raw = os.path.join(temp_dir, f"video_final_raw_{n}.mp4")
393
- subprocess.run(["ffmpeg", "-f", "concat", "-safe", "0", "-i", final_txt, "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value), video_final_raw], check=True, stderr=subprocess.PIPE)
394
-
395
- # 🎵 Música final
396
- dur_proc = subprocess.run([
397
- "ffprobe", "-v", "error", "-show_entries", "format=duration",
398
- "-of", "default=noprint_wrappers=1:nokey=1", video_final_raw
399
- ], stdout=subprocess.PIPE)
400
- dur_video_real = float(dur_proc.stdout.decode().strip())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  "-of", "default=noprint_wrappers=1:nokey=1", video_final_raw
306
  ], stdout=subprocess.PIPE)
307
  dur_video_real = float(dur_proc.stdout.decode().strip())
308
+ if musica:
309
+ musica_path = os.path.join(temp_dir, "musica_original.mp3")
310
+ with open(musica_path, "wb") as f:
311
+ f.write(musica.read())
312
+ musica_cortada = os.path.join(temp_dir, f"musica_cortada_{n}.aac")
313
+ subprocess.run([
314
+ "ffmpeg", "-i", musica_path, "-ss", "0", "-t", str(dur_video_real),
315
+ "-vn", "-acodec", "aac", "-y", musica_cortada
316
+ ], check=True, stderr=subprocess.PIPE)
317
+ final_name = f"video_final_{n}_{int(time.time())}.mp4"
318
+ subprocess.run([
319
+ "ffmpeg", "-i", video_final_raw, "-i", musica_cortada,
320
+ "-map", "0:v:0", "-map", "1:a:0",
321
+ "-c:v", "copy", "-c:a", "aac",
322
+ "-shortest", final_name
323
+ ], check=True, stderr=subprocess.PIPE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  else:
325
+ final_name = f"video_final_{n}_{int(time.time())}.mp4"
326
+ shutil.copy(video_final_raw, final_name)
327
+
328
+ # 🔒 APLICAR ANTI-FLOP NO FINAL
329
+ if ativar_antiflop:
330
+ st.info(f"🔒 Aplicando Anti-Flop no vídeo {n+1}...")
331
+
332
+ # ➡️ Anti-Flop filtros:
333
+ encoder_name = f"{fingerprint}Cam_{random.randint(1000,9999)}"
334
+ antiflop_out = f"antiflop_{n}_{int(time.time())}.mp4"
335
+
336
+ vf_af = (
337
+ f"scale=iw*{zoom_af}:ih*{zoom_af},"
338
+ f"crop=iw/{zoom_af}:ih/{zoom_af},"
339
+ f"eq=brightness={brilho_af}:contrast={contraste_af}:saturation={saturacao_af},"
340
+ f"noise=alls={ruido_af}:allf=t,"
341
+ f"rotate={rotacao_af}*PI/180:c=black@0.0,"
342
+ "scale=trunc(iw/2)*2:trunc(ih/2)*2" # Garante resolução par
343
+ )
344
+ if usar_marca:
345
+ vf_af += f",drawtext=text='{encoder_name}':fontcolor=white@0.005:x=10:y=10:fontsize=24"
346
+ if usar_glitch:
347
+ vf_af += ",blackframe=1:0"
348
+ if transicoes:
349
+ effects = [
350
+ "fade=t=in:st=0:d=0.5",
351
+ "fade=t=out:st=3:d=0.5",
352
+ "zoompan=z='min(pzoom+0.0015,1.5)':d=1",
353
+ "drawbox=x=0:y=0:w=iw:h=ih:color=white@0.02:t=fill"
354
+ ]
355
+ vf_af += "," + random.choice(effects)
356
+
357
+ af = f"asetrate=44100*{pitch_af},aresample=44100"
358
+ profile = "baseline" if fingerprint in ["Android", "Xiaomi"] else "main"
359
+ if fingerprint == "iPhone":
360
+ profile = "high"
361
+ level = "4.0" if fingerprint == "Samsung" else "3.1"
362
+ ar = "44100" if fingerprint in ["iPhone", "Xiaomi"] else "48000"
363
+
364
+ subprocess.run([
365
+ 'ffmpeg', '-i', final_name,
366
+ '-vf', vf_af,
367
+ '-af', af,
368
+ '-r', str(fps_af),
369
+ '-c:v', 'libx264', '-profile:v', profile, '-level', level,
370
+ '-b:v', f"{bitrate_af}k", '-ar', ar,
371
+ '-preset', 'fast', '-tune', 'zerolatency',
372
+ '-movflags', '+faststart',
373
+ antiflop_out
374
+ ], check=True)
375
+
376
+ videos_gerados.append(antiflop_out)
377
+ st.video(antiflop_out)
378
+ with open(antiflop_out, "rb") as f:
379
+ st.download_button(f"📥 Baixar vídeo {n+1} Anti-Flop", f, file_name=antiflop_out)
380
+ else:
381
+ videos_gerados.append(final_name)
382
+ st.video(final_name)
383
+ with open(final_name, "rb") as f:
384
+ st.download_button(f"📥 Baixar vídeo {n+1}", f, file_name=final_name)
385
+
386
+ progresso.progress(100)
387
+ st.success("✅ Todos os vídeos foram gerados com sucesso!")
388
+
389
+ except subprocess.CalledProcessError as e:
390
+ st.error(f"❌ Erro ao gerar vídeo:\n\n{e.stderr.decode(errors='ignore')}")
391
+
392
+ finally:
393
+ shutil.rmtree(temp_dir)
394
+
395
+ # ➡️ Fora do try-finally: Botão "Baixar Todos os Vídeos"
396
+ if videos_gerados:
397
+ st.markdown("### 📥 Baixar Todos os Vídeos")
398
+ download_links = ""
399
+ for v in videos_gerados:
400
+ download_links += f"<a href='{v}' download='{v}'></a>\n"
401
+
402
+ st.markdown(
403
+ f"""
404
+ <button onclick="baixarTodos()">📥 Baixar Todos</button>
405
+ <script>
406
+ function baixarTodos() {{
407
+ const links = Array.from(document.querySelectorAll('a[download]'));
408
+ for (let l of links) {{
409
+ l.click();
410
+ }}
411
+ }}
412
+ </script>
413
+ {download_links}
414
+ """,
415
+ unsafe_allow_html=True
416
+ )