【初中up主分享】自己动手,丰衣足食!看我打造的下载利器!

代码如下:

import os.path
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.filedialog as tf
import pytube
from urllib.error import URLError
import tkinter.messagebox as tm
import requests
import io
from PIL import ImageTk, Image
import threading
import subprocess
from pytube.exceptions import *class ScrollableFrame(tk.Frame):def __init__(self, container: tk.Misc | None, *args, **kwargs):super().__init__(container, *args, **kwargs)self.width = kwargs['width']self.height = kwargs['height']canvas = tk.Canvas(self, width=self.width, height=self.height)scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)self.scrollable_frame = tk.Frame(canvas, width=self.width, height=self.height)self.scrollable_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")canvas.configure(yscrollcommand=scrollbar.set)canvas.pack(side="left", fill="both", expand=True)scrollbar.pack(side="right", fill="y")def _on_mousewheel(event):  # 鼠标滚轮canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")canvas.bind_all("<MouseWheel>", _on_mousewheel)  # 绑定鼠标滚class TubeVideo:def __init__(self, url, progressbar: ttk.Progressbar, label: tk.Label, root: tk.Tk, frame: tk.Frame):self.progressbar = progressbarself.label = labelself.root = rootself.frame = frameself.yt = pytube.YouTube(url,on_progress_callback=lambda stream, chunk, bytes_remaining: self.on_progress(bytes_remaining),on_complete_callback=lambda stream, file_path: self.on_complete(file_path),use_oauth=True, allow_oauth_cache=True)self.success = Truetry:self.title = self.yt.titleexcept (URLError, Exception) as e:print(type(e), e)self.success = Falseself.percentage = 0.0if self.success:self.total_size = self.yt.streams.get_highest_resolution().filesizeself.length = self.yt.lengthelse:passdef get_title(self):return self.titledef get_succeed(self):return self.successdef get_size(self, res):self.total_size = self.yt.streams.get_by_resolution(res).filesizedef download_video(self, path, is_highest, res=None):self.label.config(foreground='gold')if is_highest:stream = self.yt.streams.get_highest_resolution()else:stream = self.yt.streams.get_by_resolution(res)os.path.join(path, f"{self.title}.mp4")stream.download(output_path=path)def calc_percentage(self, bytes_remaining):bytes_downloaded = self.total_size - bytes_remainingself.percentage = bytes_downloaded / self.total_size * 100def get_thumbnail_url(self):url = '/'.join(self.yt.thumbnail_url.split('/')[:-1]) + "/hqdefault.jpg"return urldef on_progress(self, bytes_remaining):self.calc_percentage(bytes_remaining)self.progressbar['value'] = int(self.percentage)self.label['text'] = (f"{(self.total_size - bytes_remaining) / 1024 / 1024:.2f}MB/"f"{self.total_size / 1024 / 1024:.2f}MB {self.percentage:.2f}%")self.root.update()def on_complete(self, file_path):try:os.startfile(file_path)except AttributeError:try:subprocess.run(['open', file_path])except (OSError, Exception):tm.showerror("")self.label.config(foreground="green")self.label['text'] = "下载完成!单击关闭。"self.frame['cursor'] = 'hand2'self.frame.bind("<Button-1>", lambda e: (self.frame.destroy(), self.root.update()))self.root.update()class EachVideoFrame:def __init__(self, _root, url, path, rel=None):self.rel = relself.path = pathself.url = urlself.root = _rootself.frame = tk.Frame(_root)  # 690*120self.info_frame = tk.Frame(self.frame)self.progress_frame = tk.Frame(self.frame)self.image = tk.Label(self.frame)self.title = tk.Label(self.info_frame, font=("黑体", 20), wraplength=200)self.info = tk.Label(self.info_frame, font=("黑体", 10), fg='grey')self.text = tk.Label(self.progress_frame, justify='left')self.progressbar = ttk.Progressbar(self.progress_frame, orient="horizontal", length=300, mode="determinate")self.yt: TubeVideo | None = Noneself.loading = tk.Label(self.frame, text="正在加载视频信息...", font=("黑体", 30))self.loading.pack()self.root.update()self.succeed = Truethreading.Thread(target=self.network_part).start()def network_part(self):try:self.yt = TubeVideo(self.url, self.progressbar, self.text, self.root, self.frame)except RegexMatchError:tm.showerror("错误!", "下载失败,请输入正确的URL地址!")self.frame.destroy()returnexcept AgeRestrictedError:tm.showerror("错误!", "该视频无法下载,因为它是年龄限制的。")self.frame.destroy()returnexcept (ConnectionError, Exception):tm.showerror("错误!", "下载失败,请检查网络连接或视频链接是否正确。")self.frame.destroy()returnif not self.yt.get_succeed():tm.showerror("错误!", "无法下载该视频,请检查网络连接或视频链接是否正确。")self.succeed = Falsereturnresponse = requests.get(self.yt.get_thumbnail_url(), stream=True)image_bytes = io.BytesIO(response.content)img_obj = Image.open(image_bytes)w, h = img_obj.sizeimg_obj = img_obj.resize((int(w * 0.3), int(h * 0.3)))img = ImageTk.PhotoImage(img_obj)self.image['image'] = imgself.image.image = imgtitle = self.yt.get_title()if len(title) >= 40:title = title[:37] + '...'self.title['text'] = titleself.info["text"] = f'{self.yt.total_size / 1024 / 1024:.2f}MB  {self.yt.length // 60}:{str(self.yt.length % 60)[:1]}S'self.text['text'] = f"00.00MB/{self.yt.total_size / 1024 / 1024:.2f}MB 00.00%"self.loading.destroy()del self.loadingself.image.grid(row=0, column=0, padx=5, pady=5)self.title.pack(padx=5, pady=5)self.info.pack(padx=5, pady=5)self.info_frame.grid(row=0, column=1, padx=5, pady=5)self.text.pack(side=tk.TOP, padx=5, pady=5)self.progressbar.pack(side=tk.TOP, fill=tk.X, expand=True, padx=5, pady=5)self.progress_frame.grid(row=0, column=2, sticky="w", padx=5, pady=5)if self.rel is not None:self.yt.download_video(path=self.path, is_highest=False, res=self.rel)else:self.yt.download_video(path=self.path, is_highest=True)def pack(self, *args, **kwargs):self.frame.pack(*args, **kwargs)def grid(self, *args, **kwargs):self.frame.grid(*args, **kwargs)def place(self, *args, **kwargs):self.frame.place(*args, **kwargs)class NewVideo:def __init__(self, root):self.var = tk.StringVar()self.var.set("Best")self.filenameVar = tk.StringVar()self._root = rootself.root = tk.Toplevel(self._root)self.root.title("YouTube 视频下载器--新建下载任务")self.label = tk.Label(self.root, text="输入视频链接:")self.label.grid(row=0, column=0, padx=5, pady=5)self.entry = ttk.Entry(self.root)self.entry.grid(row=0, column=1, columnspan=3, padx=5, pady=5, sticky=tk.W + tk.E)self.label2 = tk.Label(self.root, text="下载清晰度:")self.label2.grid(row=1, column=0, padx=5, pady=5)self.radios = ttk.Radiobutton(self.root, text="最高画质", value='Best', variable=self.var)self.radios2 = ttk.Radiobutton(self.root, text="标清", value='480p', variable=self.var)self.radios3 = ttk.Radiobutton(self.root, text="流畅", value='360p', variable=self.var)self.radios.grid(row=1, column=1, padx=5, pady=5)self.radios2.grid(row=1, column=2, padx=5, pady=5)self.radios3.grid(row=1, column=3, padx=5, pady=5)self.label3 = tk.Label(self.root, text="保存到:")self.label3.grid(row=2, column=0, padx=5, pady=5)self.entry2 = ttk.Entry(self.root, textvariable=self.filenameVar)self.entry2.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky=tk.W + tk.E)self.btn = ttk.Button(self.root, text="浏览", command=self.blowse)self.btn.grid(row=2, column=3, padx=5, pady=5)self.btn2 = ttk.Button(self.root, text="下载", command=self.download)self.btn2.grid(row=3, column=0, columnspan=4, padx=5, pady=5, sticky=tk.W + tk.E)def blowse(self):filename = tf.askdirectory()self.filenameVar.set(filename)def download(self):url = self.entry.get()path = self.filenameVar.get()if path == '':tm.showerror("错误,请输入有效的地址")returnquality = self.var.get()frame = EachVideoFrame(self._root, url, path, None if quality == "Best" else quality)frame.pack()self.root.destroy()class Application:def __init__(self):self.root = tk.Tk()self.root.title("YouTube 视频下载器")self.add_frame = tk.Frame(self.root)self.btn1 = ttk.Button(self.add_frame, text="下载一个新视频", command=self.add_video)self.btn1.pack(padx=5, pady=5)self.add_frame.pack(side=tk.TOP, fill=tk.X)self.frame = ScrollableFrame(self.root, width=690, height=180)self.frame.pack(side=tk.TOP, expand=True, fill=tk.BOTH)self.root.resizable(False, False)try:self.root.iconphoto(True, tk.PhotoImage(file="icon.png"))except (tk.TclError, FileNotFoundError, Exception):passdef add_video(self):NewVideo(self.frame.scrollable_frame)def run(self):self.root.mainloop()if __name__ == "__main__":app = Application()app.run()

