import streamlit as st import os import json import time import subprocess import random import string import tempfile import shutil import mimetypes import datetime BASE_FOLDER = "uploaded_files" CATEGORIES = ["AVATAR WORLD", "BLOX FRUITS", "TOCA LIFE"] EXPIRATION_FILE = "expirations.json" # --- Estilos CSS --- st.markdown(""" """, unsafe_allow_html=True) # Cria as pastas se não existirem for cat in CATEGORIES: os.makedirs(os.path.join(BASE_FOLDER, cat), exist_ok=True) # Carrega dados de expiração if os.path.exists(EXPIRATION_FILE): with open(EXPIRATION_FILE, "r") as f: expirations = json.load(f) else: expirations = {} st.title("📂 File Manager por Categoria") # --- Funções auxiliares --- def remove_expired_files(): """Remove arquivos expirados automaticamente""" changed = False now = time.time() expired_files = [] for file_full, expire_time in list(expirations.items()): cat, file = file_full.split("|||") file_path = os.path.join(BASE_FOLDER, cat, file) if now > expire_time: if os.path.exists(file_path): os.remove(file_path) expired_files.append(file_full) changed = True for file_full in expired_files: expirations.pop(file_full) if changed: with open(EXPIRATION_FILE, "w") as f: json.dump(expirations, f) def random_string(length=12): return ''.join(random.choices(string.ascii_letters + string.digits, k=length)) def process_video(file_path, hard_mode=False): """Processa vídeo removendo metadados e mascarando vestígios do ffmpeg""" temp_fd, temp_out = tempfile.mkstemp(suffix=".mp4") os.close(temp_fd) if not hard_mode: shutil.copy(file_path, temp_out) return temp_out # Randomizações técnicas crf = str(random.randint(18, 26)) bitrate = f"{random.randint(96, 192)}k" fps = f"{random.uniform(29.5, 30.5):.2f}" # Rotação de brands major_brand = random.choice(["isom", "iso2", "mp42", "avc1", "dash", "iso3"]) compatible_sets = [ ["isom", "iso2", "avc1", "mp41"], ["mp42", "isom", "avc1"], ["iso5", "mp41", "isom"], ["iso2", "mp42", "isom"] ] compatible_brands = " ".join(random.choice(compatible_sets)) compressor = random_string(random.randint(6, 12)) encoder_name = random_string(random.randint(6, 14)) # Datas nunca zeradas start_date = datetime.datetime.now() - datetime.timedelta(days=180) random_date = start_date + datetime.timedelta( days=random.randint(0, 180), seconds=random.randint(0, 86400) ) date_str = random_date.strftime("%Y-%m-%d %H:%M:%S") # Metadados falsos meta = { "title": random_string(random.randint(8, 20)), "comment": random_string(random.randint(8, 20)), "description": random_string(random.randint(8, 20)), "artist": random_string(random.randint(8, 20)), "album": random_string(random.randint(8, 20)), "genre": random_string(random.randint(5, 15)), "publisher": random_string(random.randint(5, 15)), "encoded_by": random_string(random.randint(5, 15)), "location": random_string(random.randint(5, 15)), "encoder": encoder_name, "creation_time": date_str, "modify_time": date_str } cmd_ffmpeg = [ "ffmpeg", "-y", "-i", file_path, "-map", "0:v", "-map", "0:a?", "-map_metadata", "-1", "-c:v", "libx264", "-preset", "fast", "-crf", crf, "-c:a", "aac", "-b:a", bitrate, "-r", fps, "-movflags", "use_metadata_tags+faststart", "-metadata", f"major_brand={major_brand}", "-metadata", f"compatible_brands={compatible_brands}", "-metadata", f"encoder={encoder_name}", "-metadata", f"CompressorName={compressor}", "-fflags", "+bitexact", "-flags", "+bitexact", ] for k, v in meta.items(): cmd_ffmpeg += ["-metadata", f"{k}={v}"] cmd_ffmpeg.append(temp_out) subprocess.run(cmd_ffmpeg, check=True) return temp_out # --- Apagar arquivos vencidos ao iniciar --- remove_expired_files() # --- Upload --- st.header("📤 Upload de Arquivos") st.subheader("Selecione uma categoria:") categoria = st.radio("Categoria:", CATEGORIES, index=None) hard_mode = st.checkbox("Ativar randomização HARD (vídeos apenas)") if "last_upload" not in st.session_state: st.session_state.last_upload = None if categoria: uploaded_files = st.file_uploader( f"Selecione arquivos para '{categoria}'", accept_multiple_files=True, key=f"uploader_{categoria}" ) auto_delete = st.checkbox("Excluir automaticamente após 24 horas") if uploaded_files: for uploaded_file in uploaded_files: if st.session_state.last_upload == uploaded_file.name: continue folder = os.path.join(BASE_FOLDER, categoria) os.makedirs(folder, exist_ok=True) mime, _ = mimetypes.guess_type(uploaded_file.name) is_video = mime and mime.startswith("video") with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(uploaded_file.name)[1]) as tmp: tmp.write(uploaded_file.read()) tmp_path = tmp.name if is_video and hard_mode: final_tmp = process_video(tmp_path, hard_mode=True) else: final_tmp = tmp_path if hard_mode and is_video: new_name = random_string(16) + ".mp4" else: new_name = uploaded_file.name file_path = os.path.join(folder, new_name) shutil.move(final_tmp, file_path) if auto_delete: key = f"{categoria}|||{new_name}" expirations[key] = time.time() + 24 * 60 * 60 with open(EXPIRATION_FILE, "w") as f: json.dump(expirations, f) st.session_state.last_upload = uploaded_file.name st.success(f"Arquivo '{new_name}' enviado com sucesso!") # --- Lista de Arquivos agrupada por pasta --- st.header("📄 Arquivos Disponíveis") for categoria in CATEGORIES: folder = os.path.join(BASE_FOLDER, categoria) files = os.listdir(folder) st.subheader(f"📁 {categoria}") if not files: st.info("Nenhum arquivo na categoria.") else: for file in files: st.markdown(f"