import tkinter as tk
from tkinter import messagebox
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.auth.transport.requests import Request
import os
import pickle
from datetime import datetime, timedelta
import pytz
import random
import time

# --- CONFIGURAÇÕES ---

TIMEZONE_BR = pytz.timezone("America/Sao_Paulo")

CREDENCIAIS_PATH = r"D:\CANAIS REDE\CREDENCIAL"

CREDENCIAIS_VIDEOS_MAP = {
    "Deep.pickle": r"D:\CANAIS REDE\videos para postar\Deep Psychology",
    "Doodle.pickle": r"D:\CANAIS REDE\videos para postar\Doodle Vibes",
    "OneInfinite.pickle": r"D:\CANAIS REDE\videos para postar\One Infinite",
    "OneRealm.pickle": r"D:\CANAIS REDE\videos para postar\One Realm",
    "Sequels.pickle": r"D:\CANAIS REDE\videos para postar\Sequels"
}

THUMBNAILS_FOLDER = r"D:\CANAIS REDE\thubnail"

DEFAULT_DESCRIPTION = """
🔮 Is the Universe Trying to Tell You Something? Discover the 4 Signs You're Destined to Be with Someone | Carl Jung’s Teachings

Have you ever met someone and instantly felt there was something deeper going on? Like it wasn’t just a coincidence?

In this video, we dive into the profound insights of psychologist Carl Jung and reveal the 4 spiritual and psychological signs that the universe may be aligning your life with another person’s.
From repeated "coincidences" to deep emotional connections and inner transformations, Jung believed that synchronicity and the collective unconscious could guide us to the relationships that truly matter.

If you've ever wondered whether a certain person came into your life for a reason — this video will help you understand why.

👉 Watch until the end to discover how to recognize these signs and what they might mean for your destiny and love life.

✨ Don't forget to like, subscribe, and turn on notifications for more content on Carl Jung, synchronicity, destiny, and deep psychology.

#carljung  #synchronicity  #soulmates  #jungianpsychology  #signsfromtheuniverse  #destiny2  #spirituallove  #JungLove #spiritualawakening  #psychologyoflove  #theone  #universesigns  #deepconnection  #soulconnection  #relationships  #divinetiming 

Keywords (SEO):
Carl Jung soulmate signs, synchronicity in love, Jungian psychology relationships, signs you're meant to be with someone, psychological signs of love, spiritual signs universe, destiny love connection, Carl Jung synchronicity meaning, twin flame signs, universe bringing someone back.
"""

DEFAULT_TAGS = [
    "carl gustav jung","carl gustv jung","carl jung","carl jung arquetipos","carl jung explained",
    "carl jung la sombra","carl jung lecture","carl jung mindset","carl jung philosophy",
    "carl jung psychology","carl jung quotes","carl jung shadow","carl jung shadow work",
    "carl jung teachings","carl jung the red book","carl jung theory","carl jung warning",
    "carl jung wholeness","red book carl jung","the red book carl jung"
]

# --- FUNÇÕES ---

def load_credentials(path_pickle):
    try:
        with open(path_pickle, "rb") as f:
            creds = pickle.load(f)
        if creds.expired and creds.refresh_token:
            creds.refresh(Request())
        return creds
    except Exception as e:
        print(f"Erro ao carregar credencial {path_pickle}: {e}")
        return None

def upload_video(creds, title, description, tags, video_path, thumb_path, privacy_status="private", publish_at=None):
    youtube = build("youtube", "v3", credentials=creds)
    body = {
        "snippet": {
            "title": title,
            "description": description,
            "tags": tags,
            "categoryId": "22"
        },
        "status": {
            "privacyStatus": privacy_status
        }
    }

    if publish_at:
        dt_obj = datetime.fromisoformat(publish_at)
        dt_utc = dt_obj.astimezone(pytz.utc)
        body["status"]["publishAt"] = dt_utc.isoformat()

    media = MediaFileUpload(video_path, mimetype="video/mp4", chunksize=-1, resumable=True)

    request = youtube.videos().insert(part="snippet,status", body=body, media_body=media)

    response = None
    while response is None:
        status, response = request.next_chunk()
        if status:
            print(f"Upload {int(status.progress() * 100)}% do vídeo {os.path.basename(video_path)}")

    video_id = response["id"]

    if thumb_path and os.path.exists(thumb_path):
        try:
            youtube.thumbnails().set(videoId=video_id, media_body=MediaFileUpload(thumb_path)).execute()
        except Exception as e:
            print(f"Não foi possível enviar thumbnail: {e}")

    print(f"Upload finalizado: {video_id}")
    return video_id

def obter_videos(pasta, qtd):
    if not os.path.isdir(pasta):
        return []
    vids = [os.path.join(pasta, f) for f in os.listdir(pasta) if f.lower().endswith(".mp4")]
    vids.sort(key=lambda f: os.path.getctime(f))
    if len(vids) < qtd:
        return []
    return vids[:qtd]

