• 02-08-2026, 21:29:13
    #1
    İhtiyacı olan vardır belki metini gpt ye yazdır istersen api çek metinide yazsın kodlarla oynar ayarlarsınız görselerin oldugu klasörleri seç video yapsın. Klasörden her defasında rast gele sıralama olarak fotoğraf seçer ve 5 saniye olarak yanyana koyar %50 ihtimalle yavaşça yaklaştırma %50 ihtimalle yavaşça uzaklaştırma efekti ekler hepsine geçiş efekti ekler eğer klasörde video varsa video içerisinden rast gele 3 saniye kesit alır aynalama ekler ve 3 görselden sonra 3 saniyelik kesit koyar birden fazla video varsa 3er saniye alır sonra tekrar ilk videodan rastgele 3 saniye alır hep aynı videodan almaz aynalama kullanır hepsine otomatik sese çevirir sınırsız ses düzenler isteyen kafasına göre özellik ekleyebilir



    import os
    import sys
    import time
    import re
    import asyncio
    import random
    import threading
    import gc  # Bellek (RAM) temizliği için
    from datetime import datetime
    import numpy as np
    import PIL.Image
    from PIL import ImageFilter
    import tkinter as tk
    from tkinter import filedialog, messagebox
    
    # CustomTkinter İçe Aktarımı
    import customtkinter as ctk
    
    # MoviePy - Pillow 10+ uyumluluk yaması
    if not hasattr(PIL.Image, 'ANTIALIAS'):
        PIL.Image.ANTIALIAS = PIL.Image.Resampling.LANCZOS
    
    import edge_tts
    from moviepy.editor import ImageClip, AudioFileClip, VideoFileClip, concatenate_videoclips, VideoClip, vfx
    
    # ==================== TEMA AYARLARI ====================
    ctk.set_appearance_mode("Dark")        # "Dark" veya "Light"
    ctk.set_default_color_theme("blue")    # "blue", "green", "dark-blue"
    
    IMAGE_DURATION = 5.0        # Her fotoğrafın kalma süresi (sn)
    VIDEO_CLIP_DURATION = 3.0   # Videolardan çekilecek kesit süresi (sn)
    TRANSITION_DURATION = 1.0   # Geçiş yumuşaklığı (sn)
    
    # İNGİLİZCE SES SEÇENEKLERİ
    VOICES = {
        "Erkek Ses (Christopher - Derin & Etkileyici) [EN]": "en-US-ChristopherNeural",
        "Kadın Ses (Ava - Doğal & Akıcı) [EN]": "en-US-AvaNeural",
        "Erkek Ses (Eric - Haberci Tonu) [EN]": "en-US-EricNeural",
        "Kadın Ses (Emma - Enerjik) [EN]": "en-US-EmmaNeural"
    }
    
    def clean_script_for_tts(text):
        text = re.sub(r'\(.*?\)', '', text)
        text = re.sub(r'\[.*?\]', '', text)
        text = re.sub(r'^(Narrator|Speaker|User|Host|Voiceover)\s*:\s*', '', text, flags=re.IGNORECASE | re.MULTILINE)
        text = text.replace('*', '').replace('#', '')
        text = re.sub(r'\n+', '\n', text)
        return text.strip()
    
    async def text_to_speech(text, output_filename, voice_code):
        communicate = edge_tts.Communicate(text, voice_code)
        await communicate.save(output_filename)
    
    def create_capcut_style_clip(img_path, duration=5.0, target_size=(1920, 1080)):
        tw, th = target_size
        img = PIL.Image.open(img_path).convert("RGB")
        img_w, img_h = img.size
    
        # 1. Arka Plan (Bulanık Zemin)
        ratio_bg = max(tw / img_w, th / img_h)
        bg_w, bg_h = int(img_w * ratio_bg), int(img_h * ratio_bg)
        bg_img = img.resize((bg_w, bg_h), PIL.Image.Resampling.LANCZOS)
        left = (bg_w - tw) // 2
        top = (bg_h - th) // 2
        bg_img = bg_img.crop((left, top, left + tw, top + th)).filter(ImageFilter.GaussianBlur(radius=30))
    
        # 2. Ön Plan Temel Boyutlandırması
        ratio_fg = min(tw / img_w, th / img_h)
        fg_w, fg_h = int(img_w * ratio_fg), int(img_h * ratio_fg)
        fg_base = img.resize((fg_w, fg_h), PIL.Image.Resampling.LANCZOS)
    
        zoom_direction = random.choice(["in", "out"])
    
        # 3. Canlı Ken Burns Zoom Efekt Üreteci
        def make_frame(t):
            progress = t / duration if duration > 0 else 0
            scale = 1.0 + (0.12 * progress) if zoom_direction == "in" else 1.12 - (0.12 * progress)
    
            curr_w = int(fg_w * scale)
            curr_h = int(fg_h * scale)
    
            fg_resized = fg_base.resize((curr_w, curr_h), PIL.Image.Resampling.LANCZOS)
    
            frame = bg_img.copy()
            paste_x = (tw - curr_w) // 2
            paste_y = (th - curr_h) // 2
            frame.paste(fg_resized, (paste_x, paste_y))
    
            return np.array(frame)
    
        return VideoClip(make_frame, duration=duration)
    
    def get_random_video_snippet(video_path, clip_duration=3.0, target_size=(1920, 1080)):
        """Seçilen videodan ANLIK olarak rastgele 3sn sessiz, %50 aynalanmış kesit ve ana dosyayı döndürür."""
        try:
            full_video = VideoFileClip(video_path)
            dur = full_video.duration
    
            if dur <= 0.5:
                full_video.close()
                return None, None
    
            # 1. Her çağrıldığında RASTGELE bir saniye seçer
            if dur > clip_duration:
                start_time = random.uniform(0, dur - clip_duration)
                sub_clip = full_video.subclip(start_time, start_time + clip_duration)
            else:
                sub_clip = full_video.subclip(0, dur)
    
            # 2. SESİ KAPAT
            sub_clip = sub_clip.without_audio()
    
            # 3. %50 İHTİMALLE YATAY AYNALAMA
            if random.choice([True, False]):
                sub_clip = sub_clip.fx(vfx.mirror_x)
    
            # 4. 1080p Boyutlandırma
            sub_clip = sub_clip.resize(height=target_size[1])
            if sub_clip.w > target_size[0]:
                sub_clip = sub_clip.crop(x_center=sub_clip.w/2, width=target_size[0])
    
            return sub_clip, full_video
        except Exception:
            return None, None
    
    # ==================== KUYRUKLU MODERN ARAYÜZ ====================
    class VideoBotApp(ctk.CTk):
        def __init__(self):
            super().__init__()
    
            self.title("🎬 YouTube Content Studio Pro v4.0 (GPU & RAM Accelerated)")
            self.geometry("1080x880")
            self.resizable(True, True)
    
            self.selected_image_folder = os.path.abspath("images")
            if not os.path.exists(self.selected_image_folder):
                os.makedirs(self.selected_image_folder)
    
            self.queue = []
            self.build_gui()
    
        def build_gui(self):
            header_frame = ctk.CTkFrame(self, fg_color="transparent")
            header_frame.pack(fill="x", padx=20, pady=(15, 5))
    
            title_label = ctk.CTkLabel(
                header_frame, text="🎬 YOUTUBE CONTENT STUDIO (NVIDIA NVENC GPU ACCELERATED)", 
                font=ctk.CTkFont(family="Segoe UI", size=18, weight="bold")
            )
            title_label.pack(side="left")
    
            self.status_badge = ctk.CTkLabel(
                header_frame, text="● SİSTEM HAZIR", 
                font=ctk.CTkFont(family="Segoe UI", size=11, weight="bold"),
                text_color="#10b981", fg_color="#1f2937", corner_radius=8, padx=12, pady=4
            )
            self.status_badge.pack(side="right")
    
            main_layout = ctk.CTkFrame(self, fg_color="transparent")
            main_layout.pack(fill="both", expand=True, padx=20, pady=5)
    
            left_column = ctk.CTkFrame(main_layout, fg_color="transparent")
            left_column.pack(side="left", fill="both", expand=True, padx=(0, 10))
    
            right_column = ctk.CTkFrame(main_layout, width=340, corner_radius=12)
            right_column.pack(side="right", fill="both", padx=(10, 0))
    
            # --- SOL KOLON ---
            editor_card = ctk.CTkFrame(left_column, corner_radius=12)
            editor_card.pack(fill="both", expand=True, pady=(0, 10))
    
            editor_header = ctk.CTkFrame(editor_card, fg_color="transparent")
            editor_header.pack(fill="x", padx=15, pady=(10, 5))
    
            ctk.CTkLabel(editor_header, text="📝 İngilizce Senaryo / Metin Girişi", font=ctk.CTkFont(size=13, weight="bold")).pack(side="left")
    
            btn_clear = ctk.CTkButton(
                editor_header, text="🗑️ Temizle", width=70, height=24, 
                fg_color="transparent", hover_color="#374151", text_color="#9ca3af",
                command=self.clear_text
            )
            btn_clear.pack(side="right")
    
            self.script_input = ctk.CTkTextbox(editor_card, font=("Consolas", 12), corner_radius=8, height=180)
            self.script_input.pack(fill="both", expand=True, padx=15, pady=5)
            self.script_input.bind("<KeyRelease>", self.update_stats)
    
            stats_frame = ctk.CTkFrame(editor_card, fg_color="transparent")
            stats_frame.pack(fill="x", padx=15, pady=(5, 10))
    
            self.lbl_chars = ctk.CTkLabel(stats_frame, text="Karakter: 0", font=ctk.CTkFont(size=11, weight="bold"), text_color="#3b82f6")
            self.lbl_chars.pack(side="left", padx=(0, 15))
    
            self.lbl_time = ctk.CTkLabel(stats_frame, text="Süre: ~0 sn", font=ctk.CTkFont(size=11), text_color="#9ca3af")
            self.lbl_time.pack(side="left")
    
            settings_card = ctk.CTkFrame(left_column, corner_radius=12)
            settings_card.pack(fill="x", pady=5)
    
            settings_inner = ctk.CTkFrame(settings_card, fg_color="transparent")
            settings_inner.pack(fill="x", padx=15, pady=10)
    
            ctk.CTkLabel(settings_inner, text="🎙️ İngilizce Ses:", font=ctk.CTkFont(size=11, weight="bold")).grid(row=0, column=0, sticky="w", pady=4)
            self.voice_var = ctk.StringVar(value=list(VOICES.keys())[0])
            voice_dropdown = ctk.CTkOptionMenu(settings_inner, variable=self.voice_var, values=list(VOICES.keys()), width=350, corner_radius=8)
            voice_dropdown.grid(row=0, column=1, sticky="w", pady=4, padx=(10, 0))
    
            ctk.CTkLabel(settings_inner, text="📁 Medya Klasörü:", font=ctk.CTkFont(size=11, weight="bold")).grid(row=1, column=0, sticky="w", pady=4)
            folder_frame = ctk.CTkFrame(settings_inner, fg_color="transparent")
            folder_frame.grid(row=1, column=1, sticky="ew", pady=4, padx=(10, 0))
    
            self.lbl_folder_path = ctk.CTkLabel(
                folder_frame, text=self.selected_image_folder, font=ctk.CTkFont(size=10),
                text_color="#9ca3af", fg_color="#111827", corner_radius=8, anchor="w", padx=10, height=30, width=240
            )
            self.lbl_folder_path.pack(side="left", padx=(0, 5))
    
            btn_select_folder = ctk.CTkButton(folder_frame, text="📂 Seç", width=60, height=30, corner_radius=8, command=self.select_folder)
            btn_select_folder.pack(side="right")
    
            btn_add_queue = ctk.CTkButton(
                left_column, text="➕ BU VİDEOYU KUYRUĞA EKLE", font=ctk.CTkFont(size=12, weight="bold"),
                fg_color="#10b981", hover_color="#059669", height=38, corner_radius=8, command=self.add_to_queue
            )
            btn_add_queue.pack(fill="x", pady=(5, 0))
    
            # --- SAĞ KOLON ---
            queue_header = ctk.CTkFrame(right_column, fg_color="transparent")
            queue_header.pack(fill="x", padx=15, pady=(12, 5))
    
            ctk.CTkLabel(queue_header, text="📋 İş Kuyruğu", font=ctk.CTkFont(size=13, weight="bold")).pack(side="left")
    
            btn_clear_queue = ctk.CTkButton(
                queue_header, text="Kuyruğu Temizle", width=90, height=22, 
                fg_color="transparent", hover_color="#ef4444", text_color="#f87171", command=self.clear_queue
            )
            btn_clear_queue.pack(side="right")
    
            self.queue_box = ctk.CTkTextbox(right_column, font=("Consolas", 10), corner_radius=8)
            self.queue_box.pack(fill="both", expand=True, padx=12, pady=5)
            self.queue_box.configure(state="disabled")
    
            self.lbl_queue_count = ctk.CTkLabel(right_column, text="Bekleyen İş: 0 Video", font=ctk.CTkFont(size=11, weight="bold"), text_color="#9ca3af")
            self.lbl_queue_count.pack(pady=(5, 12))
    
            # --- ALT AKSİYON & LOG ---
            action_frame = ctk.CTkFrame(self, fg_color="transparent")
            action_frame.pack(fill="x", padx=20, pady=5)
    
            self.btn_start_batch = ctk.CTkButton(
                action_frame, text="⚡ KUYRUĞU BAŞLAT (SABAHA KADAR RENDER ET)", font=ctk.CTkFont(size=13, weight="bold"),
                height=45, corner_radius=10, command=self.start_batch_process
            )
            self.btn_start_batch.pack(fill="x", pady=(0, 5))
    
            self.progress = ctk.CTkProgressBar(action_frame, height=10, corner_radius=5)
            self.progress.pack(fill="x")
            self.progress.set(0)
    
            log_card = ctk.CTkFrame(self, corner_radius=12)
            log_card.pack(fill="both", expand=True, padx=20, pady=(5, 15))
    
            self.log_area = ctk.CTkTextbox(log_card, font=("Consolas", 10), text_color="#10b981", fg_color="#090a0f", corner_radius=8, height=140)
            self.log_area.pack(fill="both", expand=True, padx=12, pady=10)
    
            self.log("🚀 Sistem hazır! GPU Hızlandırması (NVIDIA NVENC) Etkinleştirildi.")
    
        def select_folder(self):
            folder = filedialog.askdirectory(title="Görsellerin ve Videoların Olduğu Klasörü Seçin", initialdir=self.selected_image_folder)
            if folder:
                self.selected_image_folder = os.path.abspath(folder)
                display_path = self.selected_image_folder if len(self.selected_image_folder) < 32 else "..." + self.selected_image_folder[-28:]
                self.lbl_folder_path.configure(text=display_path)
    
        def clear_text(self):
            self.script_input.delete("1.0", tk.END)
            self.update_stats()
    
        def update_stats(self, event=None):
            text = self.script_input.get("1.0", tk.END).strip()
            char_count = len(text)
            est_seconds = int(char_count / 14.5) if char_count > 0 else 0
            self.lbl_chars.configure(text=f"Karakter: {char_count:,}")
            self.lbl_time.configure(text=f"Süre: ~{est_seconds} sn")
    
        def add_to_queue(self):
            text = self.script_input.get("1.0", tk.END).strip()
            if not text:
                messagebox.showwarning("Eksik Metin", "Lütfen önce İngilizce senaryo metnini girin kanka!")
                return
    
            item = {
                "id": len(self.queue) + 1,
                "text": text,
                "folder": self.selected_image_folder,
                "voice_name": self.voice_var.get(),
                "voice_code": VOICES[self.voice_var.get()]
            }
    
            self.queue.append(item)
            self.refresh_queue_ui()
            self.log(f"➕ [KUYRUK] {item['id']}. Video eklendi! ({len(text)} Karakter | Klasör: {os.path.basename(item['folder'])})")
            self.clear_text()
    
        def clear_queue(self):
            self.queue.clear()
            self.refresh_queue_ui()
            self.log("🧹 İş kuyruğu tamamen temizlendi.")
    
        def refresh_queue_ui(self):
            self.queue_box.configure(state="normal")
            self.queue_box.delete("1.0", tk.END)
    
            for i, item in enumerate(self.queue, 1):
                folder_name = os.path.basename(item['folder'])
                snippet = item['text'][:25].replace('\n', ' ') + "..."
                self.queue_box.insert(tk.END, f"#{i} | {folder_name}\n    📝 {snippet}\n-----------------------------------\n")
    
            self.queue_box.configure(state="disabled")
            self.lbl_queue_count.configure(text=f"Bekleyen İş: {len(self.queue)} Video")
    
        def log(self, message):
            now = datetime.now().strftime("%H:%M:%S")
            self.log_area.insert(tk.END, f"[{now}] {message}\n")
            self.log_area.see(tk.END)
    
        def set_progress(self, val):
            self.progress.set(val / 100.0)
    
        def set_status(self, text, is_working=False):
            color = "#f59e0b" if is_working else "#10b981"
            self.status_badge.configure(text=f"● {text.upper()}", text_color=color)
    
        def start_batch_process(self):
            if not self.queue:
                messagebox.showwarning("Kuyruk Boş", "Kuyrukta hiç video yok! Önce metin girip 'Kuyruğa Ekle' butonuna bas kanka.")
                return
    
            self.btn_start_batch.configure(state="disabled", text="⏳ GECE MODU AKTİF (GPU RENDER EDİLİYOR...)")
            self.set_status("GPU RENDER EDİLİYOR", is_working=True)
            threading.Thread(target=self.run_batch_queue, daemon=True).start()
    
        def run_batch_queue(self):
            total_jobs = len(self.queue)
            self.log(f"🚀 TOPLU İŞLEM BAŞLATILDI! Toplam {total_jobs} video NVIDIA GPU desteğiyle render edilecek.")
    
            for index, item in enumerate(list(self.queue), 1):
                # Her döngüde RAM temizliği için açılan tüm clip nesnelerini burada toplayacağız
                clips_to_close = []
                audio = None
                video = None
                final_video = None
    
                try:
                    self.log(f"\n🎬 === [VİDEO {index}/{total_jobs} BAŞLADI] ===")
                    self.set_progress(5)
    
                    # 1. Metin & İngilizce Ses
                    clean_text = clean_script_for_tts(item['text'])
                    self.log(f"🎙️ İngilizce Ses üretiliyor ({item['voice_name']})...")
                    audio_path = f"temp_voice_{index}.mp3"
                    asyncio.run(text_to_speech(clean_text, audio_path, item['voice_code']))
                    
                    audio = AudioFileClip(audio_path)
                    audio_duration = audio.duration
                    self.set_progress(25)
    
                    # 2. Klasördeki Resim ve Videoları Arama
                    media_folder = item['folder']
                    all_files = os.listdir(media_folder)
    
                    raw_images = [os.path.join(media_folder, f) for f in all_files if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
                    raw_videos = [os.path.join(media_folder, f) for f in all_files if f.lower().endswith(('.mp4', '.mov', '.avi', '.mkv'))]
    
                    if not raw_images and not raw_videos:
                        self.log(f"❌ HATA: '{media_folder}' klasöründe hiç resim veya video yok! Atlanıyor.")
                        if audio: audio.close()
                        if os.path.exists(audio_path): os.remove(audio_path)
                        continue
    
                    self.log(f"📁 Klasör İçeriği: {len(raw_images)} Resim, {len(raw_videos)} Video bulundu.")
    
                    # Fotoğraf Klip Listesi
                    random.shuffle(raw_images)
                    img_clips = []
                    for img_p in raw_images:
                        ic = create_capcut_style_clip(img_p, duration=IMAGE_DURATION)
                        img_clips.append(ic)
                        clips_to_close.append(ic)
    
                    # 3. Klipleri Harmanla (Tüm Videolar Arasında Eşit Sirkülasyon + Dinamik Kesim)
                    final_clips_sequence = []
                    current_timeline_duration = 0
                    img_idx = 0
                    video_pointer = 0  # Videoları sırayla eşit gezmek için imleç
    
                    if raw_videos:
                        random.shuffle(raw_videos)
    
                    while current_timeline_duration < audio_duration + 2.0:
                        # 2 Fotoğraf Ekle
                        for _ in range(2):
                            if img_clips:
                                c = img_clips[img_idx % len(img_clips)]
                                final_clips_sequence.append(c)
                                current_timeline_duration += (IMAGE_DURATION - TRANSITION_DURATION)
                                img_idx += 1
    
                        # 1 Video Kesiti Ekle (Eğer klasörde video varsa)
                        if raw_videos:
                            selected_video_path = raw_videos[video_pointer % len(raw_videos)]
                            video_pointer += 1
    
                            # O an videodan RASTGELE sıfırdan 3 saniye kes
                            vc, full_vid = get_random_video_snippet(selected_video_path, clip_duration=VIDEO_CLIP_DURATION)
                            if vc:
                                final_clips_sequence.append(vc)
                                current_timeline_duration += (VIDEO_CLIP_DURATION - TRANSITION_DURATION)
                                clips_to_close.append(vc)
                                if full_vid:
                                    clips_to_close.append(full_vid)
    
                    # Yumuşak Geçişler (Crossfade)
                    processed_clips = []
                    for i, clip in enumerate(final_clips_sequence):
                        if i > 0:
                            clip = clip.crossfadein(TRANSITION_DURATION)
                        processed_clips.append(clip)
    
                    self.set_progress(60)
    
                    # 4. GPU (NVIDIA NVENC) RENDER
                    output_name = f"final_video_{index}_{datetime.now().strftime('%H%M%S')}.mp4"
                    self.log(f"🔥 GPU Render Alınıyor (NVIDIA NVENC + Ryzen 12 Çekirdek) -> {output_name}")
    
                    video = concatenate_videoclips(processed_clips, padding=-TRANSITION_DURATION, method="compose")
                    video = video.set_duration(audio_duration)
                    final_video = video.set_audio(audio)
    
                    # =========================================================
                    # 8 GB NVIDIA EKRAN KARTI (NVENC) VE RYZEN 5 5600 DESTEKLİ RENDER
                    # =========================================================
                    final_video.write_videofile(
                        output_name,
                        fps=24,
                        codec="h264_nvenc",     # İşlemci (libx264) YERİNE NVIDIA GPU NVENC ÇİPİ
                        audio_codec="aac",      # Standart yüksek kaliteli ses
                        preset="p1",            # En hızlı GPU donanım profili
                        threads=12              # Ryzen 5 5600'ün 12 çekirdeğini sonuna kadar çalıştırır
                    )
    
                    self.set_progress(100)
                    self.log(f"✅ [VİDEO {index}/{total_jobs} BİTTİ] Başarıyla tamamlandı!")
    
                except Exception as e:
                    self.log(f"❌ Video #{index} işlenirken HATA oluştu: {e}. Sıradaki videoya geçiliyor...")
    
                finally:
                    # ================= TEMİZLİK VE RAM TEMİZLİĞİ =================
                    self.log("🧹 Bellek (RAM) ve geçici dosyalar temizleniyor...")
                    if final_video:
                        try: final_video.close()
                        except: pass
                    if video:
                        try: video.close()
                        except: pass
                    if audio:
                        try: audio.close()
                        except: pass
    
                    for c in clips_to_close:
                        try: c.close()
                        except: pass
    
                    clips_to_close.clear()
    
                    if os.path.exists(audio_path):
                        try: os.remove(audio_path)
                        except: pass
    
                    # Garbage Collector çalıştırarak RAM'i sıfırlıyoruz
                    gc.collect()
    
            self.log("\n🎉🎉 TÜM KUYRUK TAMAMLANDI! Videoların hazır kanka!")
            messagebox.showinfo("İşlem Bitti", f"Kuyruktaki {total_jobs} video başarıyla oluşturuldu!")
            
            self.queue.clear()
            self.refresh_queue_ui()
            self.set_status("HAZIR", is_working=False)
            self.btn_start_batch.configure(state="normal", text="⚡ KUYRUĞU BAŞLAT (SABAHA KADAR RENDER ET)")
    
    if __name__ == "__main__":
        app = VideoBotApp()
        app.mainloop()
  • 02-08-2026, 21:34:50
    #2
    Teşekkürler
  • 02-08-2026, 22:20:12
    #3
    Bugun haber gördüm. Youtube yapay zeka içeriklerin sahip olduğu 132 bin kanalı tek seferde kapatmış. Dikkatli olun hesaplarınız zarar görmesin
  • 03-08-2026, 05:02:48
    #4
    Teşekkürler hocam