import os

import cv2

import random

import threading

import tkinter as tk

from tkinter import ttk

import numpy as np

from pydub import AudioSegment

from pydub.silence import detect_nonsilent

import whisper

import subprocess

import textwrap



VIDEO_WIDTH = 1280

VIDEO_HEIGHT = 720

FPS = 30



CHANNELS = {

    "Deep Psychology": {

        "image_folder": r"D:\CANAIS REDE\Deep Psychology",

        "output_folder": r"D:\CANAIS REDE\videos para postar\Deep Psychology",

        "overlay_image": r"D:\CANAIS REDE\Apresentador\1.png",

    },

    "Doodle Vibes": {

        "image_folder": r"D:\CANAIS REDE\Doodle Vibes",

        "output_folder": r"D:\CANAIS REDE\videos para postar\Doodle Vibes",

        "overlay_image": r"D:\CANAIS REDE\Apresentador\2.png",

    },

    "One Infinite": {

        "image_folder": r"D:\CANAIS REDE\One Infinite",

        "output_folder": r"D:\CANAIS REDE\videos para postar\One Infinite",

        "overlay_image": r"D:\CANAIS REDE\Apresentador\3.png",

    },

    "One Realm": {

        "image_folder": r"D:\CANAIS REDE\One Realm",

        "output_folder": r"D:\CANAIS REDE\videos para postar\One Realm",

        "overlay_image": r"D:\CANAIS REDE\Apresentador\4.png",

    },

    "Sequels": {

        "image_folder": r"D:\CANAIS REDE\Sequels",

        "output_folder": r"D:\CANAIS REDE\videos para postar\Sequels",

        "overlay_image": r"D:\CANAIS REDE\Apresentador\5.png",

    },

}



AUDIO_INPUT_FOLDER = r"D:\CANAIS REDE\CENTRAL AUDIO"

AUDIO_BACKGROUND = r"D:\CANAIS REDE\soundfund.mp3"



FONT_FACE = cv2.FONT_HERSHEY_SIMPLEX





def load_images_from_folder_all(folder):

    files = [f for f in os.listdir(folder) if f.lower().endswith((".png", ".jpg", ".jpeg"))]

    images = []

    for f in files:

        path = os.path.join(folder, f)

        img = cv2.imread(path)

        if img is not None and img.shape[0] > 0 and img.shape[1] > 0:

            img_resized = cv2.resize(img, (VIDEO_WIDTH, VIDEO_HEIGHT), interpolation=cv2.INTER_AREA)

            images.append(img_resized)

    return images





def remover_silencio(audio_segment, silence_thresh=-50, min_silence_len=500, padding=300):

    nao_silencioso = detect_nonsilent(audio_segment, min_silence_len=min_silence_len, silence_thresh=silence_thresh)

    if not nao_silencioso:

        return audio_segment

    partes = []

    for start, end in nao_silencioso:

        start_pad = max(0, start - padding)

        end_pad = min(len(audio_segment), end + padding)

        partes.append(audio_segment[start_pad:end_pad])

    audio_sem_silencio = partes[0]

    for part in partes[1:]:

        audio_sem_silencio += AudioSegment.silent(duration=150) + part

    return audio_sem_silencio





def add_centered_subtitle(frame, text, offset_x=60, offset_y_ratio=0.35):

    h, w = frame.shape[:2]

    font_scale = 1.1

    thickness = 3

    color = (255, 255, 255)

    font = FONT_FACE



    text_size, _ = cv2.getTextSize(text, font, font_scale, thickness)

    text_w, text_h = text_size



    org = (offset_x, int(h * offset_y_ratio))



    cv2.putText(frame, text, (org[0], org[1]), font, font_scale, (0, 0, 0), thickness + 2, cv2.LINE_AA)

    cv2.putText(frame, text, (org[0], org[1]), font, font_scale, color, thickness, cv2.LINE_AA)

    return frame





def split_text_to_lines(text, max_chars=40):

    return textwrap.wrap(text, width=max_chars, break_long_words=False)





def overlay_image_alpha(img, img_overlay, x, y, alpha_mask):

    y1, y2 = max(0, y), min(img.shape[0], y + img_overlay.shape[0])

    x1, x2 = max(0, x), min(img.shape[1], x + img_overlay.shape[1])



    y1o, y2o = max(0, -y), min(img_overlay.shape[0], img.shape[0] - y)

    x1o, x2o = max(0, -x), min(img_overlay.shape[1], img.shape[1] - x)



    if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:

        return



    alpha = alpha_mask[y1o:y2o, x1o:x2o, None] / 255.0

    alpha_inv = 1.0 - alpha



    img_slice = img[y1:y2, x1:x2]

    img_overlay_slice = img_overlay[y1o:y2o, x1o:x2o]



    img[y1:y2, x1:x2] = (alpha * img_overlay_slice + alpha_inv * img_slice).astype(np.uint8)