点个赞再走吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/732726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试自学和报班学习的区别,各有各的优势和缺点,大家看完之后自己选择喔

时代在进步&#xff0c;人们汲取知识的方式不再是单一的在书本上面&#xff0c;现在网络发达&#xff0c;只需要上网就能找到相关的好多知识&#xff0c;慢慢的大家越来越觉得有了这些知识&#xff0c;只要自己有自制力就完全能够自学到一定的程度。 在自学氛围的影响下&#…

【Python】科研代码学习:五 Data Collator,Datasets

【Python】科研代码学习&#xff1a;五 Data Collator&#xff0c;Datasets Data CollatorDefault data collatorDefaultDataCollatorDataCollatorWithPaddingPadding 其他 Data Collator Datasetsload_dataset其他一些基本操作 Data Collator HF官网API&#xff1a;Data Coll…

抖音短视频素材哪里找,推荐五个好用的抖音素材网站

不知道你有没有想过一个问题&#xff0c;为什么别人都能找到那种高质量的视频素材&#xff0c;画质特别高清&#xff0c;甚至是4K的内容&#xff0c;而你需要视频素材却不知道去哪里找&#xff1f;网上有各种参差不齐的网站&#xff0c;变着法的想掏空你那本不富裕的腰包。今天…

Git 开源的版本控制系统-06-share to github 如何把项目代码共享到 github

