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

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

· 2개월 전 · 115 · 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개월 전

감사 합니다.

게시글 목록

번호 제목
1929
1928
1926
1921
1919
1911
1910
1909
1906
1904
1903
1901
1900
1899
1898
1897
1892
1891
1886
1884
1881
1876
1871
1869
1868
1867
1862
1861
1854
1851