def preprocess_segments_for_frame_display(segments, fps):

    frame_subtitles = {}

    all_text = "".join([seg['text'].strip() + " " for seg in segments]).strip()



    all_lines = split_text_to_lines(all_text, max_chars=40)

    total_duration = segments[-1]['end'] if segments else 0

    frames_per_line = int(fps * (total_duration / max(len(all_lines), 1)))



    for idx, line in enumerate(all_lines):

        start_frame = idx * frames_per_line

        end_frame = start_frame + frames_per_line

        for frame in range(start_frame, end_frame):

            frame_subtitles[frame] = line



    return frame_subtitles





def create_video_only(video_path, duration, images, fps=FPS, progress_callback=None, segments=None, channel_name=None):

    if not images:

        raise ValueError("Nenhuma imagem encontrada para criação do vídeo")



    width = VIDEO_WIDTH

    height = VIDEO_HEIGHT

    total_frames = int(duration * fps)

    out = cv2.VideoWriter(video_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height))



    overlay_img = None

    if channel_name and channel_name in CHANNELS:

        overlay_path = CHANNELS[channel_name].get("overlay_image", None)

        if overlay_path and os.path.exists(overlay_path):

            overlay_img_bgra = cv2.imread(overlay_path, cv2.IMREAD_UNCHANGED)

            if overlay_img_bgra is not None:

                # Agora redimensiona imagem de overlay para tela cheia (tamanho total do vídeo)

                overlay_img = cv2.resize(overlay_img_bgra, (width, height), interpolation=cv2.INTER_AREA)

            else:

                overlay_img = None



    frame_subtitles = {}

    if segments:

        frame_subtitles = preprocess_segments_for_frame_display(segments, fps)



    current_shift = 0.0

    direction = random.choice([-1, 1])

    speed = 0.4

    max_shift = int(width * 0.03)



    movement_state = "moving"

    movement_frames_count = 0

    movement_frames_duration = random.randint(fps * 5, fps * 10)

    pause_frames_duration = random.randint(fps * 3, fps * 5)



    current_image_index = random.randint(0, len(images) - 1)



    for i in range(total_frames):

        if movement_state == "moving":

            current_shift += direction * speed

            movement_frames_count += 1

            if current_shift > max_shift:

                current_shift = max_shift

                direction = -1

            elif current_shift < -max_shift:

                current_shift = -max_shift

                direction = 1

            if movement_frames_count >= movement_frames_duration:

                movement_state = "paused"

                movement_frames_count = 0

        else:

            movement_frames_count += 1

            if movement_frames_count >= pause_frames_duration:

                movement_state = "moving"

                movement_frames_count = 0

                movement_frames_duration = random.randint(fps * 5, fps * 10)

                pause_frames_duration = random.randint(fps * 3, fps * 5)

                current_image_index = random.randint(0, len(images) - 1)



        img = images[current_image_index].copy()

        M = np.float32([[1, 0, current_shift], [0, 1, 0]])

        img = cv2.warpAffine(img, M, (width, height))



        if overlay_img is not None:

            if overlay_img.shape[2] == 4:

                b, g, r, a = cv2.split(overlay_img)

                overlay_rgb = cv2.merge((b, g, r))

                alpha_mask = a

                overlay_image_alpha(img, overlay_rgb, 0, 0, alpha_mask)

            else:

                img[0:overlay_img.shape[0], 0:overlay_img.shape[1]] = overlay_img



        subtitle_text = frame_subtitles.get(i, "")

        if subtitle_text:

            img = add_centered_subtitle(img, subtitle_text, offset_x=500, offset_y_ratio=0.35)



        out.write(img)

        if progress_callback:

            progress_callback(i + 1, total_frames)

    out.release()