def obter_thumbnails_disponiveis():
    if not os.path.isdir(THUMBNAILS_FOLDER):
        return []
    thumbs = [os.path.join(THUMBNAILS_FOLDER, f) for f in os.listdir(THUMBNAILS_FOLDER) if f.lower().endswith((".jpg", ".jpeg", ".png"))]
    return thumbs

def remover_arquivo(caminho):
    try:
        os.remove(caminho)
    except Exception as e:
        print(f"Erro ao remover arquivo {caminho}: {e}")

def agendar_e_enviar_videos(data_inicio_str, hora_inicio_str, qtds_por_canal):
    try:
        data_inicio = datetime.strptime(data_inicio_str, "%d/%m/%Y")
        hora_inicio = datetime.strptime(hora_inicio_str, "%H:%M").time()
        dt_inicio = datetime.combine(data_inicio, hora_inicio)
        dt_inicio = TIMEZONE_BR.localize(dt_inicio)
    except Exception as e:
        messagebox.showerror("Erro", f"Formato de data/hora inválido: {e}")
        return

    credenciais_validas = {}
    credenciais_invalidas = []
    for nome_pickle, pasta_vid in CREDENCIAIS_VIDEOS_MAP.items():
        caminho_cred = os.path.join(CREDENCIAIS_PATH, nome_pickle)
        creds_obj = load_credentials(caminho_cred)
        if creds_obj is None:
            credenciais_invalidas.append(nome_pickle)
        else:
            canal = nome_pickle.split(".")[0]
            credenciais_validas[nome_pickle] = (creds_obj, canal, pasta_vid)

    if credenciais_invalidas:
        messagebox.showerror("Credenciais inválidas ou não carregadas", f"Arquivos .pickle inválidos:\n" + "\n".join(credenciais_invalidas))
        return

    insuficientes = []
    vids_por_canal = {}
    for nome_pickle, (creds_obj, canal, pasta_vid) in credenciais_validas.items():
        qtd_can = qtds_por_canal.get(canal, 0)
        if qtd_can == 0:
            continue
        vids = obter_videos(pasta_vid, qtd_can)
        if len(vids) < qtd_can:
            insuficientes.append(f"{canal} - vídeos insuficientes (pediu {qtd_can}, tem {len(vids)})")
        else:
            vids_por_canal[nome_pickle] = vids

    if insuficientes:
        messagebox.showwarning("Vídeos insuficientes", f"Não há vídeos suficientes nos canais:\n" + "\n".join(insuficientes))
        return

    total_videos = sum(qtd for qtd in qtds_por_canal.values() if qtd > 0)

    thumbs = obter_thumbnails_disponiveis()
    if len(thumbs) < total_videos:
        messagebox.showwarning("Thumbs insuficientes", f"Thumbnails disponíveis ({len(thumbs)}) são menos que necessários ({total_videos})")
        return

    thumbs_disponiveis = thumbs.copy()

    enviados = 0

    tarefas = []
    for nome_pickle, (creds_obj, canal, pasta_vid) in credenciais_validas.items():
        qtd_can = qtds_por_canal.get(canal, 0)
        if qtd_can == 0:
            continue
        vids = vids_por_canal.get(nome_pickle, [])
        for i in range(qtd_can):
            tarefas.append( (canal, nome_pickle, creds_obj, vids[i]) )

    for i, (canal, nome_pickle, creds_obj, video_path) in enumerate(tarefas):
        if not thumbs_disponiveis:
            messagebox.showerror("Erro", "Acabaram thumbnails durante envio, abortando.")
            return
        thumb_path = random.choice(thumbs_disponiveis)
        thumbs_disponiveis.remove(thumb_path)

        dt_postagem = dt_inicio + timedelta(hours=i)
        publish_at_iso = dt_postagem.isoformat()

        titulo = os.path.splitext(os.path.basename(video_path))[0]

        try:
            print(f"Iniciando upload: Canal {canal}, vídeo {titulo} agendado para {publish_at_iso}")
            video_id = upload_video(
                creds=creds_obj,
                title=titulo,
                description=DEFAULT_DESCRIPTION,
                tags=DEFAULT_TAGS,
                video_path=video_path,
                thumb_path=thumb_path,
                privacy_status="private",
                publish_at=publish_at_iso
            )
            if video_id:
                remover_arquivo(video_path)
                remover_arquivo(thumb_path)
                enviados += 1
                print(f"Upload completado: {video_id}")
                time.sleep(10)
            else:
                messagebox.showerror("Erro", f"Falha ao enviar vídeo {titulo}")
                return
        except Exception as e:
            messagebox.showerror("Erro no upload", f"Erro ao enviar vídeo {titulo}: {e}")
            return

    messagebox.showinfo("Sucesso", f"{enviados} vídeos agendados e enviados para {len(credenciais_validas)} canais.")

