Bu rehberde Python kullanarak Windows üzerinde çalışan bir YouTube video indirme arayüzünün nasıl geliştirileceğini öğreneceksiniz. Projede CustomTkinter ile masaüstü arayüzü, yt-dlp ile indirme işlemleri ve PyInstaller ile EXE paketleme adımları ele alınıyor. Kaynak kodu kendi bilgisayarınızda çalıştırabilir ve ihtiyaçlarınıza göre geliştirebilirsiniz.
1. Uygulamanın özellikleri
Hazırlayacağımız uygulama, komut satırını sürekli kullanmak istemeyenler için basit bir masaüstü arayüzü sunar.
- YouTube bağlantısı girebileceğiniz URL alanı.
- İndirme klasörünü seçme imkânı.
- Video kalitesi tercihi.
- İndirme durumunu ve ilerleme çubuğunu gösterme.
- İşlem tamamlandığında kullanıcıya bilgi verme.
- Hatalı bağlantılar ve indirme hataları için uyarılar.
- Windows için EXE dosyasına dönüştürülebilen Python projesi.
2. Kullanılan teknolojiler
| Teknoloji | Görevi |
|---|---|
| Python | Uygulamanın temel programlama dili. |
| CustomTkinter | Modern görünümlü masaüstü arayüzü. |
| yt-dlp | Desteklenen bağlantılardaki medya indirme işlemleri. |
| FFmpeg | Gerekli durumlarda video ve ses akışlarını birleştirme veya dönüştürme. |
| PyInstaller | Python uygulamasını Windows çalıştırılabilir dosyasına paketleme. |
3. Python video indirici kurulumu
Adım 1: Python'ı yükleyin
Python kurulu değilse Python'ın resmî indirme sayfasını açın ve Windows sürümünü yükleyin. Kurulum ekranında Add Python to PATH seçeneğini işaretleyin.
Kurulumdan sonra Komut İstemi'ni açıp aşağıdaki komutlardan birini çalıştırın:
python --version
Bu komut çalışmazsa şu alternatifi deneyebilirsiniz:
py --version
Adım 2: Proje klasörünü oluşturun
Masaüstünde YouTubeIndirici adında bir klasör oluşturun. Klasörün içinde terminal açın veya Komut İstemi üzerinden klasöre geçin.
cd %USERPROFILE%\Desktop
mkdir YouTubeIndirici
cd YouTubeIndirici
Adım 3: Sanal ortam oluşturun
Sanal ortam, projenin Python paketlerini diğer projelerden ayrı tutar.
python -m venv .venv
.venv\Scripts\activate
Windows'ta python komutu tanınmıyorsa komutları py ile çalıştırmayı deneyin.
Adım 4: Gerekli kütüphaneleri yükleyin
python -m pip install --upgrade pip
python -m pip install customtkinter yt-dlp pyinstaller
FFmpeg'i ayrıca kurmanız gerekebilir. Kurulum ve kullanım ayrıntıları için FFmpeg resmî indirme sayfasına bakabilirsiniz.
4. YouTube video indirici Python kaynak kodu
Aşağıdaki kodu main.py adıyla kaydedin. Arayüz, indirme işlemini ayrı bir iş parçacığında yürütür; böylece işlem sürerken pencerenin yanıt vermeye devam etmesi sağlanır.
import os
import threading
import queue
from pathlib import Path
from urllib.parse import urlparse
import customtkinter as ctk
import yt_dlp
from tkinter import filedialog, messagebox
APP_TITLE = "Web Dayı | Video İndirici"
DEFAULT_FOLDER = str(Path.home() / "Downloads")
class VideoDownloader(ctk.CTk):
def __init__(self):
super().__init__()
self.title(APP_TITLE)
self.geometry("720x590")
self.minsize(620, 520)
ctk.set_appearance_mode("light")
ctk.set_default_color_theme("blue")
self.events = queue.Queue()
self.downloading = False
self.download_folder = DEFAULT_FOLDER
Path(self.download_folder).mkdir(
parents=True, exist_ok=True
)
self.create_widgets()
self.after(100, self.process_events)
def create_widgets(self):
self.grid_columnconfigure(0, weight=1)
header = ctk.CTkFrame(self, corner_radius=14)
header.grid(
row=0, column=0, padx=22, pady=(22, 12),
sticky="ew"
)
header.grid_columnconfigure(0, weight=1)
ctk.CTkLabel(
header,
text="VIDEO İNDİRİCİ",
font=ctk.CTkFont(size=25, weight="bold")
).grid(row=0, column=0, padx=20, pady=(18, 4))
ctk.CTkLabel(
header,
text="Python • CustomTkinter • yt-dlp",
text_color="#606770",
font=ctk.CTkFont(size=13)
).grid(row=1, column=0, padx=20, pady=(0, 18))
panel = ctk.CTkFrame(self, corner_radius=14)
panel.grid(
row=1, column=0, padx=22, pady=8, sticky="ew"
)
panel.grid_columnconfigure(0, weight=1)
ctk.CTkLabel(
panel, text="Video bağlantısı",
anchor="w", font=ctk.CTkFont(weight="bold")
).grid(row=0, column=0, padx=18, pady=(17, 6), sticky="ew")
self.url_entry = ctk.CTkEntry(
panel,
placeholder_text="İndirme izniniz olan video bağlantısını girin"
)
self.url_entry.grid(
row=1, column=0, padx=18, pady=(0, 14), sticky="ew"
)
ctk.CTkLabel(
panel, text="Video kalitesi",
anchor="w", font=ctk.CTkFont(weight="bold")
).grid(row=2, column=0, padx=18, pady=(2, 6), sticky="ew")
self.quality_menu = ctk.CTkOptionMenu(
panel,
values=[
"En iyi kalite",
"1080p",
"720p",
"480p",
"360p"
]
)
self.quality_menu.set("En iyi kalite")
self.quality_menu.grid(
row=3, column=0, padx=18, pady=(0, 14), sticky="ew"
)
ctk.CTkLabel(
panel, text="Kayıt klasörü",
anchor="w", font=ctk.CTkFont(weight="bold")
).grid(row=4, column=0, padx=18, pady=(2, 6), sticky="ew")
folder_row = ctk.CTkFrame(panel, fg_color="transparent")
folder_row.grid(
row=5, column=0, padx=18, pady=(0, 18), sticky="ew"
)
folder_row.grid_columnconfigure(0, weight=1)
self.folder_label = ctk.CTkLabel(
folder_row,
text=self.download_folder,
anchor="w",
wraplength=450
)
self.folder_label.grid(
row=0, column=0, padx=(0, 10), sticky="ew"
)
self.folder_button = ctk.CTkButton(
folder_row,
text="Klasör seç",
width=110,
command=self.choose_folder
)
self.folder_button.grid(row=0, column=1)
self.progress = ctk.CTkProgressBar(self)
self.progress.grid(
row=2, column=0, padx=22, pady=(17, 4), sticky="ew"
)
self.progress.set(0)
self.status_label = ctk.CTkLabel(
self, text="İndirme için hazır.",
anchor="w", wraplength=650
)
self.status_label.grid(
row=3, column=0, padx=24, pady=(4, 12), sticky="ew"
)
self.download_button = ctk.CTkButton(
self,
text="İndirmeyi başlat",
height=44,
font=ctk.CTkFont(size=15, weight="bold"),
command=self.start_download
)
self.download_button.grid(
row=4, column=0, padx=22, pady=(0, 12), sticky="ew"
)
ctk.CTkLabel(
self,
text="Yalnızca indirme izniniz bulunan içerikleri kullanın.",
text_color="#707780",
wraplength=650
).grid(row=5, column=0, padx=22, pady=(0, 18))
def choose_folder(self):
if self.downloading:
return
folder = filedialog.askdirectory(
initialdir=self.download_folder,
title="Kayıt klasörünü seçin"
)
if folder:
self.download_folder = folder
self.folder_label.configure(text=folder)
@staticmethod
def is_valid_url(url):
try:
parsed = urlparse(url.strip())
host = (parsed.hostname or "").lower()
allowed_hosts = (
"youtube.com",
"www.youtube.com",
"m.youtube.com",
"youtu.be",
"www.youtube-nocookie.com",
)
return (
parsed.scheme in ("http", "https")
and any(
host == allowed or host.endswith("." + allowed)
for allowed in allowed_hosts
)
)
except (ValueError, TypeError):
return False
def start_download(self):
if self.downloading:
return
url = self.url_entry.get().strip()
if not self.is_valid_url(url):
messagebox.showerror(
"Geçersiz bağlantı",
"Lütfen desteklenen bir YouTube bağlantısı girin."
)
return
if not os.path.isdir(self.download_folder):
messagebox.showerror(
"Klasör hatası",
"Seçilen kayıt klasörü bulunamadı."
)
return
quality = self.quality_menu.get()
self.downloading = True
self.download_button.configure(
state="disabled", text="İndiriliyor..."
)
self.folder_button.configure(state="disabled")
self.progress.set(0)
self.status_label.configure(text="İndirme hazırlanıyor...")
worker = threading.Thread(
target=self.download_worker,
args=(url, quality, self.download_folder),
daemon=True
)
worker.start()
def download_worker(self, url, quality, folder):
def progress_hook(data):
status = data.get("status")
if status == "downloading":
total = (
data.get("total_bytes")
or data.get("total_bytes_estimate")
)
downloaded = data.get("downloaded_bytes", 0)
percent = downloaded / total if total else 0
speed = data.get("_speed_str", "")
eta = data.get("_eta_str", "")
self.events.put((
"progress",
max(0, min(percent, 1)),
f"İndiriliyor: %{percent * 100:.1f} "
f"| Hız: {speed} | Kalan: {eta}"
))
elif status == "finished":
self.events.put((
"progress", 1,
"Dosya alındı. Son işlemler yapılıyor..."
))
formats = {
"En iyi kalite":
"bestvideo*+bestaudio/best",
"1080p":
"bestvideo[height<=1080]+bestaudio/best[height<=1080]",
"720p":
"bestvideo[height<=720]+bestaudio/best[height<=720]",
"480p":
"bestvideo[height<=480]+bestaudio/best[height<=480]",
"360p":
"bestvideo[height<=360]+bestaudio/best[height<=360]",
}
options = {
"format": formats.get(quality, "bestvideo*+bestaudio/best"),
"outtmpl": os.path.join(folder, "%(title).180s.%(ext)s"),
"noplaylist": True,
"progress_hooks": [progress_hook],
"retries": 3,
"quiet": True,
"no_warnings": True,
"windowsfilenames": True,
}
try:
with yt_dlp.YoutubeDL(options) as downloader:
downloader.download([url])
self.events.put(("done", True, "İndirme tamamlandı."))
except Exception as exc:
# Kullanıcı arayüzünü engellememek için
# hata bilgisi ana pencereye kuyruk üzerinden iletilir.
self.events.put((
"done", False,
f"İndirme başarısız: {str(exc)[:700]}"
))
def process_events(self):
try:
while True:
event = self.events.get_nowait()
event_type = event[0]
if event_type == "progress":
_, value, message = event
self.progress.set(value)
self.status_label.configure(text=message)
elif event_type == "done":
_, success, message = event
self.downloading = False
self.download_button.configure(
state="normal", text="İndirmeyi başlat"
)
self.folder_button.configure(state="normal")
self.status_label.configure(text=message)
if success:
self.progress.set(1)
messagebox.showinfo("Tamamlandı", message)
else:
messagebox.showerror("İndirme hatası", message)
except queue.Empty:
pass
self.after(100, self.process_events)
if __name__ == "__main__":
app = VideoDownloader()
app.mainloop()
5. Python uygulamasını çalıştırma
Kodu main.py adıyla proje klasörüne kaydettikten sonra sanal ortamın aktif olduğundan emin olun. Ardından şu komutu çalıştırın:
python main.py
Uygulama penceresi açıldığında indirme izniniz bulunan desteklenen bir YouTube bağlantısı girin. Kayıt klasörünü ve kalite tercihini seçerek işlemi başlatabilirsiniz.
6. Python uygulamasını EXE dosyasına dönüştürme
Adım 1: PyInstaller'ı yükleyin
python -m pip install pyinstaller
Adım 2: EXE dosyasını oluşturun
Proje klasöründe aşağıdaki komutu çalıştırın:
python -m PyInstaller --noconfirm --clean --windowed --name WebDayiVideoIndirici main.py
İşlem tamamlandığında uygulama genellikle dist/WebDayiVideoIndirici/ klasöründe bulunur. Oluşturulan EXE dosyasını bu klasördeki diğer dosyalarla birlikte tutun; yalnızca EXE dosyasını başka bir klasöre taşımak her zaman yeterli değildir.
FFmpeg ve EXE notu
FFmpeg gerektiren indirmelerde FFmpeg'in uygulama tarafından bulunabilir olması gerekir. En kolay yöntem, FFmpeg'i sisteme kurup PATH değişkenine eklemektir. Başka bilgisayarlarda kullanılacak bir paket hazırlıyorsanız FFmpeg'in dağıtım koşullarını ve gerekli dosyaların pakette bulunup bulunmadığını ayrıca kontrol edin.
7. Sık karşılaşılan hatalar ve çözümleri
Python komutu tanınmıyor
Python kurulumu sırasında PATH seçeneği işaretlenmemiş olabilir. Python'ı yeniden kurun veya terminalde py komutunu deneyin.
ModuleNotFoundError hatası
Gerekli paketler aktif sanal ortama kurulmamış olabilir. Sanal ortamı etkinleştirip aşağıdaki komutu çalıştırın:
python -m pip install customtkinter yt-dlp pyinstaller
FFmpeg bulunamadı
FFmpeg'i yükleyin ve terminalden ffmpeg -version komutuyla kontrol edin. Komut tanınmıyorsa PATH ayarını veya uygulamanın FFmpeg dosyalarına erişimini kontrol edin.
Video indirilemiyor
- Bağlantının doğru ve erişilebilir olduğunu kontrol edin.
- yt-dlp paketini güncelleyin:
python -m pip install --upgrade yt-dlp
- Seçilen kalite için uygun formatın bulunup bulunmadığını kontrol edin.
- İçeriğin indirilmesine izin verildiğinden ve ek erişim şartları bulunmadığından emin olun.
- Hata sürerse terminalden çalıştırarak hata mesajını inceleyin.
EXE açılmıyor veya hemen kapanıyor
Uygulamayı terminalden çalıştırarak gerçek hata mesajını görün. Sorunun eksik paket, FFmpeg yolu veya paketleme ayarı kaynaklı olup olmadığını bu şekilde ayırabilirsiniz. Geliştirme sırasında --windowed parametresini kaldırmak hata mesajlarını görmeyi kolaylaştırabilir.
8. Uygulama nasıl geliştirilebilir?
Temel uygulama çalıştıktan sonra aşağıdaki özellikleri ekleyebilirsiniz:
- İndirme geçmişi ve tamamlanan dosyaların listesi.
- Dosya adı ve kayıt konumu için daha ayrıntılı seçenekler.
- İndirme iptali ve işlem durumunu daha ayrıntılı gösteren bir arayüz.
- Farklı işletim sistemleri için ayrı paketleme ve test süreçleri.
- Otomatik güncelleme veya paket sürümünü gösteren bir bilgi alanı.
Linux ve macOS üzerinde de Python arayüzü geliştirilebilir; ancak EXE dosyası Windows'a özgüdür. Diğer işletim sistemleri için paketlemeyi o sistemlerde ayrıca test etmeniz gerekir.
9. Kullanım koşulları ve telif hakları
Bir içeriğin internet üzerinden görüntülenebiliyor olması, o içeriği istediğiniz şekilde indirip yeniden yayımlama hakkınız olduğu anlamına gelmez. İndirdiğiniz videoların kullanım şartlarını, telif haklarını ve platform kurallarını dikkate alın. Bu projeyi yalnızca yasal olarak erişme ve indirme hakkınız olan içeriklerle kullanın.
Sonuç
Bu rehberde Python, CustomTkinter ve yt-dlp kullanarak masaüstü video indirme arayüzü oluşturmayı; gerekli paketleri kurmayı, uygulamayı çalıştırmayı ve PyInstaller ile Windows için paketlemeyi ele aldık.
Kod, geliştirilebilir bir başlangıç projesidir. Gerçek kullanım öncesinde farklı bağlantılarla test edin, hata mesajlarını kontrol edin ve paketlediğiniz uygulamayı hedef bilgisayarda doğrulayın.
Sık sorulan sorular
Bu uygulama ücretsiz mi?
Evet bu paylaşılan kodlar ücretsizdir. İstediğiniz gibi kullanabilirsiniz.
EXE oluşturmak için Python gerekli mi?
EXE dosyasını oluşturacağınız bilgisayarda Python ve geliştirme paketleri gerekir. Son kullanıcı bilgisayarında gereksinimler paketleme biçimine bağlıdır; uygulamayı hedef bilgisayarda test etmelisiniz.
FFmpeg olmadan çalışır mı?
Basit indirmeler bazı durumlarda FFmpeg olmadan çalışabilir. Ayrı ses ve görüntü akışlarının birleştirilmesi gerektiğinde FFmpeg gerekebilir.
Her YouTube videosu indirilebilir mi?
Hayır. Erişim, format, platform değişiklikleri ve içerik kullanım koşulları indirmeyi etkileyebilir. Yalnızca indirme izniniz olan içerikleri kullanın.
Web Dayı — Python, yazılım ve teknoloji rehberleri.