Update app.py
Browse files
app.py
CHANGED
|
@@ -21,7 +21,6 @@ for cat in CATEGORIAS:
|
|
| 21 |
os.makedirs(os.path.join(BASE_ASSETS, cat, "cortes"), exist_ok=True)
|
| 22 |
os.makedirs(os.path.join(BASE_ASSETS, cat, "tutoriais"), exist_ok=True)
|
| 23 |
os.makedirs(os.path.join(BASE_SALVOS, cat), exist_ok=True)
|
| 24 |
-
|
| 25 |
if pagina == "🎬 Gerador de Vídeo":
|
| 26 |
st.title("🎥 TikTok Video Generator - PRO")
|
| 27 |
|
|
@@ -57,7 +56,7 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 57 |
zoom = st.slider("Zoom", 1.0, 2.0, 1.0, 0.1)
|
| 58 |
blur_strength = st.slider("Blur no fundo", 1, 50, 10)
|
| 59 |
velocidade_final = st.slider("Velocidade final", 0.5, 2.0, 1.0, 0.1)
|
| 60 |
-
crf_value =
|
| 61 |
|
| 62 |
st.write("## Texto no Vídeo")
|
| 63 |
ativar_texto = st.checkbox("Ativar texto")
|
|
@@ -80,24 +79,7 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 80 |
with st.expander("🎨 Filtros Avançados"):
|
| 81 |
ativar_brilho = st.checkbox("Brilho extra")
|
| 82 |
ativar_contraste = st.checkbox("Contraste forte")
|
| 83 |
-
ativar_colorboost = st.checkbox("Cores
|
| 84 |
-
ativar_azul = st.checkbox("Filtro Azul")
|
| 85 |
-
ativar_quente = st.checkbox("Filtro Quente")
|
| 86 |
-
ativar_desaturar = st.checkbox("Desaturar")
|
| 87 |
-
ativar_vhs = st.checkbox("Efeito VHS")
|
| 88 |
-
|
| 89 |
-
st.write("## Outros efeitos")
|
| 90 |
-
ativar_espelhar = st.checkbox("Espelhar", True)
|
| 91 |
-
ativar_filtro_cor = st.checkbox("Ajuste de cor", True)
|
| 92 |
-
remover_borda = st.checkbox("Remover borda")
|
| 93 |
-
tamanho_borda = st.slider("Tamanho da borda (px)", 0, 200, 0, 5)
|
| 94 |
-
|
| 95 |
-
ativar_borda_personalizada = st.checkbox("Borda personalizada")
|
| 96 |
-
if ativar_borda_personalizada:
|
| 97 |
-
cor_borda = st.color_picker("Cor da borda", "#FF0000")
|
| 98 |
-
animacao_borda = st.selectbox("Animação", ["Nenhuma", "Pulsante", "Cor Animada", "Neon", "Ondulada"])
|
| 99 |
-
|
| 100 |
-
salvar_no_gerenciador = st.checkbox("Salvar no gerenciador de arquivos")
|
| 101 |
if st.button("Gerar Vídeo(s)", key="gerar_video_usuario"):
|
| 102 |
with st.spinner("🎬 Processando..."):
|
| 103 |
progresso = st.progress(0)
|
|
@@ -139,7 +121,7 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 139 |
ativar_blur_fundo_n = ativar_blur_fundo
|
| 140 |
ativar_espelhar_n = ativar_espelhar
|
| 141 |
|
| 142 |
-
#
|
| 143 |
if usar_fundo:
|
| 144 |
fundo_origem = random.choice(cortes_names)
|
| 145 |
fundo_convertido = os.path.join(temp_dir, f"fundo_convertido_{n}.mp4")
|
|
@@ -159,20 +141,20 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 159 |
"-vf",
|
| 160 |
"scale='if(gt(iw/ih,720/1280),max(720,iw),-2)':'if(gt(iw/ih,720/1280),-2,max(1280,ih))',"
|
| 161 |
"scale=720:1280:force_original_aspect_ratio=increase,crop=720:1280,fps=30",
|
| 162 |
-
"-preset", "
|
| 163 |
fundo_convertido
|
| 164 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 165 |
else:
|
| 166 |
fundo_convertido = os.path.join(temp_dir, f"fundo_vazio_{n}.mp4")
|
| 167 |
subprocess.run([
|
| 168 |
"ffmpeg", "-f", "lavfi", "-i", f"color=color=black:size=720x1280:d={duracao_final}:rate=30",
|
| 169 |
-
"-c:v", "libx264", "-t", str(duracao_final), "-preset", "
|
| 170 |
fundo_convertido
|
| 171 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 172 |
etapa_atual += 1
|
| 173 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 174 |
|
| 175 |
-
#
|
| 176 |
tentativas = 0
|
| 177 |
while tempo_total < duracao_final and tentativas < 100:
|
| 178 |
tentativas += 1
|
|
@@ -197,7 +179,7 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 197 |
subprocess.run([
|
| 198 |
"ffmpeg", "-ss", str(ini), "-i", c, "-t", str(duracao_aleatoria),
|
| 199 |
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
|
| 200 |
-
"-an", "-c:v", "libx264", "-preset", "
|
| 201 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 202 |
cortes_prontos.append(out)
|
| 203 |
cortes_usados.append((c, ini, duracao_aleatoria))
|
|
@@ -215,96 +197,45 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 215 |
video_raw = os.path.join(temp_dir, f"video_raw_{n}.mp4")
|
| 216 |
subprocess.run([
|
| 217 |
"ffmpeg", "-f", "concat", "-safe", "0", "-i", lista,
|
| 218 |
-
"-c:v", "libx264", "-preset", "
|
| 219 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 220 |
-
|
| 221 |
etapa_atual += 1
|
| 222 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 223 |
|
| 224 |
-
#
|
| 225 |
-
filtros_main = ["scale=720:1280:force_original_aspect_ratio=decrease"]
|
| 226 |
-
if zoom_n != 1.0:
|
| 227 |
-
filtros_main.append(f"scale=iw*{zoom_n}:ih*{zoom_n}")
|
| 228 |
-
if ativar_espelhar_n:
|
| 229 |
-
filtros_main.append("hflip")
|
| 230 |
-
if remover_borda_n and tamanho_borda_n > 0:
|
| 231 |
-
filtros_main.append(f"crop=in_w-{tamanho_borda_n*2}:in_h-{tamanho_borda_n*2}")
|
| 232 |
-
if ativar_filtro_cor:
|
| 233 |
-
filtros_main.append("eq=contrast=1.1:saturation=1.2")
|
| 234 |
-
filtros_main.append("scale=trunc(iw/2)*2:trunc(ih/2)*2")
|
| 235 |
-
if ativar_borda_personalizada:
|
| 236 |
-
cor_ffmpeg = f"0x{cor_borda.lstrip('#')}FF"
|
| 237 |
-
filtros_main.append(f"drawbox=x=0:y=0:w=iw:h=ih:color={cor_ffmpeg}:t=5")
|
| 238 |
-
|
| 239 |
-
filtro_complex = f"[0:v]scale=720:1280:force_original_aspect_ratio=increase,crop=720:1280"
|
| 240 |
-
if ativar_blur_fundo_n:
|
| 241 |
-
filtro_complex += f",boxblur={blur_strength_n}:1"
|
| 242 |
-
if ativar_sepia:
|
| 243 |
-
filtro_complex += ",colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131"
|
| 244 |
-
if ativar_granulado:
|
| 245 |
-
filtro_complex += ",noise=alls=20:allf=t+u"
|
| 246 |
-
if ativar_pb:
|
| 247 |
-
filtro_complex += ",hue=s=0.3"
|
| 248 |
-
if ativar_vignette:
|
| 249 |
-
filtro_complex += ",vignette"
|
| 250 |
-
if ativar_brilho:
|
| 251 |
-
filtro_complex += ",eq=brightness=0.05"
|
| 252 |
-
if ativar_contraste:
|
| 253 |
-
filtro_complex += ",eq=contrast=1.3"
|
| 254 |
-
if ativar_colorboost:
|
| 255 |
-
filtro_complex += ",eq=saturation=1.5"
|
| 256 |
-
if ativar_azul:
|
| 257 |
-
filtro_complex += ",colorbalance=bs=0.5"
|
| 258 |
-
if ativar_quente:
|
| 259 |
-
filtro_complex += ",colorbalance=rs=0.3"
|
| 260 |
-
if ativar_desaturar:
|
| 261 |
-
filtro_complex += ",hue=s=0.5"
|
| 262 |
-
if ativar_vhs:
|
| 263 |
-
filtro_complex += ",noise=alls=10:allf=t+u,format=yuv420p"
|
| 264 |
-
|
| 265 |
-
filtro_complex += "[blur];"
|
| 266 |
-
filtro_complex += f"[1:v]{','.join(filtros_main)}[zoomed];"
|
| 267 |
-
filtro_complex += "[blur][zoomed]overlay=(W-w)/2:(H-h)/2[base]"
|
| 268 |
-
|
| 269 |
-
if ativar_texto and texto_personalizado.strip():
|
| 270 |
-
y_pos = "100" if posicao_texto == "Topo" else "(h-text_h)/2" if posicao_texto == "Centro" else "h-text_h-100"
|
| 271 |
-
enable = f":enable='lt(t\\,{segundos_texto})'" if duracao_texto == "Apenas primeiros segundos" else ""
|
| 272 |
-
texto_clean = texto_personalizado.replace(":", "\\:").replace("'", "\\'")
|
| 273 |
-
filtro_complex += f";[base]drawtext=text='{texto_clean}':"
|
| 274 |
-
filtro_complex += (
|
| 275 |
-
f"fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:"
|
| 276 |
-
f"fontcolor={cor_texto}:fontsize={tamanho_texto}:"
|
| 277 |
-
f"shadowcolor={cor_sombra}:shadowx=3:shadowy=3:"
|
| 278 |
-
f"x=(w-text_w)/2:y={y_pos}{enable}[final]"
|
| 279 |
-
)
|
| 280 |
-
else:
|
| 281 |
-
filtro_complex += ";[base]null[final]"
|
| 282 |
-
|
| 283 |
video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
|
| 284 |
subprocess.run([
|
| 285 |
"ffmpeg", "-i", fundo_convertido, "-i", video_raw,
|
| 286 |
"-filter_complex", filtro_complex,
|
| 287 |
"-map", "[final]",
|
| 288 |
-
"-c:v", "libx264", "-preset", "
|
| 289 |
video_editado
|
| 290 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 291 |
|
| 292 |
etapa_atual += 1
|
| 293 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 294 |
|
| 295 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
if usar_tutorial and tutorials_salvos:
|
| 297 |
tutorial_path = random.choice(tutorials_salvos)
|
| 298 |
tutorial_mp4 = os.path.join(temp_dir, f"tutorial_conv_{n}.mp4")
|
| 299 |
subprocess.run([
|
| 300 |
"ffmpeg", "-i", tutorial_path, "-vf", "scale=720:1280,fps=30",
|
| 301 |
-
"-c:v", "libx264", "-preset", "
|
| 302 |
"-y", tutorial_mp4
|
| 303 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 304 |
|
| 305 |
dur_proc = subprocess.run([
|
| 306 |
"ffprobe", "-v", "error", "-show_entries", "format=duration",
|
| 307 |
-
"-of", "default=noprint_wrappers=1:nokey=1",
|
| 308 |
], stdout=subprocess.PIPE)
|
| 309 |
dur_f = float(dur_proc.stdout.decode().strip() or 0)
|
| 310 |
pt = dur_f / 2 if dur_f < 10 else random.uniform(5, dur_f - 5)
|
|
@@ -312,11 +243,11 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 312 |
part1 = os.path.join(temp_dir, f"part1_{n}.mp4")
|
| 313 |
part2 = os.path.join(temp_dir, f"part2_{n}.mp4")
|
| 314 |
|
| 315 |
-
subprocess.run(["ffmpeg", "-i",
|
| 316 |
-
"-c:v", "libx264", "-preset", "
|
| 317 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 318 |
-
subprocess.run(["ffmpeg", "-i",
|
| 319 |
-
"-c:v", "libx264", "-preset", "
|
| 320 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 321 |
|
| 322 |
final_txt = os.path.join(temp_dir, f"final_{n}.txt")
|
|
@@ -325,25 +256,17 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 325 |
|
| 326 |
video_final_raw = os.path.join(temp_dir, f"video_final_raw_{n}.mp4")
|
| 327 |
subprocess.run(["ffmpeg", "-f", "concat", "-safe", "0", "-i", final_txt,
|
| 328 |
-
"-c:v", "libx264", "-preset", "
|
| 329 |
video_final_raw], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 330 |
else:
|
| 331 |
-
video_final_raw =
|
| 332 |
etapa_atual += 1
|
| 333 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 334 |
|
| 335 |
-
#
|
| 336 |
-
video_com_velocidade = os.path.join(temp_dir, f"video_com_velocidade_{n}.mp4")
|
| 337 |
-
subprocess.run([
|
| 338 |
-
"ffmpeg", "-y", "-i", video_final_raw, "-an",
|
| 339 |
-
"-filter:v", f"setpts=PTS/{velocidade_final_n}",
|
| 340 |
-
"-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
|
| 341 |
-
video_com_velocidade
|
| 342 |
-
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 343 |
-
|
| 344 |
dur_final_str = subprocess.run([
|
| 345 |
"ffprobe", "-v", "error", "-show_entries", "format=duration",
|
| 346 |
-
"-of", "default=noprint_wrappers=1:nokey=1",
|
| 347 |
], stdout=subprocess.PIPE).stdout.decode().strip()
|
| 348 |
if not dur_final_str:
|
| 349 |
continue
|
|
@@ -357,12 +280,12 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 357 |
"-vn", "-acodec", "aac", "-y", musica_cortada],
|
| 358 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 359 |
|
| 360 |
-
subprocess.run(["ffmpeg", "-i",
|
| 361 |
"-map", "0:v:0", "-map", "1:a:0",
|
| 362 |
"-c:v", "copy", "-c:a", "aac", "-shortest", final_name],
|
| 363 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 364 |
else:
|
| 365 |
-
shutil.copy(
|
| 366 |
|
| 367 |
if salvar_no_gerenciador:
|
| 368 |
destino = os.path.join(BASE_SALVOS, categoria_selecionada, final_name)
|
|
@@ -377,7 +300,6 @@ if pagina == "🎬 Gerador de Vídeo":
|
|
| 377 |
st.error(f"❌ Erro inesperado: {str(e)}")
|
| 378 |
finally:
|
| 379 |
shutil.rmtree(temp_dir)
|
| 380 |
-
|
| 381 |
# ======================== GERENCIADOR ========================
|
| 382 |
elif pagina == "📂 Gerenciador de Arquivos":
|
| 383 |
st.header("📂 Vídeos Salvos por Categoria")
|
|
@@ -419,7 +341,6 @@ elif pagina == "📂 Gerenciador de Arquivos":
|
|
| 419 |
os.remove(file_path)
|
| 420 |
st.success(f"❌ Arquivo '{file}' excluído.")
|
| 421 |
st.rerun()
|
| 422 |
-
|
| 423 |
# ======================== ADMIN ========================
|
| 424 |
elif pagina == "🔐 Admin":
|
| 425 |
st.title("🔐 Área de Administração")
|
|
@@ -469,7 +390,7 @@ elif pagina == "🔐 Admin":
|
|
| 469 |
subprocess.run([
|
| 470 |
"ffmpeg", "-i", temp,
|
| 471 |
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,fps=30",
|
| 472 |
-
"-c:v", "libx264", "-preset", "
|
| 473 |
"-y", final
|
| 474 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 475 |
else:
|
|
|
|
| 21 |
os.makedirs(os.path.join(BASE_ASSETS, cat, "cortes"), exist_ok=True)
|
| 22 |
os.makedirs(os.path.join(BASE_ASSETS, cat, "tutoriais"), exist_ok=True)
|
| 23 |
os.makedirs(os.path.join(BASE_SALVOS, cat), exist_ok=True)
|
|
|
|
| 24 |
if pagina == "🎬 Gerador de Vídeo":
|
| 25 |
st.title("🎥 TikTok Video Generator - PRO")
|
| 26 |
|
|
|
|
| 56 |
zoom = st.slider("Zoom", 1.0, 2.0, 1.0, 0.1)
|
| 57 |
blur_strength = st.slider("Blur no fundo", 1, 50, 10)
|
| 58 |
velocidade_final = st.slider("Velocidade final", 0.5, 2.0, 1.0, 0.1)
|
| 59 |
+
crf_value = 18 # ✅ fixado em 18 para melhor qualidade
|
| 60 |
|
| 61 |
st.write("## Texto no Vídeo")
|
| 62 |
ativar_texto = st.checkbox("Ativar texto")
|
|
|
|
| 79 |
with st.expander("🎨 Filtros Avançados"):
|
| 80 |
ativar_brilho = st.checkbox("Brilho extra")
|
| 81 |
ativar_contraste = st.checkbox("Contraste forte")
|
| 82 |
+
ativar_colorboost = st.checkbox("Cores i_
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
if st.button("Gerar Vídeo(s)", key="gerar_video_usuario"):
|
| 84 |
with st.spinner("🎬 Processando..."):
|
| 85 |
progresso = st.progress(0)
|
|
|
|
| 121 |
ativar_blur_fundo_n = ativar_blur_fundo
|
| 122 |
ativar_espelhar_n = ativar_espelhar
|
| 123 |
|
| 124 |
+
# ======================== ETAPA 1 - Fundo ========================
|
| 125 |
if usar_fundo:
|
| 126 |
fundo_origem = random.choice(cortes_names)
|
| 127 |
fundo_convertido = os.path.join(temp_dir, f"fundo_convertido_{n}.mp4")
|
|
|
|
| 141 |
"-vf",
|
| 142 |
"scale='if(gt(iw/ih,720/1280),max(720,iw),-2)':'if(gt(iw/ih,720/1280),-2,max(1280,ih))',"
|
| 143 |
"scale=720:1280:force_original_aspect_ratio=increase,crop=720:1280,fps=30",
|
| 144 |
+
"-preset", "veryfast", "-crf", "18",
|
| 145 |
fundo_convertido
|
| 146 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 147 |
else:
|
| 148 |
fundo_convertido = os.path.join(temp_dir, f"fundo_vazio_{n}.mp4")
|
| 149 |
subprocess.run([
|
| 150 |
"ffmpeg", "-f", "lavfi", "-i", f"color=color=black:size=720x1280:d={duracao_final}:rate=30",
|
| 151 |
+
"-c:v", "libx264", "-t", str(duracao_final), "-preset", "veryfast", "-crf", "18",
|
| 152 |
fundo_convertido
|
| 153 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 154 |
etapa_atual += 1
|
| 155 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 156 |
|
| 157 |
+
# ======================== ETAPA 2 - Cortes ========================
|
| 158 |
tentativas = 0
|
| 159 |
while tempo_total < duracao_final and tentativas < 100:
|
| 160 |
tentativas += 1
|
|
|
|
| 179 |
subprocess.run([
|
| 180 |
"ffmpeg", "-ss", str(ini), "-i", c, "-t", str(duracao_aleatoria),
|
| 181 |
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
|
| 182 |
+
"-an", "-c:v", "libx264", "-preset", "veryfast", "-crf", "18", out
|
| 183 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 184 |
cortes_prontos.append(out)
|
| 185 |
cortes_usados.append((c, ini, duracao_aleatoria))
|
|
|
|
| 197 |
video_raw = os.path.join(temp_dir, f"video_raw_{n}.mp4")
|
| 198 |
subprocess.run([
|
| 199 |
"ffmpeg", "-f", "concat", "-safe", "0", "-i", lista,
|
| 200 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", "18", video_raw
|
| 201 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
|
|
| 202 |
etapa_atual += 1
|
| 203 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 204 |
|
| 205 |
+
# ======================== ETAPA 3 - Filtros e Efeitos ========================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
|
| 207 |
subprocess.run([
|
| 208 |
"ffmpeg", "-i", fundo_convertido, "-i", video_raw,
|
| 209 |
"-filter_complex", filtro_complex,
|
| 210 |
"-map", "[final]",
|
| 211 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", "18",
|
| 212 |
video_editado
|
| 213 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 214 |
|
| 215 |
etapa_atual += 1
|
| 216 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 217 |
|
| 218 |
+
# ======================== ETAPA 3.5 - Aceleração ANTES do Tutorial ========================
|
| 219 |
+
video_editado_speed = os.path.join(temp_dir, f"video_editado_speed_{n}.mp4")
|
| 220 |
+
subprocess.run([
|
| 221 |
+
"ffmpeg", "-y", "-i", video_editado, "-an",
|
| 222 |
+
"-filter:v", f"setpts=PTS/{velocidade_final_n}",
|
| 223 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", "18",
|
| 224 |
+
video_editado_speed
|
| 225 |
+
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 226 |
+
# ======================== ETAPA 4 - Tutorial ========================
|
| 227 |
if usar_tutorial and tutorials_salvos:
|
| 228 |
tutorial_path = random.choice(tutorials_salvos)
|
| 229 |
tutorial_mp4 = os.path.join(temp_dir, f"tutorial_conv_{n}.mp4")
|
| 230 |
subprocess.run([
|
| 231 |
"ffmpeg", "-i", tutorial_path, "-vf", "scale=720:1280,fps=30",
|
| 232 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", 18,
|
| 233 |
"-y", tutorial_mp4
|
| 234 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 235 |
|
| 236 |
dur_proc = subprocess.run([
|
| 237 |
"ffprobe", "-v", "error", "-show_entries", "format=duration",
|
| 238 |
+
"-of", "default=noprint_wrappers=1:nokey=1", video_editado_speed
|
| 239 |
], stdout=subprocess.PIPE)
|
| 240 |
dur_f = float(dur_proc.stdout.decode().strip() or 0)
|
| 241 |
pt = dur_f / 2 if dur_f < 10 else random.uniform(5, dur_f - 5)
|
|
|
|
| 243 |
part1 = os.path.join(temp_dir, f"part1_{n}.mp4")
|
| 244 |
part2 = os.path.join(temp_dir, f"part2_{n}.mp4")
|
| 245 |
|
| 246 |
+
subprocess.run(["ffmpeg", "-i", video_editado_speed, "-ss", "0", "-t", str(pt),
|
| 247 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", 18, part1],
|
| 248 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 249 |
+
subprocess.run(["ffmpeg", "-i", video_editado_speed, "-ss", str(pt),
|
| 250 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", 18, part2],
|
| 251 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 252 |
|
| 253 |
final_txt = os.path.join(temp_dir, f"final_{n}.txt")
|
|
|
|
| 256 |
|
| 257 |
video_final_raw = os.path.join(temp_dir, f"video_final_raw_{n}.mp4")
|
| 258 |
subprocess.run(["ffmpeg", "-f", "concat", "-safe", "0", "-i", final_txt,
|
| 259 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", 18,
|
| 260 |
video_final_raw], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 261 |
else:
|
| 262 |
+
video_final_raw = video_editado_speed
|
| 263 |
etapa_atual += 1
|
| 264 |
atualizar_barra(n, etapa_atual, num_videos_finais, total_etapas)
|
| 265 |
|
| 266 |
+
# ======================== ETAPA 5 - FINALIZAÇÃO ========================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
dur_final_str = subprocess.run([
|
| 268 |
"ffprobe", "-v", "error", "-show_entries", "format=duration",
|
| 269 |
+
"-of", "default=noprint_wrappers=1:nokey=1", video_final_raw
|
| 270 |
], stdout=subprocess.PIPE).stdout.decode().strip()
|
| 271 |
if not dur_final_str:
|
| 272 |
continue
|
|
|
|
| 280 |
"-vn", "-acodec", "aac", "-y", musica_cortada],
|
| 281 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 282 |
|
| 283 |
+
subprocess.run(["ffmpeg", "-i", video_final_raw, "-i", musica_cortada,
|
| 284 |
"-map", "0:v:0", "-map", "1:a:0",
|
| 285 |
"-c:v", "copy", "-c:a", "aac", "-shortest", final_name],
|
| 286 |
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 287 |
else:
|
| 288 |
+
shutil.copy(video_final_raw, final_name)
|
| 289 |
|
| 290 |
if salvar_no_gerenciador:
|
| 291 |
destino = os.path.join(BASE_SALVOS, categoria_selecionada, final_name)
|
|
|
|
| 300 |
st.error(f"❌ Erro inesperado: {str(e)}")
|
| 301 |
finally:
|
| 302 |
shutil.rmtree(temp_dir)
|
|
|
|
| 303 |
# ======================== GERENCIADOR ========================
|
| 304 |
elif pagina == "📂 Gerenciador de Arquivos":
|
| 305 |
st.header("📂 Vídeos Salvos por Categoria")
|
|
|
|
| 341 |
os.remove(file_path)
|
| 342 |
st.success(f"❌ Arquivo '{file}' excluído.")
|
| 343 |
st.rerun()
|
|
|
|
| 344 |
# ======================== ADMIN ========================
|
| 345 |
elif pagina == "🔐 Admin":
|
| 346 |
st.title("🔐 Área de Administração")
|
|
|
|
| 390 |
subprocess.run([
|
| 391 |
"ffmpeg", "-i", temp,
|
| 392 |
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,fps=30",
|
| 393 |
+
"-c:v", "libx264", "-preset", "veryfast", "-crf", "18",
|
| 394 |
"-y", final
|
| 395 |
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 396 |
else:
|