pcdoido2 commited on
Commit
d51c8cc
·
verified ·
1 Parent(s): 5081db2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -370
app.py CHANGED
@@ -1,374 +1,41 @@
1
  import streamlit as st
2
- import subprocess
3
  import os
4
- import random
5
- import tempfile
6
  import shutil
7
- import time
8
 
9
- st.set_page_config(page_title="TikTok Video Generator", layout="centered")
10
- st.title("🎥 TikTok Video Generator - PRO")
11
-
12
- st.markdown("Envie seus vídeos e gere conteúdo com efeitos, zoom, texto, música e filtros!")
13
-
14
- # Uploads dos vídeos de cortes (principal)
15
- st.markdown("<div style='background-color:#F0F0FF;padding:10px;border-radius:8px'>", unsafe_allow_html=True)
16
- st.subheader("🎬 Envie os vídeos principais (cortes)")
17
- cortes = st.file_uploader("Vídeos de cortes", type=["mp4"], accept_multiple_files=True)
18
- st.markdown("</div>", unsafe_allow_html=True)
19
-
20
- # Upload do vídeo de fundo (opcional)
21
- st.markdown("<div style='background-color:#FFF0F0;padding:10px;border-radius:8px;margin-top:15px;'>", unsafe_allow_html=True)
22
- st.subheader("🌄 Envie o vídeo de fundo (opcional)")
23
- video_fundo = st.file_uploader("Vídeo de Fundo (com blur e efeitos)", type=["mp4", "mov"])
24
- st.markdown("</div>", unsafe_allow_html=True)
25
-
26
- # Uploads adicionais
27
- video_tutorial = st.file_uploader("📎 Tutorial (opcional)", type="mp4")
28
- musica = st.file_uploader("🎵 Música (opcional, MP3)", type=["mp3"])
29
-
30
- # Configurações gerais
31
- num_videos_finais = st.number_input("Quantos vídeos gerar?", 1, 10, 1)
32
- duracao_final = st.number_input("Duração final (s)", 10, 300, 30)
33
- duracao_corte = st.number_input("Duração de cada corte (s)", 1, 30, 5)
34
- zoom = st.slider("Zoom no vídeo principal", 1.0, 2.0, 1.0, 0.1)
35
- blur_strength = st.slider("Blur no fundo", 1, 50, 10)
36
- velocidade_cortes = st.slider("Velocidade dos cortes", 0.5, 2.0, 1.0, 0.1)
37
- velocidade_final = st.slider("Velocidade final", 0.5, 2.0, 1.0, 0.1)
38
- crf_value = st.slider("Qualidade CRF", 18, 30, 23)
39
-
40
- # Texto com emojis
41
- st.write("### Texto no Vídeo")
42
- ativar_texto = st.checkbox("Ativar texto", value=False)
43
- if ativar_texto:
44
- texto_personalizado = st.text_input("Texto (emojis permitidos)", "🔥 Siga para mais!")
45
- posicao_texto = st.selectbox("Posição do texto", ["Topo", "Centro", "Base"])
46
- duracao_texto = st.radio("Duração do texto", ["Vídeo todo", "Apenas primeiros segundos"])
47
- segundos_texto = 5
48
- if duracao_texto == "Apenas primeiros segundos":
49
- segundos_texto = st.slider("Segundos", 1, 30, 5)
50
- cor_texto = st.color_picker("Cor do texto", "#FFFF00")
51
- cor_sombra = st.color_picker("Cor da sombra", "#000000")
52
- tamanho_texto = st.slider("Tamanho da fonte", 20, 100, 60, step=2)
53
-
54
- # Filtros no fundo
55
- st.write("### Filtros no fundo")
56
- ativar_blur_fundo = st.checkbox("Ativar blur no fundo", value=True)
57
- ativar_sepia = st.checkbox("Sépia", False)
58
- ativar_granulado = st.checkbox("Granulado", False)
59
- ativar_pb = st.checkbox("Preto e branco", False)
60
- ativar_vignette = st.checkbox("Vignette", False)
61
-
62
- # Novos efeitos PRO
63
- st.write("### Efeitos PRO")
64
- ativar_zoom_dinamico = st.checkbox("Ativar Zoom/Pan Dinâmico (Movimento de câmera)", value=False)
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")
72
- ativar_espelhar = st.checkbox("Espelhar vídeo", True)
73
- ativar_filtro_cor = st.checkbox("Ajuste de cor", True)
74
- remover_borda = st.checkbox("Remover borda do vídeo")
75
- tamanho_borda = st.slider("Tamanho da borda (px)", 0, 200, 0, 5)
76
-
77
- # Borda personalizada
78
- ativar_borda_personalizada = st.checkbox("Borda personalizada", False)
79
- if ativar_borda_personalizada:
80
- cor_borda = st.color_picker("Cor da borda", "#FF0000")
81
- animacao_borda = st.selectbox("Animação da borda", ["Nenhuma", "Borda Pulsante", "Cor Animada", "Neon", "Ondulada"])
82
- # BOTÃO PRINCIPAL
83
- if st.button("Gerar Vídeo(s)"):
84
- if not cortes:
85
- st.error("❌ Envie os vídeos de cortes.")
86
- else:
87
- with st.spinner("🎬 Processando..."):
88
- progresso = st.progress(0)
89
- temp_dir = tempfile.mkdtemp()
90
-
91
- try:
92
- # Salvar ou gerar fundo
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())
98
- else:
99
- subprocess.run([
100
- "ffmpeg", "-f", "lavfi", "-i", "color=black:s=720x1280:d=600",
101
- "-c:v", "libx264", "-t", str(duracao_final),
102
- "-pix_fmt", "yuv420p", "-y", fundo_path
103
- ], check=True, stderr=subprocess.PIPE)
104
-
105
- # Salvar e converter tutorial (se enviado)
106
- if video_tutorial:
107
- tutorial_path = os.path.join(temp_dir, "tutorial_raw.mp4")
108
- with open(tutorial_path, "wb") as f:
109
- f.write(video_tutorial.read())
110
- tutorial_mp4 = os.path.join(temp_dir, "tutorial.mp4")
111
- subprocess.run([
112
- "ffmpeg", "-i", tutorial_path, "-vf", "scale=720:1280,fps=30",
113
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
114
- "-y", tutorial_mp4
115
- ], check=True, stderr=subprocess.PIPE)
116
-
117
- # Padronizar vídeos de cortes
118
- cortes_names = []
119
- for idx, corte in enumerate(cortes):
120
- path_in = os.path.join(temp_dir, f"corte_in_{idx}.mp4")
121
- path_out = os.path.join(temp_dir, f"corte_padrao_{idx}.mp4")
122
- with open(path_in, "wb") as f:
123
- f.write(corte.read())
124
- subprocess.run([
125
- "ffmpeg", "-i", path_in,
126
- "-vf", "scale=1280:720:force_original_aspect_ratio=decrease,scale=trunc(iw/2)*2:trunc(ih/2)*2",
127
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", "30", path_out
128
- ], check=True, stderr=subprocess.PIPE)
129
- cortes_names.append(path_out)
130
-
131
- # Cortar fundo para a duração final
132
- fundo_cortado = os.path.join(temp_dir, "fundo_cortado.mp4")
133
- subprocess.run([
134
- "ffmpeg", "-i", fundo_path, "-t", str(duracao_final),
135
- "-c:v", "libx264", "-preset", "ultrafast", "-y", fundo_cortado
136
- ], check=True, stderr=subprocess.PIPE)
137
-
138
- for n in range(num_videos_finais):
139
- progresso.progress(10 + n * 5)
140
- random.shuffle(cortes_names)
141
- tempo_total = 0
142
- cortes_prontos = []
143
-
144
- while tempo_total < duracao_final:
145
- for c in cortes_names:
146
- dur = subprocess.run([
147
- "ffprobe", "-v", "error", "-show_entries", "format=duration",
148
- "-of", "default=noprint_wrappers=1:nokey=1", c
149
- ], stdout=subprocess.PIPE).stdout.decode().strip()
150
-
151
- try:
152
- d = float(dur)
153
- if d > duracao_corte:
154
- ini = random.uniform(0, d - duracao_corte)
155
- out = os.path.join(temp_dir, f"cut_{random.randint(1000,9999)}.mp4")
156
-
157
- filtros_corte = []
158
-
159
- # ✅ Zoom/Pan Dinâmico corrigido
160
- if ativar_zoom_dinamico:
161
- filtros_corte.append("scale=iw*1.05:ih*1.05,crop=iw-20:ih-20")
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 (aleatório)
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 (aleatório, 0.5s no meio)
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")
178
- subprocess.run([
179
- "ffmpeg", "-ss", str(ini + duracao_corte/2), "-i", c,
180
- "-t", "0.001", "-vf", "scale=1280:720", "-c:v", "libx264",
181
- "-y", freeze_frame
182
- ], check=True, stderr=subprocess.PIPE)
183
- cortes_prontos.append(freeze_frame)
184
- tempo_total += 0.5
185
-
186
- filtro_final = ",".join(filtros_corte)
187
-
188
- subprocess.run([
189
- "ffmpeg", "-ss", str(ini), "-i", c, "-t", str(duracao_corte),
190
- "-vf", filtro_final,
191
- "-an", "-c:v", "libx264", "-preset", "ultrafast", "-crf", "30", out
192
- ], check=True, stderr=subprocess.PIPE)
193
-
194
- cortes_prontos.append(out)
195
- tempo_total += duracao_corte / velocidade_cortes
196
- if tempo_total >= duracao_final:
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:
204
- f.write(f"file '{c}'\n")
205
-
206
- video_raw = os.path.join(temp_dir, f"video_raw_{n}.mp4")
207
- subprocess.run([
208
- "ffmpeg", "-f", "concat", "-safe", "0", "-i", lista,
209
- "-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
210
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", "30", video_raw
211
- ], check=True, stderr=subprocess.PIPE)
212
-
213
- progresso.progress(35 + n * 5)
214
-
215
- # Filtros aplicados ao vídeo principal (sobre o vídeo de cortes)
216
- filtros_main = ["scale=720:1280:force_original_aspect_ratio=decrease"]
217
-
218
- if zoom != 1.0:
219
- filtros_main.append(f"scale=iw*{zoom}:ih*{zoom}")
220
-
221
- filtros_main.append(f"setpts=PTS/{velocidade_cortes}")
222
-
223
- if ativar_espelhar:
224
- filtros_main.append("hflip")
225
-
226
- if remover_borda and tamanho_borda > 0:
227
- filtros_main.append(f"crop=in_w-{tamanho_borda*2}:in_h-{tamanho_borda*2}")
228
-
229
- if ativar_filtro_cor:
230
- filtros_main.append("eq=contrast=1.1:saturation=1.2")
231
-
232
- # ✅ Color Grading aleatório
233
- if ativar_color_grading:
234
- opcoes_color = [
235
- "curves=preset=vintage",
236
- "curves=preset=strong_contrast",
237
- "eq=brightness=0.05:saturation=1.4:contrast=1.3",
238
- "hue=s=0.6",
239
- "colorchannelmixer=.5:0:.5:0:.5:0:.5:0:.5:0:.5"
240
- ]
241
- filtros_main.append(random.choice(opcoes_color))
242
-
243
- filtros_main.append("scale=trunc(iw/2)*2:trunc(ih/2)*2")
244
- # Montar filter_complex
245
- filtro_complex = (
246
- f"[0:v]scale=720:1280:force_original_aspect_ratio=increase,"
247
- f"crop=720:1280"
248
- )
249
-
250
- if ativar_blur_fundo:
251
- filtro_complex += f",boxblur={blur_strength}:1"
252
- if ativar_sepia:
253
- filtro_complex += ",colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131"
254
- if ativar_granulado:
255
- filtro_complex += ",noise=alls=20:allf=t+u"
256
- if ativar_pb:
257
- filtro_complex += ",hue=s=0.3"
258
- if ativar_vignette:
259
- filtro_complex += ",vignette"
260
- filtro_complex += "[blur];"
261
-
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";[base]drawtext=text='{texto_clean}':"
270
- filtro_complex += (
271
- f"fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:"
272
- f"fontcolor={cor_texto}:fontsize={tamanho_texto}:"
273
- f"shadowcolor={cor_sombra}:shadowx=3:shadowy=3:"
274
- f"x=(w-text_w)/2:y={y_pos}{enable}[final]"
275
- )
276
- else:
277
- filtro_complex += ";[base]null[final]"
278
-
279
- # Gerar vídeo com filtros
280
- video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
281
- subprocess.run([
282
- "ffmpeg", "-i", fundo_cortado, "-i", video_raw,
283
- "-filter_complex", filtro_complex,
284
- "-map", "[final]",
285
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
286
- video_editado
287
- ], check=True, stderr=subprocess.PIPE)
288
-
289
- # Acelerar vídeo (sem áudio ainda)
290
- video_acelerado = os.path.join(temp_dir, f"video_acelerado_{n}.mp4")
291
- subprocess.run([
292
- "ffmpeg", "-y", "-i", video_editado, "-an",
293
- "-filter:v", f"setpts=PTS/{velocidade_final}",
294
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
295
- video_acelerado
296
- ], check=True, stderr=subprocess.PIPE)
297
-
298
- progresso.progress(90)
299
- # Tutorial no meio, se fornecido
300
- video_final_raw = video_acelerado # Começa com o vídeo acelerado
301
- if video_tutorial:
302
- dur_proc = subprocess.run([
303
- "ffprobe", "-v", "error", "-show_entries", "format=duration",
304
- "-of", "default=noprint_wrappers=1:nokey=1", video_acelerado
305
- ], stdout=subprocess.PIPE)
306
- dur_f = float(dur_proc.stdout.decode().strip())
307
- pt = dur_f / 2 if dur_f < 10 else random.uniform(5, dur_f - 5)
308
-
309
- part1 = os.path.join(temp_dir, f"part1_{n}.mp4")
310
- part2 = os.path.join(temp_dir, f"part2_{n}.mp4")
311
-
312
- subprocess.run([
313
- "ffmpeg", "-i", video_acelerado, "-ss", "0", "-t", str(pt),
314
- "-c:v", "libx264", "-preset", "ultrafast", part1
315
- ], check=True, stderr=subprocess.PIPE)
316
- subprocess.run([
317
- "ffmpeg", "-i", video_acelerado, "-ss", str(pt),
318
- "-c:v", "libx264", "-preset", "ultrafast", part2
319
- ], check=True, stderr=subprocess.PIPE)
320
-
321
- final_txt = os.path.join(temp_dir, f"final_{n}.txt")
322
- with open(final_txt, "w") as f:
323
- f.write(f"file '{part1}'\nfile '{tutorial_mp4}'\nfile '{part2}'\n")
324
-
325
- video_final_raw = os.path.join(temp_dir, f"video_final_raw_{n}.mp4")
326
- subprocess.run([
327
- "ffmpeg", "-f", "concat", "-safe", "0", "-i", final_txt,
328
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
329
- video_final_raw
330
- ], check=True, stderr=subprocess.PIPE)
331
-
332
- # 🧠 Obter duração real do vídeo final (após tudo)
333
- dur_proc = subprocess.run([
334
- "ffprobe", "-v", "error", "-show_entries", "format=duration",
335
- "-of", "default=noprint_wrappers=1:nokey=1", video_final_raw
336
- ], stdout=subprocess.PIPE)
337
- dur_video_real = float(dur_proc.stdout.decode().strip())
338
-
339
- # 🎵 Cortar música para a duração real
340
- if musica:
341
- musica_path = os.path.join(temp_dir, "musica_original.mp3")
342
- with open(musica_path, "wb") as f:
343
- f.write(musica.read())
344
-
345
- musica_cortada = os.path.join(temp_dir, f"musica_cortada_{n}.aac")
346
- subprocess.run([
347
- "ffmpeg", "-i", musica_path, "-ss", "0", "-t", str(dur_video_real),
348
- "-vn", "-acodec", "aac", "-y", musica_cortada
349
- ], check=True, stderr=subprocess.PIPE)
350
-
351
- final_name = f"video_final_{n}_{int(time.time())}.mp4"
352
- subprocess.run([
353
- "ffmpeg", "-i", video_final_raw, "-i", musica_cortada,
354
- "-map", "0:v:0", "-map", "1:a:0",
355
- "-c:v", "copy", "-c:a", "aac",
356
- "-shortest", final_name
357
- ], check=True, stderr=subprocess.PIPE)
358
-
359
- else:
360
- final_name = f"video_final_{n}_{int(time.time())}.mp4"
361
- shutil.copy(video_final_raw, final_name)
362
-
363
- st.video(final_name)
364
- with open(final_name, "rb") as f:
365
- st.download_button(f"📥 Baixar vídeo {n+1}", f, file_name=final_name)
366
-
367
- progresso.progress(100)
368
- st.success("✅ Todos os vídeos foram gerados com sucesso!")
369
-
370
- except subprocess.CalledProcessError as e:
371
- st.error(f"❌ Erro ao gerar vídeo:\n\n{e.stderr.decode(errors='ignore')}")
372
-
373
- finally:
374
- shutil.rmtree(temp_dir)
 