拓展阅读 Subversion 开源的版本控制系统入门介绍 VCS Git 开源的版本控制系统-01-入门使用介绍 Git 开源的版本控制系统-02-base usage 基本用法 Git 开源的版本控制系统-03-时间数据回溯 Git 开源的版本控制系统-04-branch manage 分支管理 Git 开源的版本控制系统-05-…

springMVC自定义异常处理器

目录 &#x1f331;使用原因 &#x1f333;优点 &#x1f331;实现 &#x1f333;自定义一个异常 &#x1f333;异常处理 &#x1f333;测试 使用原因 系统中会有各种各样的&#xff0c;意料之中和意料之外的结果&#xff0c;我们并不能做到完全针对每个异常时刻做出针对…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Marquee)

跑马灯组件&#xff0c;用于滚动展示一段单行文本。仅当文本内容宽度超过跑马灯组件宽度时滚动&#xff0c;不超过时不滚动。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 Ma…

数据结构从入门到精通——队列

队列 前言一、队列1.1队列的概念及结构1.2队列的实现1.3队列的实现1.4扩展 二、队列面试题三、队列的具体实现代码Queue.hQueue.ctest.c队列的初始化队列的销毁入队列出队列返回队头元素返回队尾元素检测队列是否为空检测元素个数 前言 队列是一种特殊的线性数据结构&#xff…

【操作系统学习笔记】文件管理2.3

【操作系统学习笔记】文件管理2.3 参考书籍: 王道考研 视频地址: Bilibili 虚拟文件系统 由于不同的硬件需要不用的文件系统&#xff0c;会导致写代码非常复杂 虚拟文件系统 VFS: 向上层用户进程提供统一标准的系统调用接口&#xff0c;屏蔽底层具体文件系统的实现差异VFS…

Python 初步了解urllib库:网络请求的利器

目录 urllib库简介 request模块 parse模块 error模块 response模块 读取响应内容 获取响应状态码 获取响应头部信息 处理重定向 关闭响应 总结 在Python的众多库中&#xff0c;urllib库是一个专门用于处理网络请求的强大工具。urllib库提供了多种方法来打开和读取UR…