def merge_audio_with_video(video_path, audio_path, output_path, audio_background_path=None):

    audio1 = AudioSegment.from_file(audio_path).set_channels(2)



    if audio_background_path and os.path.exists(audio_background_path):

        audio2 = AudioSegment.from_file(audio_background_path).set_channels(2)

        audio2 = audio2 - 15

        if len(audio2) < len(audio1):

            audio2 *= (len(audio1) // len(audio2) + 1)

        audio2 = audio2[:len(audio1)]

        combined = audio1.overlay(audio2)

    else:

        combined = audio1



    temp_audio_path = "temp_combined_audio.mp3"

    combined.export(temp_audio_path, format="mp3")



    command = [

        "ffmpeg",

        "-y",

        "-i", video_path,

        "-i", temp_audio_path,

        "-c:v", "copy",

        "-c:a", "aac",

        "-shortest",

        output_path

    ]

    subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

    if os.path.exists(temp_audio_path):

        os.remove(temp_audio_path)





def selecionar_canal_por_balanceamento():

    counts = {}

    for channel_name, paths in CHANNELS.items():

        folder = paths["output_folder"]

        try:

            files = [f for f in os.listdir(folder) if f.lower().endswith(".mp4")]

            counts[channel_name] = len(files)

        except Exception:

            counts[channel_name] = 0



    if all(v == 0 for v in counts.values()):

        return random.choice(list(CHANNELS.keys()))



    min_count = min(counts.values())

    candidatos = [ch for ch, c in counts.items() if c == min_count]

    return random.choice(candidatos)





def criar_video_com_interface():

    root = tk.Tk()

    root.title("Criador de Vídeo com imagens e áudio")

    root.geometry("600x250")



    tk.Label(root, text=f"Pasta de entrada Áudios: {AUDIO_INPUT_FOLDER}").pack(pady=7)

    tk.Label(root, text="Coloque arquivos de áudio (.mp3, .wav, .m4a) na pasta acima para iniciar a produção automática.").pack()



    progress_var = tk.IntVar()

    progress_bar = ttk.Progressbar(root, maximum=100, variable=progress_var, length=550)

    progress_bar.pack(pady=7)



    progress_label = tk.Label(root, text="Aguardando arquivos na fila...")

    progress_label.pack(pady=7)



    processing_lock = threading.Lock()

    queue_audios = []

    processing = False



    model = whisper.load_model("small")



    def update_progress_ui(atual, total):

        pct = int(atual / total * 100)

        progress_var.set(pct)

        progress_label.config(text=f"Progresso: {pct}%")

        root.update_idletasks()



    def process_audio_file(audio_path):

        nonlocal processing

        try:

            canal = selecionar_canal_por_balanceamento()

            image_folder = CHANNELS[canal]['image_folder']

            output_folder = CHANNELS[canal]['output_folder']

            if not os.path.exists(output_folder):

                os.makedirs(output_folder)



            images = load_images_from_folder_all(image_folder)

            if not images:

                print(f"Nenhuma imagem válida encontrada em {image_folder}, pulando {os.path.basename(audio_path)}")

                with processing_lock:

                    processing = False

                root.after(100, check_and_start_process)

                return



            progress_var.set(0)

            progress_label.config(text=f"Processando: {os.path.basename(audio_path)} | Canal: {canal}")

            root.update_idletasks()



            audio = AudioSegment.from_file(audio_path)

            silence_thresh = audio.dBFS - 14

            audio_sem_silencio = remover_silencio(audio, silence_thresh=silence_thresh, min_silence_len=400, padding=300)

            temp_audio_clean = "temp_audio_clean.mp3"

            audio_sem_silencio.export(temp_audio_clean, format="mp3")



            duration = audio_sem_silencio.duration_seconds

            base_name = os.path.splitext(os.path.basename(audio_path))[0]

            temp_video = base_name + "_temp.mp4"

            video_final = os.path.join(output_folder, f"{base_name}.mp4")



            result = model.transcribe(temp_audio_clean, language="en")

            segments = result.get('segments', [])



            create_video_only(temp_video, duration, images, fps=FPS, progress_callback=update_progress_ui, segments=segments, channel_name=canal)



            merge_audio_with_video(temp_video, temp_audio_clean, video_final, audio_background_path=AUDIO_BACKGROUND)



            if os.path.exists(temp_video):

                os.remove(temp_video)

            if os.path.exists(temp_audio_clean):

                os.remove(temp_audio_clean)

            try:

                if os.path.exists(audio_path):

                    os.remove(audio_path)

            except Exception as e:

                print(f"Erro ao remover arquivo de áudio original: {e}")



        except Exception as e:

            print(f"Erro ao criar vídeo para {audio_path}: {e}")

        finally:

            with processing_lock:

                processing = False

            root.after(100, check_and_start_process)



    def check_and_start_process():

        nonlocal processing

        with processing_lock:

            if processing or not queue_audios:

                if not queue_audios:

                    progress_label.config(text="Fila vazia, aguardando novos arquivos na pasta:\n" + AUDIO_INPUT_FOLDER)

                return

            next_audio = queue_audios.pop(0)

            processing = True



        threading.Thread(target=process_audio_file, args=(next_audio,), daemon=True).start()



    def scan_for_new_audios():

        try:

            current_files = [f for f in os.listdir(AUDIO_INPUT_FOLDER) if f.lower().endswith((".mp3", ".wav", ".m4a"))]

            abs_files = [os.path.join(AUDIO_INPUT_FOLDER, f) for f in current_files]

        except Exception as e:

            print(f"Erro ao listar pasta de áudio: {e}")

            abs_files = []



        with processing_lock:

            fila_set = set(queue_audios)

            for fpath in abs_files:

                if fpath not in fila_set and os.path.isfile(fpath):

                    queue_audios.append(fpath)



    def periodic_scan():

        try:

            scan_for_new_audios()

            check_and_start_process()

        except Exception as e:

            print(f"Erro no scan ou start do processo: {e}")

        root.after(5000, periodic_scan)



    periodic_scan()

    root.mainloop()





if __name__ == "__main__":

    criar_video_com_interface() . chat re escreva esse codigo para mim e otimize mas para ele ficar mas rapido tanto na edição quanto na exportação mantendo o estilo de edição intacto também melhore a velocidade de indenficar e transcrição das legendas seja mais rapido se tiver um sistema para isso mais rapido mude se for preciso