1
  import streamlit as st
 
2
  import os
 
 
3
  import shutil
 
4
 
5
+ UPLOAD_FOLDER = "uploaded_files"
6
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
7
+
8
+ st.title("📂 File Manager Simples")
9
+
10
+ # --- Upload ---
11
+ st.header("📤 Upload de Arquivos")
12
+ uploaded_files = st.file_uploader("Selecione arquivos", accept_multiple_files=True)
13
+
14
+ if uploaded_files:
15
+ for uploaded_file in uploaded_files:
16
+ file_path = os.path.join(UPLOAD_FOLDER, uploaded_file.name)
17
+ with open(file_path, "wb") as f:
18
+ f.write(uploaded_file.read())
19
+ st.success("Arquivos enviados com sucesso!")
20
+ st.experimental_rerun() # Atualiza a página após upload
21
+
22
+ # --- Lista de Arquivos ---
23
+ st.header("📄 Arquivos Disponíveis")
24
+
25
+ files = os.listdir(UPLOAD_FOLDER)
26
+
27
+ if not files:
28
+ st.info("Nenhum arquivo disponível.")
29
+ else:
30
+ for file in files:
31
+ col1, col2, col3 = st.columns([4, 1, 1])
32
+ with col1:
33
+ st.write(file)
34
+ with col2:
35
+ with open(os.path.join(UPLOAD_FOLDER, file), "rb") as f:
36
+ st.download_button("⬇ Download", f, file_name=file)
37
+ with col3:
38
+ if st.button("🗑 Excluir", key=f"delete_{file}"):
39
+ os.remove(os.path.join(UPLOAD_FOLDER, file))
40
+ st.success(f"Arquivo '{file}' excluído.")
41
+ st.experimental_rerun() # Atualiza a lista após exclusão