File size: 12,356 Bytes
175f17e
 
 
 
 
 
 
fcea57a
175f17e
fcea57a
5f81f42
 
fcea57a
 
 
 
 
bf00d65
 
 
 
fcea57a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bf00d65
fcea57a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b4138bb
 
fcea57a
 
 
 
 
 
 
 
 
 
 
 
015967f
fcea57a
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
import streamlit as st
import subprocess
import os
import random
import tempfile
import shutil
import time
import base64

# ======================= CONFIG GERAL =======================
st.set_page_config(page_title="Shorts Generator", layout="centered")

# Abas laterais (igual ao primeiro app)
abas = ["🎬 Gerador", "🔐 Admin"]
pagina = st.sidebar.radio("Escolha uma página:", abas)

# Categorias e estrutura de pastas
CATEGORIAS = ["AVATAR WORLD", "BLOX FRUITS", "TOCA LIFE", "FC MOBILE"]
BASE_ASSETS = "assets"
for cat in CATEGORIAS:
    os.makedirs(os.path.join(BASE_ASSETS, cat, "cortes"), exist_ok=True)

# ======================= PÁGINA GERADOR =======================
if pagina == "🎬 Gerador":
    st.title("🎥 Shorts Generator - Simples")
    st.markdown("Envie seus vídeos e/ou use cortes salvos por categoria para gerar conteúdo com efeitos e controle de duração!")

    # Seleção de categoria para usar cortes salvos (opcional)
    categoria_selecionada = st.selectbox(
        "Escolha a categoria (opcional, para usar cortes já salvos):",
        ["Selecione..."] + CATEGORIAS
    )

    cortes_salvos_paths = []
    if categoria_selecionada != "Selecione...":
        path_cortes_salvos = os.path.join(BASE_ASSETS, categoria_selecionada, "cortes")
        if os.path.isdir(path_cortes_salvos):
            cortes_salvos_paths = [
                os.path.join(path_cortes_salvos, f)
                for f in os.listdir(path_cortes_salvos)
                if f.lower().endswith(".mp4")
            ]
        st.caption(f"Encontrados {len(cortes_salvos_paths)} cortes salvos em: {path_cortes_salvos}")

    # Upload dos vídeos (MANTIDO)
    cortes = st.file_uploader("Envie os vídeos de cortes", type=["mp4"], accept_multiple_files=True)

    # Configurações (MANTIDO)
    num_videos_finais = st.number_input("Quantos vídeos finais gerar?", min_value=1, max_value=10, value=1)
    duracao_final = st.number_input("Duração final do vídeo (em segundos)", min_value=10, max_value=300, value=30)

    # Min e Max duração dos cortes (MANTIDO)
    duracao_min = st.slider("Duração mínima de cada corte (s)", 1, 30, 3)
    duracao_max = st.slider("Duração máxima de cada corte (s)", 1, 60, 5)
    if duracao_min > duracao_max:
        st.warning("⚠️ A duração mínima não pode ser maior que a máxima.")

    # Corte lateral e zoom (MANTIDO)
    corte_lateral = st.slider("Corte lateral (%)", 0, 50, 0, 5)
    zoom = st.slider("Zoom Central (1.0 = normal)", 1.0, 2.0, 1.0, 0.1)

    # Velocidades e qualidade (MANTIDO)
    velocidade_cortes = st.slider("Velocidade dos cortes", 0.5, 2.0, 1.0, 0.1)
    velocidade_final = st.slider("Velocidade final do vídeo", 0.5, 2.0, 1.0, 0.1)
    crf_value = st.slider("Qualidade CRF (menor = melhor qualidade)", 18, 30, 18)

    # Outros (MANTIDO)
    st.write("### Outros")
    ativar_espelhar = st.checkbox("Espelhar Vídeo", value=True)
    ativar_filtro_cor = st.checkbox("Filtro de Cor (Contraste/Saturação)", value=True)

    # Botão principal (MANTIDO, agora combinando uploads + salvos)
    if st.button("Gerar Vídeo(s)"):
        if not cortes and len(cortes_salvos_paths) == 0:
            st.error("❌ Envie vídeos OU selecione uma categoria com cortes salvos para continuar.")
        else:
            with st.spinner('🎥 Seu vídeo está sendo gerado...'):
                progresso = st.progress(0)
                temp_dir = tempfile.mkdtemp()

                try:
                    # === PREPARAR LISTA FINAL DE ARQUIVOS DE CORTE ===
                    cortes_names = []

                    # 1) Arquivos enviados (MANTIDO)
                    if cortes:
                        for idx, corte in enumerate(cortes):
                            nome = os.path.join(temp_dir, f"corte_{idx}_{random.randint(1000,9999)}.mp4")
                            with open(nome, "wb") as f:
                                f.write(corte.read())
                            cortes_names.append(nome)

                    # 2) Arquivos salvos na categoria (NOVO – usamos os caminhos diretamente)
                    if len(cortes_salvos_paths) > 0:
                        cortes_names.extend(cortes_salvos_paths)

                    if len(cortes_names) == 0:
                        st.error("❌ Não há cortes disponíveis após combinar uploads e salvos.")
                        shutil.rmtree(temp_dir)
                        st.stop()

                    progresso.progress(10)

                    for n in range(num_videos_finais):
                        cortes_prontos = []
                        random.shuffle(cortes_names)
                        progresso.progress(10 + int(20 * (n / num_videos_finais)))

                        tempo_total = 0
                        while tempo_total < duracao_final:
                            for c in cortes_names:
                                dur_proc = subprocess.run([
                                    "ffprobe", "-v", "error", "-show_entries", "format=duration",
                                    "-of", "default=noprint_wrappers=1:nokey=1", c
                                ], stdout=subprocess.PIPE)

                                dur = dur_proc.stdout.decode().strip()
                                try:
                                    d = float(dur)
                                    dur_aleatoria = random.uniform(duracao_min, duracao_max)
                                    if d > dur_aleatoria:
                                        ini = random.uniform(0, d - dur_aleatoria)
                                        out = os.path.join(temp_dir, f"cut_{n}_{random.randint(1000,9999)}.mp4")
                                        subprocess.run([
                                            "ffmpeg", "-ss", str(ini), "-i", c, "-t", str(dur_aleatoria),
                                            "-an", "-c:v", "libx264", "-preset", "ultrafast", "-crf", "30", out
                                        ], check=True, stderr=subprocess.PIPE)
                                        cortes_prontos.append(out)
                                        tempo_total += dur_aleatoria / velocidade_cortes
                                        if tempo_total >= duracao_final:
                                            break
                                except:
                                    continue

                        lista = os.path.join(temp_dir, f"lista_{n}.txt")
                        with open(lista, "w") as f:
                            for c in cortes_prontos:
                                f.write(f"file '{c}'\n")

                        video_raw = os.path.join(temp_dir, f"video_raw_{n}.mp4")
                        subprocess.run([
                            "ffmpeg", "-f", "concat", "-safe", "0", "-i", lista, "-c:v", "libx264",
                            "-preset", "ultrafast", "-crf", "30", video_raw
                        ], check=True, stderr=subprocess.PIPE)

                        progresso.progress(40 + int(20 * (n / num_videos_finais)))

                        filtros_main = []

                        if corte_lateral > 0:
                            fator = (100 - corte_lateral) / 100
                            filtros_main.append(f"crop=iw*{fator}:ih:(iw-iw*{fator})/2:0")

                        if zoom != 1.0:
                            filtros_main.append(f"scale=iw*{zoom}:ih*{zoom},crop=iw/{zoom}:ih/{zoom}")

                        filtros_main.append(f"setpts=PTS/{velocidade_cortes}")
                        if ativar_espelhar:
                            filtros_main.append("hflip")
                        if ativar_filtro_cor:
                            filtros_main.append("eq=contrast=1.1:saturation=1.2")

                        filtros_main.append("pad=ceil(iw/2)*2:ceil(ih/2)*2")
                        filtro_final = ",".join(filtros_main)

                        video_editado = os.path.join(temp_dir, f"video_editado_{n}.mp4")
                        subprocess.run([
                            "ffmpeg", "-i", video_raw, "-vf", filtro_final,
                            "-c:v", "libx264", "-preset", "ultrafast", "-crf", str(crf_value),
                            video_editado
                        ], check=True, stderr=subprocess.PIPE)

                        video_final = f"video_final_{n}_{int(time.time())}.mp4"
                        subprocess.run([
                            "ffmpeg", "-i", video_editado, "-filter:v", f"setpts=PTS/{velocidade_final}",
                            "-t", str(duracao_final), "-c:v", "libx264", "-preset", "ultrafast",
                            "-crf", str(crf_value), "-map_metadata", "-1", "-movflags", "+faststart", video_final
                        ], check=True, stderr=subprocess.PIPE)

                        progresso.progress(90 + int(10 * (n / num_videos_finais)))
                        st.video(video_final)
                        with open(video_final, "rb") as f:
                            st.download_button(f"📅 Baixar Vídeo {n+1}", f, file_name=video_final)

                    progresso.progress(100)
                    st.success("✅ Todos os vídeos foram gerados com sucesso!")

                except subprocess.CalledProcessError as e:
                    st.error(f"Erro durante processamento: {e.stderr.decode()}")
                except Exception as e:
                    st.error(f"Erro inesperado: {str(e)}")
                finally:
                    shutil.rmtree(temp_dir)

