视频万能转换器(源码)

import os
import sys
import tkinter as tk
from tkinter import filedialog, ttk
import subprocess
import threading
import datetime


class VideoConverterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("万能高清转换器-三松礼品-强哥出品必属精品")

        # 转换参数预设
        self.presets = {
            '高清1080p': '-c:v libx264 -crf 23 -preset medium -vf scale=1920:1080 -c:a aac -b:a 192k',
            '高清720p': '-c:v libx264 -crf 23 -preset fast -vf scale=1280:720 -c:a aac -b:a 128k',
            '原画质': '-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 256k'
        }

        # 获取 `ffmpeg` 相关文件的路径
        self.ffmpeg_path = self.get_ffmpeg_path()
        self.ffplay_path = self.get_ffplay_path()
        self.ffprobe_path = self.get_ffprobe_path()

        # 创建 GUI 界面
        self.create_widgets()

        # 当前转换进程
        self.current_process = None

    def get_ffmpeg_path(self):
        """ 获取 ffmpeg.exe 的路径 """
        if getattr(sys, 'frozen', False):
            return os.path.join(sys._MEIPASS, "ffmpeg.exe")
        return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffmpeg.exe")

    def get_ffplay_path(self):
        """ 获取 ffplay.exe 的路径 """
        if getattr(sys, 'frozen', False):
            return os.path.join(sys._MEIPASS, "ffplay.exe")
        return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffplay.exe")

    def get_ffprobe_path(self):
        """ 获取 ffprobe.exe 的路径 """
        if getattr(sys, 'frozen', False):
            return os.path.join(sys._MEIPASS, "ffprobe.exe")
        return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffprobe.exe")

    def create_widgets(self):
        # 文件选择
        tk.Label(self.root, text="选择文件或文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.input_entry = tk.Entry(self.root, width=50)
        self.input_entry.grid(row=0, column=1, padx=5, pady=5)
        tk.Button(self.root, text="浏览", command=self.select_input_file_or_folder).grid(row=0, column=2, padx=5, pady=5)

        # 输出目录
        tk.Label(self.root, text="输出目录:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.output_entry = tk.Entry(self.root, width=50)
        self.output_entry.grid(row=1, column=1, padx=5, pady=5)
        self.output_entry.insert(0, os.getcwd())  # 默认当前目录
        tk.Button(self.root, text="浏览", command=self.select_output_dir).grid(row=1, column=2, padx=5, pady=5)

        # 预设选择
        tk.Label(self.root, text="转换预设:").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.preset_var = tk.StringVar()
        self.preset_combobox = ttk.Combobox(self.root, textvariable=self.preset_var, values=list(self.presets.keys()))
        self.preset_combobox.current(0)
        self.preset_combobox.grid(row=2, column=1, padx=5, pady=5, sticky="w")

        # 输出格式选择
        tk.Label(self.root, text="选择输出格式:").grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.format_var = tk.StringVar()
        self.format_combobox = ttk.Combobox(self.root, textvariable=self.format_var,
                                            values=[".mp4", ".avi", ".mkv", ".mov", ".flv"])
        self.format_combobox.current(0)
        self.format_combobox.grid(row=3, column=1, padx=5, pady=5, sticky="w")

        # 进度条
        self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate")
        self.progress.grid(row=4, column=0, columnspan=3, padx=5, pady=5)

        # 日志框
        self.log_text = tk.Text(self.root, height=10, width=60)
        self.log_text.grid(row=5, column=0, columnspan=3, padx=5, pady=5)

        # 转换按钮
        self.start_conversion_button = tk.Button(self.root, text="开始转换", command=self.start_conversion)
        self.start_conversion_button.grid(row=6, column=2, padx=5, pady=10)

        # 取消按钮
        tk.Button(self.root, text="取消转换", command=self.cancel_conversion).grid(row=6, column=0, padx=5, pady=5)

    def select_input_file_or_folder(self):
        input_path = filedialog.askopenfilename(filetypes=[("视频文件", "*.ts;*.mp4;*.avi;*.mkv;*.mov;*.flv")])
        if not input_path:
            input_path = filedialog.askdirectory()
        self.input_entry.delete(0, tk.END)
        self.input_entry.insert(0, input_path)

    def select_output_dir(self):
        dir_path = filedialog.askdirectory()
        self.output_entry.delete(0, tk.END)
        self.output_entry.insert(0, dir_path)

    def log_message(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)

    def start_conversion(self):
        """ 开始转换时禁用按钮,防止重复点击 """
        self.start_conversion_button.config(state=tk.DISABLED)

        input_file = self.input_entry.get()
        output_dir = self.output_entry.get()
        output_format = self.format_var.get()
        preset = self.presets[self.preset_var.get()]

        output_file = os.path.join(output_dir,
                                   os.path.splitext(os.path.basename(input_file))[0] + "_converted" + output_format)

        ffmpeg_cmd = [self.ffmpeg_path, "-i", input_file, "-y"] + preset.split() + [output_file]

        self.log_message(f"执行命令: {' '.join(ffmpeg_cmd)}")
        threading.Thread(target=self.run_ffmpeg_silently, args=(ffmpeg_cmd, output_file)).start()

    def run_ffmpeg_silently(self, cmd, output_file):
        """ 运行 ffmpeg 并隐藏窗口,同时在转换结束后恢复按钮 """
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)
        out, err = process.communicate()  # 获取输出和错误信息
        process.wait()

        if process.returncode == 0:
            self.log_message(f"转换完成,文件保存在: {output_file}")
        else:
            self.log_message(f"错误: {err.decode()}")

        # 转换完成后恢复按钮
        self.start_conversion_button.config(state=tk.NORMAL)

    def cancel_conversion(self):
        if self.current_process:
            self.current_process.terminate()
            self.log_message("转换已取消")
            self.start_conversion_button.config(state=tk.NORMAL)  # 恢复按钮状态


if __name__ == "__main__":
    root = tk.Tk()
    app = VideoConverterApp(root)
    root.mainloop()



"""
pyinstaller --onefile --add-data "ffmpeg.exe;." --add-data "ffplay.exe;." --add-data "ffprobe.exe;." --noconsole 222.py

"""

 带日期限制的代码:

import os
import sys
import tkinter as tk
from tkinter import filedialog, ttk
import subprocess
import threading
import datetime
import requests

class VideoConverterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("万能高清转换器-三松礼品-强哥出品必属精品")

        # 设置程序的时间限制(比如:2025年2月12日 18:00)
        self.restricted_time = datetime.datetime(2025, 12, 30, 18, 0, 0)

        # 获取当前互联网时间并比较
        if not self.check_time_allowed():
            self.show_restricted_message()
            return

        # 转换参数预设
        self.presets = {
            '高清1080p': '-c:v libx264 -crf 23 -preset medium -vf scale=1920:1080 -c:a aac -b:a 192k',
            '高清720p': '-c:v libx264 -crf 23 -preset fast -vf scale=1280:720 -c:a aac -b:a 128k',
            '原画质': '-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 256k'
        }

        # 获取 `ffmpeg` 相关文件的路径
        self.ffmpeg_path = self.get_ffmpeg_path()
        self.ffplay_path = self.get_ffplay_path()
        self.ffprobe_path = self.get_ffprobe_path()

        # 创建 GUI 界面
        self.create_widgets()

        # 当前转换进程
        self.current_process = None

    def get_ffmpeg_path(self):
        """ 获取 ffmpeg.exe 的路径 """
        if getattr(sys, 'frozen', False):
            return os.path.join(sys._MEIPASS, "ffmpeg.exe")
        return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffmpeg.exe")

    def get_ffplay_path(self):
        """ 获取 ffplay.exe 的路径 """
        if getattr(sys, 'frozen', False):
            return os.path.join(sys._MEIPASS, "ffplay.exe")
        return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffplay.exe")

    def get_ffprobe_path(self):
        """ 获取 ffprobe.exe 的路径 """
        if getattr(sys, 'frozen', False):
            return os.path.join(sys._MEIPASS, "ffprobe.exe")
        return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffprobe.exe")

    def check_time_allowed(self):
        """ 获取当前互联网时间,并与限制时间进行比较 """
        try:
            response = requests.get('http://worldtimeapi.org/api/timezone/Etc/UTC')
            data = response.json()
            current_time = datetime.datetime.fromisoformat(data['datetime'].replace('Z', '+00:00'))

            if current_time > self.restricted_time:
                return False  # 超过限制时间,禁止使用
            return True
        except requests.RequestException:
            # 如果无法获取互联网时间,默认允许使用
            return True

    def show_restricted_message(self):
        """ 显示程序禁止使用的消息 """
        tk.Label(self.root, text="程序禁止使用:超过限制时间", font=("Arial", 16)).pack(padx=5, pady=5)
        self.root.after(5000, self.root.quit)  # 5秒后自动关闭程序

    def create_widgets(self):
        # 文件选择
        tk.Label(self.root, text="选择文件或文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.input_entry = tk.Entry(self.root, width=50)
        self.input_entry.grid(row=0, column=1, padx=5, pady=5)
        tk.Button(self.root, text="浏览", command=self.select_input_file_or_folder).grid(row=0, column=2, padx=5, pady=5)

        # 输出目录
        tk.Label(self.root, text="输出目录:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.output_entry = tk.Entry(self.root, width=50)
        self.output_entry.grid(row=1, column=1, padx=5, pady=5)
        self.output_entry.insert(0, os.getcwd())  # 默认当前目录
        tk.Button(self.root, text="浏览", command=self.select_output_dir).grid(row=1, column=2, padx=5, pady=5)

        # 预设选择
        tk.Label(self.root, text="转换预设:").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.preset_var = tk.StringVar()
        self.preset_combobox = ttk.Combobox(self.root, textvariable=self.preset_var, values=list(self.presets.keys()))
        self.preset_combobox.current(0)
        self.preset_combobox.grid(row=2, column=1, padx=5, pady=5, sticky="w")

        # 输出格式选择
        tk.Label(self.root, text="选择输出格式:").grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.format_var = tk.StringVar()
        self.format_combobox = ttk.Combobox(self.root, textvariable=self.format_var,
                                            values=[".mp4", ".avi", ".mkv", ".mov", ".flv"])
        self.format_combobox.current(0)
        self.format_combobox.grid(row=3, column=1, padx=5, pady=5, sticky="w")

        # 进度条
        self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate")
        self.progress.grid(row=4, column=0, columnspan=3, padx=5, pady=5)

        # 日志框
        self.log_text = tk.Text(self.root, height=10, width=60)
        self.log_text.grid(row=5, column=0, columnspan=3, padx=5, pady=5)

        # 转换按钮
        self.start_conversion_button = tk.Button(self.root, text="开始转换", command=self.start_conversion)
        self.start_conversion_button.grid(row=6, column=2, padx=5, pady=10)

        # 取消按钮
        tk.Button(self.root, text="取消转换", command=self.cancel_conversion).grid(row=6, column=0, padx=5, pady=5)

    def select_input_file_or_folder(self):
        input_path = filedialog.askopenfilename(filetypes=[("视频文件", "*.ts;*.mp4;*.avi;*.mkv;*.mov;*.flv")])
        if not input_path:
            input_path = filedialog.askdirectory()
        self.input_entry.delete(0, tk.END)
        self.input_entry.insert(0, input_path)

    def select_output_dir(self):
        dir_path = filedialog.askdirectory()
        self.output_entry.delete(0, tk.END)
        self.output_entry.insert(0, dir_path)

    def log_message(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)

    def start_conversion(self):
        """ 开始转换时禁用按钮,防止重复点击 """
        self.start_conversion_button.config(state=tk.DISABLED)

        input_file = self.input_entry.get()
        output_dir = self.output_entry.get()
        output_format = self.format_var.get()
        preset = self.presets[self.preset_var.get()]

        output_file = os.path.join(output_dir,
                                   os.path.splitext(os.path.basename(input_file))[0] + "_converted" + output_format)

        ffmpeg_cmd = [self.ffmpeg_path, "-i", input_file, "-y"] + preset.split() + [output_file]

        self.log_message(f"执行命令: {' '.join(ffmpeg_cmd)}")
        threading.Thread(target=self.run_ffmpeg_silently, args=(ffmpeg_cmd, output_file)).start()

    def run_ffmpeg_silently(self, cmd, output_file):
        """ 运行 ffmpeg 并隐藏窗口,同时在转换结束后恢复按钮 """
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)
        out, err = process.communicate()  # 获取输出和错误信息
        process.wait()

        if process.returncode == 0:
            self.log_message(f"转换完成,文件保存在: {output_file}")
        else:
            self.log_message(f"错误: {err.decode()}")

        # 转换完成后恢复按钮
        self.start_conversion_button.config(state=tk.NORMAL)

    def cancel_conversion(self):
        if self.current_process:
            self.current_process.terminate()
            self.log_message("转换已取消")
            self.start_conversion_button.config(state=tk.NORMAL)  # 恢复按钮状态


if __name__ == "__main__":
    root = tk.Tk()
    app = VideoConverterApp(root)
    root.mainloop()



"""
pyinstaller --onefile --add-data "ffmpeg.exe;." --add-data "ffplay.exe;." --add-data "ffprobe.exe;." --noconsole 222.py

"""

 

posted @ 2025-02-11 17:47  *感悟人生*  阅读(87)  评论(0)    收藏  举报