M3U8视频下载器 – 图形界面版

# M3U8视频下载器 - 图形界面版

今天给大家分享一个简单易用的M3U8视频下载工具,可以将在线的M3U8流媒体视频下载保存为本地MP4文件。

## 什么是M3U8?

M3U8是一种常见的流媒体播放列表格式,很多在线视频网站使用这种格式来播放视频。虽然在线观看很方便,但有时我们希望将视频保存到本地以便离线观看。

## 工具介绍

这个图形界面下载器基于强大的FFmpeg工具开发,具有以下特点:

- 简单直观的图形界面
- 一键下载M3U8视频为MP4格式
- 实时显示下载进度和日志
- 无需复杂的命令行操作

## 使用方法

### 1. 准备工作

#### 安装Python
确保你的电脑已安装Python 3.6或更高版本。

#### 安装FFmpeg
1. 访问FFmpeg官网下载页面:https://ffmpeg.org/download.html
2. 根据你的操作系统选择合适的版本下载
3. 解压后将`ffmpeg.exe`所在的文件夹路径添加到系统环境变量中

#### Python依赖
通常Python自带tkinter库,如果缺少可以使用以下命令安装:
```bash
pip install tkinter

2. 运行程序

将图形界面程序保存为m3u8_downloader_gui.py,然后双击运行或使用命令:

python m3u8_downloader_gui.py

3. 下载视频

  1. 在打开的界面中输入M3U8视频链接
  2. 点击"浏览"按钮选择保存位置和文件名
  3. 点击"开始下载"按钮即可开始下载
  4. 下载过程中可以查看实时日志信息
  5. 下载完成后会有提示

注意事项

  • 请确保你有权下载相关视频内容
  • 某些受保护的视频可能无法下载
  • 下载速度取决于网络状况和视频大小
  • 请遵守相关法律法规使用此工具

希望这个小工具能帮助你轻松下载喜欢的视频!

以下是python代码 m3u8_downloader_gui.py

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import subprocess
import os
import threading

class M3U8DownloaderGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("M3U8视频下载器")
        self.root.geometry("600x400")
        
        # 创建界面元素
        self.create_widgets()
        
    def create_widgets(self):
        # URL输入框
        tk.Label(self.root, text="M3U8 URL:").pack(pady=5)
        self.url_entry = tk.Entry(self.root, width=70)
        self.url_entry.pack(pady=5)
        self.url_entry.insert(0, "")
        
        # 输出文件路径选择
        tk.Label(self.root, text="输出文件:").pack(pady=5)
        
        file_frame = tk.Frame(self.root)
        file_frame.pack(pady=5)
        
        self.file_entry = tk.Entry(file_frame, width=60)
        self.file_entry.pack(side=tk.LEFT, padx=5)
        self.file_entry.insert(0, "E:/video/0108.mp4")
        
        browse_btn = tk.Button(file_frame, text="浏览", command=self.browse_file)
        browse_btn.pack(side=tk.LEFT, padx=5)
        
        # 下载按钮
        self.download_btn = tk.Button(self.root, text="开始下载", command=self.start_download)
        self.download_btn.pack(pady=20)
        
        # 进度条
        self.progress = ttk.Progressbar(self.root, mode='indeterminate')
        self.progress.pack(pady=10, padx=20, fill=tk.X)
        
        # 日志文本框
        tk.Label(self.root, text="日志信息:").pack(pady=5)
        self.log_text = tk.Text(self.root, height=10)
        self.log_text.pack(pady=5, padx=20, fill=tk.BOTH, expand=True)
        
        # 垂直滚动条
        scrollbar = tk.Scrollbar(self.log_text)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.log_text.yview)
        
    def browse_file(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".mp4",
            filetypes=[("MP4 files", "*.mp4"), ("All files", "*.*")]
        )
        if file_path:
            self.file_entry.delete(0, tk.END)
            self.file_entry.insert(0, file_path)
            
    def start_download(self):
        url = self.url_entry.get().strip()
        output_file = self.file_entry.get().strip()
        
        if not url:
            messagebox.showerror("错误", "请输入M3U8 URL")
            return
            
        if not output_file:
            messagebox.showerror("错误", "请选择输出文件路径")
            return
            
        # 在新线程中执行下载,避免界面冻结
        self.download_btn.config(state=tk.DISABLED)
        self.progress.start()
        
        download_thread = threading.Thread(target=self.download_m3u8, args=(url, output_file))
        download_thread.daemon = True
        download_thread.start()
        
    def download_m3u8(self, m3u8_url, output_file):
        # 确保输出目录存在
        output_dir = os.path.dirname(output_file)
        if output_dir and not os.path.exists(output_dir):
            try:
                os.makedirs(output_dir)
            except Exception as e:
                self.log_message(f"创建目录失败: {str(e)}")
                self.download_complete()
                return
        
        # 构建ffmpeg命令
        ffmpeg_cmd = [
            'ffmpeg',
            '-i', m3u8_url,
            '-c', 'copy',
            output_file,
            '-y'  # 覆盖输出文件
        ]
        
        self.log_message(f"正在下载: {m3u8_url}")
        self.log_message(f"输出文件: {output_file}")
        self.log_message("执行命令: " + " ".join(ffmpeg_cmd))
        
        try:
            # 执行ffmpeg命令
            process = subprocess.Popen(
                ffmpeg_cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                universal_newlines=True
            )
            
            # 实时读取输出
            for line in process.stdout:
                self.log_message(line.strip())
                
            process.wait()
            
            if process.returncode == 0:
                self.log_message("下载成功!")
                messagebox.showinfo("成功", "视频下载完成!")
            else:
                self.log_message("下载失败!")
                messagebox.showerror("失败", "视频下载失败,请查看日志!")
                
        except FileNotFoundError:
            self.log_message("错误: 找不到ffmpeg。请确保已安装ffmpeg并将其添加到系统PATH中。")
            messagebox.showerror("错误", "找不到ffmpeg。请确保已安装ffmpeg并将其添加到系统PATH中。")
        except Exception as e:
            self.log_message(f"发生错误: {str(e)}")
            messagebox.showerror("错误", f"发生错误: {str(e)}")
            
        self.download_complete()
        
    def log_message(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        self.root.update()
        
    def download_complete(self):
        self.progress.stop()
        self.download_btn.config(state=tk.NORMAL)

def main():
    root = tk.Tk()
    app = M3U8DownloaderGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main()
退出移动版