# ======================= PÁGINA ADMIN =======================
elif pagina == "🔐 Admin":
    st.title("🔐 Área de Administração (CORTES)")

    # Mesma senha do seu primeiro código: base64 de "admin123"
    SENHA_CODIFICADA = "YWRtaW4xMjM="

    if "autenticado_admin" not in st.session_state:
        st.session_state.autenticado_admin = False

    if not st.session_state.autenticado_admin:
        senha_input = st.text_input("Senha do Admin:", type="password")
        if st.button("Entrar"):
            if base64.b64encode(senha_input.encode()).decode() == SENHA_CODIFICADA:
                st.session_state.autenticado_admin = True
                st.success("✅ Acesso liberado!")
            else:
                st.error("❌ Senha incorreta.")
                st.stop()

        if not st.session_state.autenticado_admin:
            st.stop()

    # Seleção da categoria e upload de CORTES
    cat_admin = st.selectbox("Categoria para salvar os cortes:", CATEGORIAS, key="cat_admin_upload")
    pasta_admin = os.path.join(BASE_ASSETS, cat_admin, "cortes")
    st.caption(f"Pasta de destino: `{pasta_admin}`")

    arquivos_admin = st.file_uploader(
        "Enviar arquivos de CORTES (.mp4) para esta categoria",
        type=["mp4"], accept_multiple_files=True, key="admin_uploader"
    )

    if arquivos_admin:
        with st.spinner("⏳ Processando e padronizando cortes..."):
            for f in arquivos_admin:
                ext = os.path.splitext(f.name)[1].lower()
                nome_aleatorio = f"{random.randint(1000000, 9999999)}{ext}"
                temp_in = os.path.join(tempfile.gettempdir(), f"adm_input_{nome_aleatorio}")
                with open(temp_in, "wb") as out:
                    out.write(f.read())

                final_out = os.path.join(pasta_admin, nome_aleatorio)

                # Agora salvando o arquivo diretamente, sem padronizar
                shutil.move(temp_in, final_out)

            st.success("✅ Cortes enviados, padronizados e salvos com sucesso!")

    # Listagem e exclusão
    st.write("Arquivos existentes nesta categoria:")
    try:
        arquivos_existentes = sorted([f for f in os.listdir(pasta_admin) if f.lower().endswith(".mp4")])
    except FileNotFoundError:
        arquivos_existentes = []

    if not arquivos_existentes:
        st.info("Nenhum arquivo encontrado nesta categoria.")
    else:
        for arq in arquivos_existentes:
            col1, col2 = st.columns([5, 1])
            with col1:
                st.markdown(f"`{arq}`")
            with col2:
                if st.button("🗑", key=f"del_{cat_admin}_{arq}"):
                    os.remove(os.path.join(pasta_admin, arq))
                    st.success(f"❌ Arquivo '{arq}' excluído.")
                    st.rerun()