-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
140 lines (117 loc) · 4.98 KB
/
main.py
File metadata and controls
140 lines (117 loc) · 4.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import threading
from tkinter import (
Tk, Label, Entry, Button, messagebox, Text, Scrollbar,
END, DISABLED, NORMAL, W
)
# 导入 yt-dlp 核心模块(打包时需包含)
import yt_dlp
# 日志更新函数:实时显示下载进度
def log_update(d):
if d['status'] == 'downloading':
# 格式化下载进度信息(百分比、总大小、下载速度)
progress_info = (
f"下载中:{d['_percent_str'].strip()} | "
f"总大小:{d['_total_bytes_str']} | "
f"速度:{d['_speed_str']}\n"
)
log_text.config(state=NORMAL)
log_text.insert(END, progress_info)
log_text.see(END) # 自动滚动到最新日志
log_text.config(state=DISABLED)
elif d['status'] == 'finished':
log_text.config(state=NORMAL)
log_text.insert(END, "✅ 视频文件下载完成,正在处理最终文件...\n")
log_text.see(END)
log_text.config(state=DISABLED)
# 核心下载函数:调用 yt-dlp API 实现单 MP4 输出
def start_download():
url = url_entry.get().strip()
# 1. 基础URL验证
if not url.startswith(('http://', 'https://')):
messagebox.showerror(
title="格式错误",
message="请输入有效的URL,必须以 http:// 或 https:// 开头"
)
return
# 2. 清空历史日志
log_text.config(state=NORMAL)
log_text.delete(1.0, END)
log_text.insert(END, f"🔍 开始解析URL:{url}\n")
log_text.config(state=DISABLED)
# 3. 启动子线程执行下载(避免GUI卡顿)
def download_task():
# yt-dlp 配置:强制单 MP4 文件 + 日志输出
ydl_options = {
'format': 'mp4', # 只选择 MP4 格式的音视频流
'merge_output_format': 'mp4', # 合并音视频为单个 MP4
'outtmpl': '%(title)s.%(ext)s', # 输出文件名:视频标题.mp4
'progress_hooks': [log_update], # 绑定进度日志钩子
'quiet': True, # 关闭默认命令行输出(仅通过钩子显示日志)
'no_warnings': True,
}
try:
# 执行下载
with yt_dlp.YoutubeDL(ydl_options) as ydl:
ydl.download([url])
# 下载成功提示
log_text.config(state=NORMAL)
log_text.insert(END, "\n🎉 全部完成!文件已保存至 EXE 所在文件夹")
log_text.config(state=DISABLED)
messagebox.showinfo(title="成功", message="视频下载完成,文件为 MP4 格式")
except Exception as e:
# 捕获并显示错误信息
error_info = f"\n❌ 下载失败:{str(e)}\n"
log_text.config(state=NORMAL)
log_text.insert(END, error_info)
log_text.config(state=DISABLED)
messagebox.showerror(title="错误", message=f"下载出错:{str(e)}")
# 启动下载线程(daemon=True:主程序退出时自动关闭线程)
threading.Thread(target=download_task, daemon=True).start()
# ---------------------- GUI 界面搭建 ----------------------
root = Tk()
root.title("Easy YTDLP GUI (单 MP4 版)")
root.geometry("850x600")
root.resizable(width=False, height=False) # 固定窗口大小
# 1. 标题标签
title_label = Label(
root, text="EASY YTDLP 视频下载器",
font=("微软雅黑", 14, "bold"), fg="#2c3e50"
)
title_label.grid(row=0, column=0, columnspan=2, sticky=W, padx=20, pady=20)
# 2. URL 输入框
url_label = Label(root, text="视频URL:", font=("微软雅黑", 11), fg="#34495e")
url_label.grid(row=1, column=0, sticky=W, padx=20, pady=5)
url_entry = Entry(
root, width=60, font=("微软雅黑", 11),
bd=2, relief="groove"
)
url_entry.grid(row=1, column=1, sticky=W, padx=10, pady=5)
url_entry.focus() # 启动后自动聚焦输入框
# 3. 下载按钮
download_btn = Button(
root, text="开始下载", command=start_download,
font=("微软雅黑", 11, "bold"), bg="#3498db", fg="white",
bd=0, padx=20, pady=5, activebackground="#2980b9"
)
download_btn.grid(row=1, column=2, sticky=W, padx=15, pady=5)
# 4. 日志区域(带滚动条)
log_label = Label(root, text="下载日志:", font=("微软雅黑", 11), fg="#34495e")
log_label.grid(row=2, column=0, columnspan=2, sticky=W, padx=20, pady=(15, 5))
# 日志文本框 + 滚动条容器
log_frame = Label(root, bd=1, relief="groove")
log_frame.grid(row=3, column=0, columnspan=3, padx=20, pady=5, sticky="nsew")
# 日志文本框(只读)
log_text = Text(
log_frame, font=("Consolas", 10), wrap="word",
state=DISABLED, bd=0
)
log_text.pack(side="left", fill="both", expand=True)
# 滚动条
log_scrollbar = Scrollbar(log_frame, command=log_text.yview)
log_scrollbar.pack(side="right", fill="y")
log_text.config(yscrollcommand=log_scrollbar.set)
# 调整网格权重(让日志区域自适应高度)
root.grid_rowconfigure(3, weight=1)
root.grid_columnconfigure(1, weight=1)
# 启动GUI主循环
root.mainloop()