테스트 사이트 - 개발 중인 베타 버전입니다

[유틸] 유튜브 다운로드 프로그램 만들기 공유

· 2개월 전 · 116 · 6

유튜브 다운로드 프로그램 만드는게 유행인듯 싶어서 관련자료 공유하고 갑니다.

 

ffmpeg-release-essentials.zip 파일을 다운로드 하세요..

바로링크  https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip

bin/ffmpeg.exe를 같은 폴더 복사

 

import tkinter as tk

from tkinter import ttk, filedialog, messagebox

import threading

import yt_dlp

import os

class YouTubeDownloader:

def __init__(self, root):

self.root = root

self.root.title("YouTube Downloader (카이루 v1.0)")

self.root.geometry("700x680")

self.root.resizable(False, False)

style = ttk.Style()

style.theme_use("clam") # clam, alt, default 등 선택 가능

style.configure("TLabel", font=("맑은 고딕", 11))

style.configure("TButton", font=("맑은 고딕", 11), padding=6)

style.configure("TEntry", padding=4)

# 제목

title = ttk.Label(root, text=" 카이루 유튜브 다운로드 2025 ", font=("맑은 고딕", 18, "bold"), foreground="#2c3e50")

title.pack(pady=15)

# URL 입력 프레임

url_frame = ttk.LabelFrame(root, text=" YouTube URL 입력 (최대 10개) ", padding=10)

url_frame.pack(padx=20, pady=10, fill="x")

self.url_entries = []

for i in range(10):

row_frame = ttk.Frame(url_frame)

row_frame.pack(fill="x", pady=2)

num_label = ttk.Label(row_frame, text=f"{i+1:02d}.", width=3, anchor="center")

num_label.pack(side="left")

entry = ttk.Entry(row_frame, width=80)

entry.pack(side="left", padx=5)

self.url_entries.append(entry)

# 저장 경로 선택

path_frame = ttk.Frame(root)

path_frame.pack(pady=10, fill="x")

ttk.Button(path_frame, text="? 저장 경로 선택", command=self.choose_directory).pack(side="left", padx=10)

self.save_dir = tk.StringVar(value=os.getcwd())

ttk.Label(path_frame, textvariable=self.save_dir, foreground="#2980b9").pack(side="left")

# 진행 상태 표시

progress_frame = ttk.Frame(root)

progress_frame.pack(pady=20)

self.progress_label = ttk.Label(progress_frame, text="대기 중...")

self.progress_label.pack()

self.progress_bar = ttk.Progressbar(progress_frame, length=500, mode="determinate")

self.progress_bar.pack(pady=10)

# 버튼 프레임

button_frame = ttk.Frame(root)

button_frame.pack(pady=20)

ttk.Button(button_frame, text="? MP3 다운로드", command=lambda: self.start_download("mp3")).grid(row=0, column=0, padx=15)

ttk.Button(button_frame, text="? 영상(720p)", command=lambda: self.start_download("video_720")).grid(row=0, column=1, padx=15)

ttk.Button(button_frame, text="? 영상(고화질)", command=lambda: self.start_download("video_hd")).grid(row=0, column=2, padx=15)

def choose_directory(self):

directory = filedialog.askdirectory()

if directory:

self.save_dir.set(directory)

def start_download(self, mode):

urls = [e.get().strip() for e in self.url_entries if e.get().strip()]

if not urls:

messagebox.showerror("에러", "최소 1개 이상의 URL을 입력하세요!")

return

self.progress_bar["value"] = 0

self.progress_bar["maximum"] = len(urls)

self.progress_label.config(text="다운로드 준비 중...")

threading.Thread(target=self._download_worker, args=(mode, urls, self.save_dir.get()), daemon=True).start()

def _download_worker(self, mode, urls, save_dir):

def progress_hook(d, idx, total):

if d['status'] == 'downloading':

percent = d.get('_percent_str', '0%').strip()

self.root.after(0, lambda: self.progress_label.config(

text=f"[{idx}/{total}] 다운로드 중... {percent}"))

elif d['status'] == 'finished':

self.root.after(0, lambda: self.progress_label.config(

text=f"[{idx}/{total}] 변환 중..."))

try:

total = len(urls)

for idx, url in enumerate(urls, start=1):

if mode == "mp3":

ydl_opts = {

"format": "bestaudio/best",

"outtmpl": os.path.join(save_dir, "%(title)s"),

"postprocessors": [{

"key": "FFmpegExtractAudio",

"preferredcodec": "mp3",

"preferredquality": "0",

}],

"progress_hooks": [lambda d, i=idx: progress_hook(d, i, total)],

"noplaylist": True,

}

elif mode == "video_720":

ydl_opts = {

"format": "bestvideo[height<=720]+bestaudio/best[height<=720]",

"merge_output_format": "mp4",

"outtmpl": os.path.join(save_dir, "%(title)s_[720p].mp4"),

"progress_hooks": [lambda d, i=idx: progress_hook(d, i, total)],

"noplaylist": True,

}

elif mode == "video_hd":

ydl_opts = {

"format": "bestvideo[height>=1080]+bestaudio/best",

"merge_output_format": "mp4",

"outtmpl": os.path.join(save_dir, "%(title)s_[1080p+].mp4"),

"progress_hooks": [lambda d, i=idx: progress_hook(d, i, total)],

"noplaylist": True,

}

with yt_dlp.YoutubeDL(ydl_opts) as ydl:

ydl.download([url])

self.root.after(0, lambda val=idx: self.progress_bar.config(value=val))

self.root.after(0, lambda: self.progress_label.config(text="✅ 전체 다운로드 완료"))

except Exception as e:

self.root.after(0, lambda: messagebox.showerror("다운로드 실패", str(e)))

if __name__ == "__main__":

root = tk.Tk()

app = YouTubeDownloader(root)

root.mainloop()

 

 

 

댓글 작성

댓글을 작성하시려면 로그인이 필요합니다.

로그인하기

댓글 6개

2개월 전

실행파일이 어떤건가요?

2개월 전

@데코이 실행파일은 없고 파이썬으로 직접 소스 붙어 넣기 하고 실행하면 됩니다 vscode 설치하고

파이썬 설치(https://www.python.org/ ) 하면 가능합니다.

2개월 전

감사하고 좋기는 한데...

이거... 불법은 아니겠죠?

2개월 전

@휴매니아 - 개인적인 용도로, 저작권자가 명시적으로 허용한 콘텐츠를 다운로드하는 경우
- 자신이 업로드한 영상을 백업하거나 저장하는 경우

 

개인용도면 문제가 없다고 GTP 답변이 있네요

2개월 전

@카이루 감사합니다.^^

2개월 전

감사 합니다.

게시글 목록

번호 제목
1463
1461
1460
1459
1457
1456
1454
1452
1451
1450
1448
1446
1445
1442
1440
1438
1429
1427
1423
1421
1417
1415
1414
1412
1411
1410
1408
1406
1405
1404