STM32 HAL库RTC复位丢失年月日的解决办法

STM32 HAL库RTC复位丢失年月日的解决办法 0.前言一、实现方式1.CubeMX配置&#xff1a;2.MX_RTC_Init()函数修改2.编写手动解析函数 二、总结 参考文章&#xff1a;stm32f1 cubeMX RTC 掉电后日期丢失的问题 0.前言 最近在使用STM32F103做RTC实验时&#xff0c;发现RTC复位后时…

基于Java的物管系统设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术介绍 3 1.1 JSP介绍 3 1.2 MySQL介绍 3 1.3 B/S开发模式 3 1.4 Java介绍 4 2 系统分析 5 2.1 可行性研究 5 2.1.1技术可行性 5 2.2.2经济可行性 5 2.3.1操作可行性 5 2.2 需求分析 6 2.2.1系统用例图 6 2.2.2系统功能模块需求分析…

机器学习--循环神经网络(RNN)1

一、简介 循环神经网络&#xff08;Recurrent Neural Network&#xff09;是深度学习领域中一种非常经典的网络结构&#xff0c;在现实生活中有着广泛的应用。以槽填充&#xff08;slot filling&#xff09;为例&#xff0c;如下图所示&#xff0c;假设订票系统听到用户说&…

关于vue3使用prop传动态参数时父子数据不同步更新问题

子: <template><div><h3>子组件</h3><input :value"modelValue" input"$emit(update:modelValue, $event.target.value)"></div> </template><script setup> import { defineProps, defineEmits } from …

P5635 【CSGRound1】天下第一

题目背景 天下第一的 cbw 以主席的身份在 8102 年统治全宇宙后&#xff0c;开始了自己休闲的生活&#xff0c;并邀请自己的好友每天都来和他做游戏。由于 cbw 想要显出自己平易近人&#xff0c;所以 zhouwc 虽然是一个蒟蒻&#xff0c;也有能和 cbw 玩游戏的机会。 题目描述 …

揭秘接口测试:完整流程指南!

在讲接口测试之前&#xff0c;首先需要给大家申明下&#xff1a;接口测试对于测试人员而言&#xff0c;非常非常重要&#xff0c;懂功能测试接口测试&#xff0c;就能在企业中拿到一份非常不错的薪资。 这么重要的接口测试&#xff0c;一般也是面试笔试必问。为方便大家更好的…

logstash和elasticsearch的几种交互接口

Logstash与Elasticsearch是两个非常流行的开源工具&#xff0c;用于处理和存储大量的日志数据。它们之间的集成非常重要&#xff0c;因为Logstash用于收集、处理和转换日志数据&#xff0c;而Elasticsearch用于存储、搜索和分析这些数据。在本文中&#xff0c;我们将详细介绍Lo…

【C/C++】常量指针与指针常量的深入解析与区分(什么是const int * 与 int * const ?)

目录 一、前言 二、const 的简单介绍 三、常量指针 &#x1f50d;介绍与分析 &#x1f4f0;小结与记忆口诀 四、指针常量 &#x1f50d;介绍与分析 &#x1f4f0;小结与记忆口诀 五、总结与提炼 六、共勉 一、前言 在【C/C】的编程中&#xff0c;指针与const关键字的组合…

防御保护IPSEC实验

要求&#xff1a;在FW5和FW3之间建立一条IPSEC通道&#xff0c;保证10.0.2.0/24网段可以正常访问到192.168.1.0/24. 因为是双机热备状态则只需要配置FW1主设备。 新建ACL待加密数据流 安全建议&#xff1a; IPSec参数配置 FW3配置如下与FW1类似&#xff1a; FW1中新建安全策略…

链表|19.删除链表的倒数第N个节点

力扣题目链接 struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {//定义虚拟头节点dummy 并初始化使其指向headstruct ListNode* dummy malloc(sizeof(struct ListNode));dummy->val 0;dummy->next head;//定义 fast slow 双指针struct ListNode* f…

论文汇总:Rectifying the Shortcut Learning of Background for Few-Shot Learning

原文解读&#xff1a; 论文解读&#xff1a;Rectifying the Shortcut Learning of Background for Few-Shot Learning-CSDN博客 文章汇总 问题&动机&解决方法 图像背景是一种有害知识的来源&#xff0c;这是少数镜头学习模型容易吸收的(问题) 通过在训练和评估中提…