# --- INTERFACE ---

root = tk.Tk()
root.title("Agendador Carl Jung - Multi Canais com Upload")
root.geometry("700x600")

frame_credenciais_status = tk.LabelFrame(root, text="Status das Credenciais")
frame_credenciais_status.pack(fill="x", padx=10, pady=10)

def atualizar_status_credenciais_ui():
    for widget in frame_credenciais_status.winfo_children():
        widget.destroy()
    for nome_pickle in CREDENCIAIS_VIDEOS_MAP.keys():
        caminho_cred = os.path.join(CREDENCIAIS_PATH, nome_pickle)
        if not os.path.exists(caminho_cred):
            cor = "red"
            texto = f"{nome_pickle} - Arquivo .pickle não encontrado"
        else:
            creds_obj = load_credentials(caminho_cred)
            if creds_obj is None:
                cor = "red"
                texto = f"{nome_pickle} - Credencial inválida"
            else:
                cor = "green"
                texto = f"{nome_pickle} - Credencial válida"
        lbl = tk.Label(frame_credenciais_status, text=texto, fg=cor, font=("Arial", 12, "bold"))
        lbl.pack(anchor="w")

atualizar_status_credenciais_ui()

frame_conf = tk.LabelFrame(root, text="Configurar agendamento")
frame_conf.pack(fill="x", padx=10, pady=10)

tk.Label(frame_conf, text="Data de início (dd/mm/aaaa):").grid(row=0, column=0, sticky="w", padx=5, pady=5)
entrada_data = tk.Entry(frame_conf)
entrada_data.grid(row=0, column=1, sticky="w", padx=5, pady=5)
entrada_data.insert(0, datetime.now().strftime("%d/%m/%Y"))

tk.Label(frame_conf, text="Hora de início (HH:MM):").grid(row=1, column=0, sticky="w", padx=5, pady=5)
entrada_hora = tk.Entry(frame_conf)
entrada_hora.grid(row=1, column=1, sticky="w", padx=5, pady=5)
entrada_hora.insert(0, "03:00")

spinbox_qtds = {}
linha_inicial = 2

for i, nome_pickle in enumerate(CREDENCIAIS_VIDEOS_MAP.keys()):
    canal = nome_pickle.split(".")[0]
    tk.Label(frame_conf, text=f"Qtd vídeos para canal {canal} (0 a 12):").grid(row=linha_inicial + i, column=0, sticky="w", padx=5, pady=5)
    sb = tk.Spinbox(frame_conf, from_=0, to=12, width=5)
    sb.grid(row=linha_inicial + i, column=1, sticky="w", padx=5, pady=5)
    sb.delete(0, "end")
    sb.insert(0, "0")
    spinbox_qtds[canal] = sb

def on_agendar_click():
    data = entrada_data.get()
    hora = entrada_hora.get()

    qtds_por_canal = {}
    for canal, sb in spinbox_qtds.items():
        try:
            v = int(sb.get())
            if v < 0 or v > 12:
                raise ValueError()
            qtds_por_canal[canal] = v
        except:
            messagebox.showwarning("Atenção", f"Quantidade inválida para canal {canal}. Informe número inteiro entre 0 e 12.")
            return

    total_videos = sum(v for v in qtds_por_canal.values())
    if total_videos == 0:
        messagebox.showwarning("Atenção", "Nenhum vídeo selecionado para envio. Escolha quantidade > 0 para algum canal.")
        return

    agendar_e_enviar_videos(data, hora, qtds_por_canal)

btn_agendar = tk.Button(root, text="Agendar e Enviar vídeos para todos os canais", command=on_agendar_click)
btn_agendar.pack(pady=20)

root.mainloop() . chat coloque para o invês dele escolher entre as thumb de uma mesma pasta a todos não ele vai fazer o seguinte /. todos que forem (D:\CANAIS REDE\videos para postar\Deep Psychology) as thumb serão de (D:\CANAIS REDE\thubnail\Deep) . (D:\CANAIS REDE\videos para postar\Doodle Vibes) pegar de (D:\CANAIS REDE\thubnail\Doodle Vibes)  . (D:\CANAIS REDE\videos para postar\Sequels) pegar de (D:\CANAIS REDE\thubnail\Sequels) . "Por favor, me dê o código completo e integral da solução, linha por linha, sem resumir ou omitir nada, mesmo que seja um código muito longo. Divida em partes se necessário, mas garanta que todas as funções, classes e trechos estejam presentes na íntegra." não quero comentários do tipo “o restante do código é este ou aquele” — tudo deve ser escrito. chat me de tudo mesmo que o codigo fique gigante e passe do limite faça o codigo completo mesmo que fique longo pfv você tá abreviando partes do codigo me de completo sem abreviar pfv escreva todas as partes linha por linha não tente me enganar . não pessa para minha incluir nem nada escreva você tudo