Python Youtube Video İndirici

başaramadıkabi

Kayıtlı Üye
Katılım
15 Temmuz 2020
Mesajlar
563
Tepkime puanı
0
Puan
0
Deepseek ile oluşturduğum video indirici. Satır satır link veriliyor verilen linkleri mp4 ya da mp3 olarak indiriyor. İhtiyacı olan kullansın diye kodu paylaşıyorum.



Kod:
import os
import time
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from threading import Thread
import yt_dlp
from datetime import datetime

class YouTubeDownloader:
    def __init__(self, master):
        self.master = master
        master.title("YouTube İndirici")
        master.geometry("720x500")
        
        self.setup_ui()
        self.setup_ydl_options()
        
    def setup_ui(self):
        # Temel Stil
        self.style = ttk.Style()
        self.style.theme_use('clam')
        self.style.configure("TButton", padding=6, font=('Arial', 10))
        self.style.configure("TLabel", font=('Arial', 10))
        
        # URL Giriş
        url_frame = ttk.Frame(self.master)
        url_frame.pack(pady=10, padx=20, fill=tk.X)
        
        ttk.Label(url_frame, text="YouTube URL'leri (Her satıra bir URL):").pack(anchor=tk.W)
        self.url_text = tk.Text(url_frame, height=8, width=80)
        self.url_text.pack(pady=5)

        # Ayarlar
        settings_frame = ttk.Frame(self.master)
        settings_frame.pack(pady=10, padx=20, fill=tk.X)
        
        # Klasör Seçimi
        ttk.Label(settings_frame, text="Kaydetme Klasörü:").grid(row=0, column=0, sticky=tk.W)
        self.folder_path = tk.StringVar(value=os.path.expanduser("~/Downloads"))
        ttk.Entry(settings_frame, textvariable=self.folder_path, width=50).grid(row=0, column=1, padx=5)
        ttk.Button(settings_frame, text="Gözat", command=self.select_folder).grid(row=0, column=2)

        # Format Seçimi
        ttk.Label(settings_frame, text="İndirme Formatı:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.format_var = tk.StringVar(value="video")
        ttk.Radiobutton(settings_frame, text="Video (MP4)", variable=self.format_var, value="video").grid(row=1, column=1, sticky=tk.W)
        ttk.Radiobutton(settings_frame, text="Sadece Ses (MP3)", variable=self.format_var, value="audio").grid(row=1, column=2, sticky=tk.W)

        # İlerleme Çubuğu
        self.progress = ttk.Progressbar(self.master, orient='horizontal', mode='determinate')
        self.progress.pack(pady=10, padx=20, fill=tk.X)

        # Durum Bilgisi
        self.status_var = tk.StringVar()
        ttk.Label(self.master, textvariable=self.status_var).pack(pady=5)

        # Kontrol Butonları
        btn_frame = ttk.Frame(self.master)
        btn_frame.pack(pady=10)
        ttk.Button(btn_frame, text="İndirmeyi Başlat", command=self.start_download).grid(row=0, column=0, padx=5)
        ttk.Button(btn_frame, text="Temizle", command=self.clear_inputs).grid(row=0, column=1, padx=5)

    def setup_ydl_options(self):
        self.ydl_opts = {
            'outtmpl': os.path.join(self.folder_path.get(), '%(title)s.%(ext)s'),
            'progress_hooks': [self.update_progress],
            'restrictfilenames': True,
            'noplaylist': True,
            'postprocessor_args': ['-map_metadata', '-1']  # Metadata'yı temizle
        }

    def select_folder(self):
        folder = filedialog.askdirectory()
        if folder:
            self.folder_path.set(folder)
            self.setup_ydl_options()

    def update_progress(self, d):
        if d['status'] == 'downloading':
            total = d.get('total_bytes') or d.get('total_bytes_estimate')
            if total:
                percent = (d['downloaded_bytes'] / total) * 100
                self.progress['value'] = percent
                self.status_var.set(f"İndiriliyor: {os.path.basename(d['filename'])} - {percent:.1f}%")
                self.master.update_idletasks()

    def download_media(self, url):
        try:
            if self.format_var.get() == 'video':
                format_selector = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio/best'
                postprocessors = [{
                    'key': 'FFmpegVideoConvertor',
                    'preferedformat': 'mp4'
                }]
            else:
                format_selector = 'bestaudio/best'
                postprocessors = [{
                    'key': 'FFmpegExtractAudio',
                    'preferredcodec': 'mp3',
                    'preferredquality': '192',
                }]

            opts = {
                **self.ydl_opts,
                'format': format_selector,
                'postprocessors': postprocessors,
                'merge_output_format': 'mp4'
            }

            with yt_dlp.YoutubeDL(opts) as ydl:
                info = ydl.extract_info(url, download=True)
                filename = ydl.prepare_filename(info)

            self.update_file_times(filename)
            return True
        
        except Exception as e:
            messagebox.showerror("Hata", f"{url}\n{str(e)}")
            return False

    def update_file_times(self, filename):
        """Dosya zaman damgalarını güncelleyen fonksiyon"""
        try:
            now = time.time()
            # Değiştirme ve erişim zamanını güncelle
            os.utime(filename, (now, now))
            
            # Windows'ta oluşturma zamanını güncelle
            if os.name == 'nt':
                from pywin32 import win32file, win32con
                handle = win32file.CreateFile(
                    filename,
                    win32con.GENERIC_WRITE,
                    0, None,
                    win32con.OPEN_EXISTING,
                    0, None
                )
                win32file.SetFileTime(handle, datetime.fromtimestamp(now), None, None)
                handle.close()
                
        except Exception as e:
            print(f"Zaman güncelleme hatası: {str(e)}")

    def start_download(self):
        urls = [url.strip() for url in self.url_text.get("1.0", tk.END).split('\n') if url.strip()]
        
        if not urls:
            messagebox.showwarning("Uyarı", "Lütfen en az bir YouTube URL'si girin!")
            return
            
        if not os.path.exists(self.folder_path.get()):
            os.makedirs(self.folder_path.get())

        self.progress['value'] = 0
        self.status_var.set("İndirme başlatılıyor...")

        Thread(target=self.process_downloads, args=(urls,), daemon=True).start()

    def process_downloads(self, urls):
        success = 0
        for index, url in enumerate(urls):
            self.status_var.set(f"İşleniyor ({index+1}/{len(urls)})...")
            if self.download_media(url):
                success += 1
        messagebox.showinfo("Tamamlandı", f"İndirme tamamlandı!\nBaşarılı: {success}\nBaşarısız: {len(urls)-success}")
        self.progress['value'] = 100
        self.status_var.set("Hazır")

    def clear_inputs(self):
        self.url_text.delete("1.0", tk.END)
        self.progress['value'] = 0
        self.status_var.set("")

if __name__ == "__main__":
    root = tk.Tk()
    app = YouTubeDownloader(root)
    root.mainloop()
 
Son düzenleme:
Deepseek ile oluşturduğum video indirici. Satır satır link veriliyor verilen linkleri mp4 ya da mp3 olarak indiriyor. İhtiyacı olan kullansın diye kodu paylaşıyorum.



Kod:
import os
import time
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from threading import Thread
import yt_dlp
from datetime import datetime

class YouTubeDownloader:
    def __init__(self, master):
        self.master = master
        master.title("YouTube İndirici")
        master.geometry("720x500")
        
        self.setup_ui()
        self.setup_ydl_options()
        
    def setup_ui(self):
        # Temel Stil
        self.style = ttk.Style()
        self.style.theme_use('clam')
        self.style.configure("TButton", padding=6, font=('Arial', 10))
        self.style.configure("TLabel", font=('Arial', 10))
        
        # URL Giriş
        url_frame = ttk.Frame(self.master)
        url_frame.pack(pady=10, padx=20, fill=tk.X)
        
        ttk.Label(url_frame, text="YouTube URL'leri (Her satıra bir URL):").pack(anchor=tk.W)
        self.url_text = tk.Text(url_frame, height=8, width=80)
        self.url_text.pack(pady=5)

        # Ayarlar
        settings_frame = ttk.Frame(self.master)
        settings_frame.pack(pady=10, padx=20, fill=tk.X)
        
        # Klasör Seçimi
        ttk.Label(settings_frame, text="Kaydetme Klasörü:").grid(row=0, column=0, sticky=tk.W)
        self.folder_path = tk.StringVar(value=os.path.expanduser("~/Downloads"))
        ttk.Entry(settings_frame, textvariable=self.folder_path, width=50).grid(row=0, column=1, padx=5)
        ttk.Button(settings_frame, text="Gözat", command=self.select_folder).grid(row=0, column=2)

        # Format Seçimi
        ttk.Label(settings_frame, text="İndirme Formatı:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.format_var = tk.StringVar(value="video")
        ttk.Radiobutton(settings_frame, text="Video (MP4)", variable=self.format_var, value="video").grid(row=1, column=1, sticky=tk.W)
        ttk.Radiobutton(settings_frame, text="Sadece Ses (MP3)", variable=self.format_var, value="audio").grid(row=1, column=2, sticky=tk.W)

        # İlerleme Çubuğu
        self.progress = ttk.Progressbar(self.master, orient='horizontal', mode='determinate')
        self.progress.pack(pady=10, padx=20, fill=tk.X)

        # Durum Bilgisi
        self.status_var = tk.StringVar()
        ttk.Label(self.master, textvariable=self.status_var).pack(pady=5)

        # Kontrol Butonları
        btn_frame = ttk.Frame(self.master)
        btn_frame.pack(pady=10)
        ttk.Button(btn_frame, text="İndirmeyi Başlat", command=self.start_download).grid(row=0, column=0, padx=5)
        ttk.Button(btn_frame, text="Temizle", command=self.clear_inputs).grid(row=0, column=1, padx=5)

    def setup_ydl_options(self):
        self.ydl_opts = {
            'outtmpl': os.path.join(self.folder_path.get(), '%(title)s.%(ext)s'),
            'progress_hooks': [self.update_progress],
            'restrictfilenames': True,
            'noplaylist': True,
            'postprocessor_args': ['-map_metadata', '-1']  # Metadata'yı temizle
        }

    def select_folder(self):
        folder = filedialog.askdirectory()
        if folder:
            self.folder_path.set(folder)
            self.setup_ydl_options()

    def update_progress(self, d):
        if d['status'] == 'downloading':
            total = d.get('total_bytes') or d.get('total_bytes_estimate')
            if total:
                percent = (d['downloaded_bytes'] / total) * 100
                self.progress['value'] = percent
                self.status_var.set(f"İndiriliyor: {os.path.basename(d['filename'])} - {percent:.1f}%")
                self.master.update_idletasks()

    def download_media(self, url):
        try:
            if self.format_var.get() == 'video':
                format_selector = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio/best'
                postprocessors = [{
                    'key': 'FFmpegVideoConvertor',
                    'preferedformat': 'mp4'
                }]
            else:
                format_selector = 'bestaudio/best'
                postprocessors = [{
                    'key': 'FFmpegExtractAudio',
                    'preferredcodec': 'mp3',
                    'preferredquality': '192',
                }]

            opts = {
                **self.ydl_opts,
                'format': format_selector,
                'postprocessors': postprocessors,
                'merge_output_format': 'mp4'
            }

            with yt_dlp.YoutubeDL(opts) as ydl:
                info = ydl.extract_info(url, download=True)
                filename = ydl.prepare_filename(info)

            self.update_file_times(filename)
            return True
        
        except Exception as e:
            messagebox.showerror("Hata", f"{url}\n{str(e)}")
            return False

    def update_file_times(self, filename):
        """Dosya zaman damgalarını güncelleyen fonksiyon"""
        try:
            now = time.time()
            # Değiştirme ve erişim zamanını güncelle
            os.utime(filename, (now, now))
            
            # Windows'ta oluşturma zamanını güncelle
            if os.name == 'nt':
                from pywin32 import win32file, win32con
                handle = win32file.CreateFile(
                    filename,
                    win32con.GENERIC_WRITE,
                    0, None,
                    win32con.OPEN_EXISTING,
                    0, None
                )
                win32file.SetFileTime(handle, datetime.fromtimestamp(now), None, None)
                handle.close()
                
        except Exception as e:
            print(f"Zaman güncelleme hatası: {str(e)}")

    def start_download(self):
        urls = [url.strip() for url in self.url_text.get("1.0", tk.END).split('\n') if url.strip()]
        
        if not urls:
            messagebox.showwarning("Uyarı", "Lütfen en az bir YouTube URL'si girin!")
            return
            
        if not os.path.exists(self.folder_path.get()):
            os.makedirs(self.folder_path.get())

        self.progress['value'] = 0
        self.status_var.set("İndirme başlatılıyor...")

        Thread(target=self.process_downloads, args=(urls,), daemon=True).start()

    def process_downloads(self, urls):
        success = 0
        for index, url in enumerate(urls):
            self.status_var.set(f"İşleniyor ({index+1}/{len(urls)})...")
            if self.download_media(url):
                success += 1
        messagebox.showinfo("Tamamlandı", f"İndirme tamamlandı!\nBaşarılı: {success}\nBaşarısız: {len(urls)-success}")
        self.progress['value'] = 100
        self.status_var.set("Hazır")

    def clear_inputs(self):
        self.url_text.delete("1.0", tk.END)
        self.progress['value'] = 0
        self.status_var.set("")

if __name__ == "__main__":
    root = tk.Tk()
    app = YouTubeDownloader(root)
    root.mainloop()

exe olarak daha cok ıse yarayacaktır. bılmeyenler ıcın
 
Kişiselleştirme

Tema editörü

Ayarlar Renkler

  • Mobil kullanıcılar bu fonksiyonları kullanamaz.

    Alternatif header

    Farklı bir görünüm için alternatif header yapısını kolayca seçebilirsiniz.

    Görünüm Modu Seçimi

    Tam ekran ve dar ekran modları arasında geçiş yapın.

    Izgara Görünümü

    Izgara modu ile içerikleri kolayca inceleyin ve düzenli bir görünüm elde edin.

    Resimli Izgara Modu

    Arka plan görselleriyle içeriğinizi düzenli ve görsel olarak zengin bir şekilde görüntüleyin.

    Yan Paneli Kapat

    Yan paneli gizleyerek daha geniş bir çalışma alanı oluşturun.

    Sabit Yan Panel

    Yan paneli sabitleyerek sürekli erişim sağlayın ve içeriğinizi kolayca yönetin.

    Box görünüm

    Temanızın yanlarına box tarzı bir çerçeve ekleyebilir veya mevcut çerçeveyi kaldırabilirsiniz. 1300px üstü çözünürler için geçerlidir.

    Köşe Yuvarlama Kontrolü

    Köşe yuvarlama efektini açıp kapatarak görünümü dilediğiniz gibi özelleştirin.

  • Renginizi seçin

    Tarzınızı yansıtan rengi belirleyin ve estetik uyumu sağlayın.

Geri