Update app.py
Browse files
app.py
CHANGED
@@ -59,13 +59,18 @@ ativar_granulado = st.checkbox("Granulado", False)
|
|
59 |
ativar_pb = st.checkbox("Preto e branco", False)
|
60 |
ativar_vignette = st.checkbox("Vignette", False)
|
61 |
|
62 |
-
#
|
63 |
st.write("### Efeitos PRO")
|
64 |
-
ativar_zoom_dinamico = st.checkbox("Ativar Zoom
|
|
|
|
|
65 |
ativar_color_grading = st.checkbox("Aplicar Color Grading Aleatório", value=False)
|
66 |
ativar_transicoes = st.checkbox("Adicionar Transições Cinemáticas", value=False)
|
67 |
ativar_freeze_frame = st.checkbox("Aplicar Freeze Frame automático", value=False)
|
68 |
ativar_slow_motion = st.checkbox("Aplicar Slow Motion Inteligente aleatório", value=False)
|
|
|
|
|
|
|
69 |
|
70 |
# Efeitos extras
|
71 |
st.write("### Outros efeitos")
|
@@ -89,9 +94,8 @@ if st.button("Gerar Vídeo(s)"):
|
|
89 |
temp_dir = tempfile.mkdtemp()
|
90 |
|
91 |
try:
|
92 |
-
#
|
93 |
fundo_path = os.path.join(temp_dir, "fundo.mp4")
|
94 |
-
|
95 |
if video_fundo:
|
96 |
with open(fundo_path, "wb") as f:
|
97 |
f.write(video_fundo.read())
|
@@ -102,7 +106,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
102 |
"-pix_fmt", "yuv420p", "-y", fundo_path
|
103 |
], check=True, stderr=subprocess.PIPE)
|
104 |
|
105 |
-
#
|
106 |
if video_tutorial:
|
107 |
tutorial_path = os.path.join(temp_dir, "tutorial_raw.mp4")
|
108 |
with open(tutorial_path, "wb") as f:
|
@@ -114,7 +118,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
114 |
"-y", tutorial_mp4
|
115 |
], check=True, stderr=subprocess.PIPE)
|
116 |
|
117 |
-
# Padronizar vídeos
|
118 |
cortes_names = []
|
119 |
for idx, corte in enumerate(cortes):
|
120 |
path_in = os.path.join(temp_dir, f"corte_in_{idx}.mp4")
|
@@ -128,7 +132,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
128 |
], check=True, stderr=subprocess.PIPE)
|
129 |
cortes_names.append(path_out)
|
130 |
|
131 |
-
#
|
132 |
fundo_cortado = os.path.join(temp_dir, "fundo_cortado.mp4")
|
133 |
subprocess.run([
|
134 |
"ffmpeg", "-i", fundo_path, "-t", str(duracao_final),
|
@@ -156,22 +160,35 @@ if st.button("Gerar Vídeo(s)"):
|
|
156 |
|
157 |
filtros_corte = []
|
158 |
|
159 |
-
# ✅ Zoom
|
160 |
if ativar_zoom_dinamico:
|
161 |
-
filtros_corte.append(
|
|
|
|
|
|
|
162 |
else:
|
163 |
filtros_corte.append("scale=trunc(iw/2)*2:trunc(ih/2)*2")
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
# ✅ Transições Cinemáticas
|
166 |
if ativar_transicoes:
|
167 |
filtros_corte.append("fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3")
|
168 |
|
169 |
-
# ✅ Slow Motion Inteligente
|
170 |
aplicar_slow = ativar_slow_motion and random.random() < 0.3
|
171 |
if aplicar_slow:
|
172 |
filtros_corte.append("setpts=1.5*PTS")
|
173 |
|
174 |
-
# ✅ Freeze Frame
|
175 |
aplicar_freeze = ativar_freeze_frame and random.random() < 0.3
|
176 |
if aplicar_freeze:
|
177 |
freeze_frame = os.path.join(temp_dir, f"freeze_{random.randint(1000,9999)}.mp4")
|
@@ -197,7 +214,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
197 |
break
|
198 |
except:
|
199 |
continue
|
200 |
-
# Concatenação dos cortes
|
201 |
lista = os.path.join(temp_dir, f"lista_{n}.txt")
|
202 |
with open(lista, "w") as f:
|
203 |
for c in cortes_prontos:
|
@@ -212,7 +229,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
212 |
|
213 |
progresso.progress(35 + n * 5)
|
214 |
|
215 |
-
# Filtros
|
216 |
filtros_main = ["scale=720:1280:force_original_aspect_ratio=decrease"]
|
217 |
|
218 |
if zoom != 1.0:
|
@@ -231,15 +248,27 @@ if st.button("Gerar Vídeo(s)"):
|
|
231 |
|
232 |
# ✅ Color Grading aleatório
|
233 |
if ativar_color_grading:
|
234 |
-
|
235 |
"curves=preset=vintage",
|
236 |
"curves=preset=strong_contrast",
|
237 |
-
"eq=brightness=0.05:saturation=1.
|
238 |
"hue=s=0.6",
|
239 |
"colorchannelmixer=.5:0:.5:0:.5:0:.5:0:.5:0:.5"
|
240 |
-
]
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
|
|
|
|
|
|
|
|
|
|
|
243 |
filtros_main.append("scale=trunc(iw/2)*2:trunc(ih/2)*2")
|
244 |
# Montar filter_complex
|
245 |
filtro_complex = (
|
@@ -262,11 +291,28 @@ if st.button("Gerar Vídeo(s)"):
|
|
262 |
filtro_complex += f"[1:v]{','.join(filtros_main)}[zoomed];"
|
263 |
filtro_complex += "[blur][zoomed]overlay=(W-w)/2:(H-h)/2[base]"
|
264 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
if ativar_texto and texto_personalizado.strip():
|
266 |
y_pos = "100" if posicao_texto == "Topo" else "(h-text_h)/2" if posicao_texto == "Centro" else "h-text_h-100"
|
267 |
enable = f":enable='lt(t\\,{segundos_texto})'" if duracao_texto == "Apenas primeiros segundos" else ""
|
268 |
texto_clean = texto_personalizado.replace(":", "\\:").replace("'", "\\'")
|
269 |
-
filtro_complex += f";[
|
270 |
filtro_complex += (
|
271 |
f"fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:"
|
272 |
f"fontcolor={cor_texto}:fontsize={tamanho_texto}:"
|
@@ -274,7 +320,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
274 |
f"x=(w-text_w)/2:y={y_pos}{enable}[final]"
|
275 |
)
|
276 |
else:
|
277 |
-
filtro_complex += ";[
|
278 |
|
279 |
# Gerar vídeo com filtros
|
280 |
video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
|
@@ -336,7 +382,7 @@ if st.button("Gerar Vídeo(s)"):
|
|
336 |
], stdout=subprocess.PIPE)
|
337 |
dur_video_real = float(dur_proc.stdout.decode().strip())
|
338 |
|
339 |
-
# 🎵
|
340 |
if musica:
|
341 |
musica_path = os.path.join(temp_dir, "musica_original.mp3")
|
342 |
with open(musica_path, "wb") as f:
|
|
|
59 |
ativar_pb = st.checkbox("Preto e branco", False)
|
60 |
ativar_vignette = st.checkbox("Vignette", False)
|
61 |
|
62 |
+
# Efeitos PRO
|
63 |
st.write("### Efeitos PRO")
|
64 |
+
ativar_zoom_dinamico = st.checkbox("Ativar Zoom Progressivo", value=False)
|
65 |
+
zoom_dinamico_velocidade = st.slider("Velocidade do Zoom", 0.001, 0.01, 0.003, step=0.001)
|
66 |
+
movimento_camera = st.selectbox("Movimento de Câmera", ["Nenhum", "Esquerda para Direita", "Direita para Esquerda"])
|
67 |
ativar_color_grading = st.checkbox("Aplicar Color Grading Aleatório", value=False)
|
68 |
ativar_transicoes = st.checkbox("Adicionar Transições Cinemáticas", value=False)
|
69 |
ativar_freeze_frame = st.checkbox("Aplicar Freeze Frame automático", value=False)
|
70 |
ativar_slow_motion = st.checkbox("Aplicar Slow Motion Inteligente aleatório", value=False)
|
71 |
+
ativar_frame_blending = st.checkbox("Aplicar Frame Blending", value=False)
|
72 |
+
ativar_motion_crop = st.checkbox("Ativar Motion Crop Inteligente", value=False)
|
73 |
+
ativar_color_space_alt = st.checkbox("Alternar Color Space (anti-detect)", value=False)
|
74 |
|
75 |
# Efeitos extras
|
76 |
st.write("### Outros efeitos")
|
|
|
94 |
temp_dir = tempfile.mkdtemp()
|
95 |
|
96 |
try:
|
97 |
+
# Fundo
|
98 |
fundo_path = os.path.join(temp_dir, "fundo.mp4")
|
|
|
99 |
if video_fundo:
|
100 |
with open(fundo_path, "wb") as f:
|
101 |
f.write(video_fundo.read())
|
|
|
106 |
"-pix_fmt", "yuv420p", "-y", fundo_path
|
107 |
], check=True, stderr=subprocess.PIPE)
|
108 |
|
109 |
+
# Tutorial
|
110 |
if video_tutorial:
|
111 |
tutorial_path = os.path.join(temp_dir, "tutorial_raw.mp4")
|
112 |
with open(tutorial_path, "wb") as f:
|
|
|
118 |
"-y", tutorial_mp4
|
119 |
], check=True, stderr=subprocess.PIPE)
|
120 |
|
121 |
+
# Padronizar vídeos
|
122 |
cortes_names = []
|
123 |
for idx, corte in enumerate(cortes):
|
124 |
path_in = os.path.join(temp_dir, f"corte_in_{idx}.mp4")
|
|
|
132 |
], check=True, stderr=subprocess.PIPE)
|
133 |
cortes_names.append(path_out)
|
134 |
|
135 |
+
# Fundo cortado
|
136 |
fundo_cortado = os.path.join(temp_dir, "fundo_cortado.mp4")
|
137 |
subprocess.run([
|
138 |
"ffmpeg", "-i", fundo_path, "-t", str(duracao_final),
|
|
|
160 |
|
161 |
filtros_corte = []
|
162 |
|
163 |
+
# ✅ Zoom Progressivo
|
164 |
if ativar_zoom_dinamico:
|
165 |
+
filtros_corte.append(
|
166 |
+
f"zoompan=z='min(zoom+{zoom_dinamico_velocidade},1.5)':d=1:"
|
167 |
+
f"x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)',fps=30,scale=1280:720"
|
168 |
+
)
|
169 |
else:
|
170 |
filtros_corte.append("scale=trunc(iw/2)*2:trunc(ih/2)*2")
|
171 |
|
172 |
+
# ✅ Pan de câmera (horizontal)
|
173 |
+
if movimento_camera == "Esquerda para Direita":
|
174 |
+
filtros_corte.append("crop=w=720:h=1280:x='t*50':y=0")
|
175 |
+
elif movimento_camera == "Direita para Esquerda":
|
176 |
+
filtros_corte.append("crop=w=720:h=1280:x='(main_w-w)-t*50':y=0")
|
177 |
+
|
178 |
+
# ✅ Motion Crop Inteligente (simulado)
|
179 |
+
if ativar_motion_crop:
|
180 |
+
filtros_corte.append("crop=720:1280:x='abs(mod(t*100\\,main_w-w))':y='(main_h-h)/2'")
|
181 |
+
|
182 |
# ✅ Transições Cinemáticas
|
183 |
if ativar_transicoes:
|
184 |
filtros_corte.append("fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3")
|
185 |
|
186 |
+
# ✅ Slow Motion Inteligente
|
187 |
aplicar_slow = ativar_slow_motion and random.random() < 0.3
|
188 |
if aplicar_slow:
|
189 |
filtros_corte.append("setpts=1.5*PTS")
|
190 |
|
191 |
+
# ✅ Freeze Frame
|
192 |
aplicar_freeze = ativar_freeze_frame and random.random() < 0.3
|
193 |
if aplicar_freeze:
|
194 |
freeze_frame = os.path.join(temp_dir, f"freeze_{random.randint(1000,9999)}.mp4")
|
|
|
214 |
break
|
215 |
except:
|
216 |
continue
|
217 |
+
# Concatenação dos cortes com ajuste para múltiplos de 2
|
218 |
lista = os.path.join(temp_dir, f"lista_{n}.txt")
|
219 |
with open(lista, "w") as f:
|
220 |
for c in cortes_prontos:
|
|
|
229 |
|
230 |
progresso.progress(35 + n * 5)
|
231 |
|
232 |
+
# Filtros principais sobre o vídeo principal
|
233 |
filtros_main = ["scale=720:1280:force_original_aspect_ratio=decrease"]
|
234 |
|
235 |
if zoom != 1.0:
|
|
|
248 |
|
249 |
# ✅ Color Grading aleatório
|
250 |
if ativar_color_grading:
|
251 |
+
filtros_main.append(random.choice([
|
252 |
"curves=preset=vintage",
|
253 |
"curves=preset=strong_contrast",
|
254 |
+
"eq=brightness=0.05:saturation=1.5:contrast=1.2",
|
255 |
"hue=s=0.6",
|
256 |
"colorchannelmixer=.5:0:.5:0:.5:0:.5:0:.5:0:.5"
|
257 |
+
]))
|
258 |
+
|
259 |
+
# ✅ Color Space alternado
|
260 |
+
if ativar_color_space_alt:
|
261 |
+
filtros_main.append(random.choice([
|
262 |
+
"colorspace=all=bt601-6-625",
|
263 |
+
"colorspace=all=bt470bg",
|
264 |
+
"colorspace=all=smpte240m"
|
265 |
+
]))
|
266 |
|
267 |
+
# ✅ Frame Blending (minterpolate)
|
268 |
+
if ativar_frame_blending:
|
269 |
+
filtros_main.append("minterpolate='mi_mode=mci:mc_mode=aobmc:vsbmc=1'")
|
270 |
+
|
271 |
+
# Garantir múltiplos de 2 no final
|
272 |
filtros_main.append("scale=trunc(iw/2)*2:trunc(ih/2)*2")
|
273 |
# Montar filter_complex
|
274 |
filtro_complex = (
|
|
|
291 |
filtro_complex += f"[1:v]{','.join(filtros_main)}[zoomed];"
|
292 |
filtro_complex += "[blur][zoomed]overlay=(W-w)/2:(H-h)/2[base]"
|
293 |
|
294 |
+
if ativar_borda_personalizada:
|
295 |
+
cor_ffmpeg = f"0x{cor_borda.lstrip('#')}FF"
|
296 |
+
anim_map = {
|
297 |
+
"Nenhuma": "",
|
298 |
+
"Borda Pulsante": "enable='lt(mod(t,1),0.5)'",
|
299 |
+
"Cor Animada": "enable='lt(mod(t,1),0.5)'",
|
300 |
+
"Neon": "enable='lt(mod(t,0.5),0.25)'",
|
301 |
+
"Ondulada": "enable='gt(sin(t*3.14),0)'"
|
302 |
+
}
|
303 |
+
drawbox = f"drawbox=x=0:y=0:w=iw:h=ih:color={cor_ffmpeg}:t=5"
|
304 |
+
if anim_map[animacao_borda]:
|
305 |
+
drawbox += f":{anim_map[animacao_borda]}"
|
306 |
+
filtro_complex += f";[base]{drawbox}[borda]"
|
307 |
+
filtro_complex += ";[borda]null[texto]"
|
308 |
+
else:
|
309 |
+
filtro_complex += ";[base]null[texto]"
|
310 |
+
|
311 |
if ativar_texto and texto_personalizado.strip():
|
312 |
y_pos = "100" if posicao_texto == "Topo" else "(h-text_h)/2" if posicao_texto == "Centro" else "h-text_h-100"
|
313 |
enable = f":enable='lt(t\\,{segundos_texto})'" if duracao_texto == "Apenas primeiros segundos" else ""
|
314 |
texto_clean = texto_personalizado.replace(":", "\\:").replace("'", "\\'")
|
315 |
+
filtro_complex += f";[texto]drawtext=text='{texto_clean}':"
|
316 |
filtro_complex += (
|
317 |
f"fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:"
|
318 |
f"fontcolor={cor_texto}:fontsize={tamanho_texto}:"
|
|
|
320 |
f"x=(w-text_w)/2:y={y_pos}{enable}[final]"
|
321 |
)
|
322 |
else:
|
323 |
+
filtro_complex += ";[texto]null[final]"
|
324 |
|
325 |
# Gerar vídeo com filtros
|
326 |
video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
|
|
|
382 |
], stdout=subprocess.PIPE)
|
383 |
dur_video_real = float(dur_proc.stdout.decode().strip())
|
384 |
|
385 |
+
# 🎵 Música sincronizada
|
386 |
if musica:
|
387 |
musica_path = os.path.join(temp_dir, "musica_original.mp3")
|
388 |
with open(musica_path, "wb") as f:
|