Skip to content

m3u8下载合并视频

更新: 5/28/2025 字数: 0 字 时长: 0 分钟

一、下载python

更新: 5/28/2025 字数: 0 字 时长: 0 分钟

https://python.org/

二、利用python自带http.server搭建本地服务器

更新: 5/28/2025 字数: 0 字 时长: 0 分钟

python
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from functools import partial
import contextlib
import sys
import os
import socket
import threading
import webbrowser



class DualStackServer(ThreadingHTTPServer):
    def server_bind(self):
        with contextlib.suppress(Exception):
            self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
        return super().server_bind()

class HTTPGUI:
    def __init__(self, root):
        self.root = root
        self.server = None
        self.server_thread = None
        
        root.title("HTTP Server Config")
        self.create_widgets()
        self.root.bind("<<ServerStopped>>", self.on_server_stopped)

    def create_widgets(self):
        # IP Address
        ttk.Label(self.root, text="IP Address:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.ip_entry = ttk.Entry(self.root)
        self.ip_entry.insert(0, "0.0.0.0")  # 替换默认的127.0.0.1
        self.ip_entry.grid(row=0, column=1, padx=5, pady=5)

        # Port
        ttk.Label(self.root, text="Port:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.port_entry = ttk.Entry(self.root)
        self.port_entry.insert(0, "8000")
        self.port_entry.grid(row=1, column=1, padx=5, pady=5)

        # Directory
        ttk.Label(self.root, text="Directory:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        self.dir_entry = ttk.Entry(self.root)
        self.dir_entry.grid(row=2, column=1, padx=5, pady=5)
        ttk.Button(self.root, text="Browse", command=self.browse_directory).grid(row=2, column=2, padx=5, pady=5)

        # Controls
        self.start_btn = ttk.Button(self.root, text="Start Server", command=self.start_server)
        self.start_btn.grid(row=3, column=0, padx=5, pady=10)
        self.stop_btn = ttk.Button(self.root, text="Stop Server", command=self.stop_server, state=tk.DISABLED)
        self.stop_btn.grid(row=3, column=1, padx=5, pady=10)

        # 状态提示框架
        status_frame = ttk.LabelFrame(self.root, text="网络状态")
        status_frame.grid(row=4, column=0, columnspan=3, padx=5, pady=10, sticky=tk.EW)

        # 服务器状态标签
        self.status_label = ttk.Label(status_frame, text="状态: 已停止", foreground="gray")
        self.status_label.grid(row=0, column=0, padx=5, pady=2, sticky=tk.W)

        # IP/端口显示标签
        self.ip_label = ttk.Label(status_frame, text="监听地址: -")
        self.ip_label.grid(row=1, column=0, padx=5, pady=2, sticky=tk.W)
        
        self.port_label = ttk.Label(status_frame, text="本机IP: -") 
        self.port_label.grid(row=2, column=0, padx=5, pady=2, sticky=tk.W)

        # 域名访问链接 (新增在状态框架最后一行)
        self.domain_btn = ttk.Button(
            status_frame, 
            text="访问地址: -",
            style="Link.TLabel",
            command=lambda: self.open_browser()
        )
        self.domain_btn.grid(row=3, column=0, padx=5, pady=2, sticky=tk.W)

    def browse_directory(self):
        dir_path = filedialog.askdirectory()
        if dir_path:
            self.dir_entry.delete(0, tk.END)
            self.dir_entry.insert(0, dir_path)

    def validate_inputs(self):
        # Validate IP
        try:
            socket.inet_pton(socket.AF_INET, self.ip_entry.get())
        except socket.error:
            try:
                socket.inet_pton(socket.AF_INET6, self.ip_entry.get())
            except socket.error:
                return False, "Invalid IP Address"
        
        # Validate Port
        try:
            port = int(self.port_entry.get())
            if not (1 <= port <= 65535):
                return False, "Port must be 1-65535"
        except ValueError:
            return False, "Invalid Port Number"
        
        # Validate Directory
        if not os.path.isdir(self.dir_entry.get()):
            return False, "Directory does not exist"
        
        return True, ""

    def start_server(self):
        valid, msg = self.validate_inputs()
        if not valid:
            messagebox.showerror("Error", msg)
            return

        self.start_btn.config(state=tk.DISABLED)
        self.stop_btn.config(state=tk.NORMAL)
        
        server_args = (
            self.ip_entry.get(),
            int(self.port_entry.get()),
            self.dir_entry.get()
        )
        
        self.server_thread = threading.Thread(
            target=self.run_server,
            args=server_args,
            daemon=True
        )
        self.server_thread.start()

         # 更新状态显示
        self.status_label.config(text="状态: 运行中", foreground="green")
        self.ip_label.config(text=f"监听地址: {self.ip_entry.get()}:{self.port_entry.get()}")
        self.port_label.config(text=f"本机IP: {self.get_lan_ip() or '未知'}")
        lan_ip = self.get_lan_ip()
        port = self.port_entry.get()
        if lan_ip:
            self.domain_btn.config(text=f"访问地址: http://{lan_ip}:{port}", 
                                state=tk.NORMAL)
        else:
            self.domain_btn.config(text="无法获取IP地址", state=tk.DISABLED)

    def stop_server(self):
        if self.server:
            self.server.shutdown()
            self.server = None

    def run_server(self, bind, port, directory):
        handler = partial(SimpleHTTPRequestHandler, directory=directory)
        self.server = DualStackServer((bind, port), handler)
        
        try:
            print(f"Serving {directory} on {bind}:{port}")
            self.server.serve_forever()
        finally:
            self.server.server_close()
            self.root.event_generate("<<ServerStopped>>")

    def on_server_stopped(self, event):
        self.start_btn.config(state=tk.NORMAL)
        self.stop_btn.config(state=tk.DISABLED)
        print("Server stopped")

        # 重置状态显示
        self.status_label.config(text="状态: 已停止", foreground="gray")
        self.ip_label.config(text="监听地址: -")
        self.port_label.config(text="本机IP: -")

        # 重置域名显示 (新增以下代码)
        self.domain_btn.config(text="访问地址: -", state=tk.DISABLED)

    def get_lan_ip(self):
        # 获取本机的所有网络接口
        interfaces = socket.getaddrinfo(socket.gethostname(), None)
        for family, _, _, _, addr in interfaces:
            # 过滤出IPv4地址
            if family == socket.AF_INET:
                return addr[0]
        return None

    def open_browser(self):
        """打开浏览器访问服务"""
        lan_ip = self.get_lan_ip()
        port = self.port_entry.get()
        if lan_ip and port:
            webbrowser.open(f"http://{lan_ip}:{port}")

if __name__ == "__main__":
    root = tk.Tk()
    app = HTTPGUI(root)
    root.mainloop()
```ts
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from functools import partial
import contextlib
import sys
import os
import socket
import threading

class DualStackServer(ThreadingHTTPServer):
    def server_bind(self):
        with contextlib.suppress(Exception):
            self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
        return super().server_bind()

class HTTPGUI:
    def __init__(self, root):
        self.root = root
        self.server = None
        self.server_thread = None
        
        root.title("HTTP Server Config")
        self.create_widgets()
        self.root.bind("<<ServerStopped>>", self.on_server_stopped)

    def create_widgets(self):
        # IP Address
        ttk.Label(self.root, text="IP Address:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.ip_entry = ttk.Entry(self.root)
        self.ip_entry.insert(0, "127.0.0.1")
        self.ip_entry.grid(row=0, column=1, padx=5, pady=5)

        # Port
        ttk.Label(self.root, text="Port:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.port_entry = ttk.Entry(self.root)
        self.port_entry.insert(0, "8000")
        self.port_entry.grid(row=1, column=1, padx=5, pady=5)

        # Directory
        ttk.Label(self.root, text="Directory:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        self.dir_entry = ttk.Entry(self.root)
        self.dir_entry.grid(row=2, column=1, padx=5, pady=5)
        ttk.Button(self.root, text="Browse", command=self.browse_directory).grid(row=2, column=2, padx=5, pady=5)

        # Controls
        self.start_btn = ttk.Button(self.root, text="Start Server", command=self.start_server)
        self.start_btn.grid(row=3, column=0, padx=5, pady=10)
        self.stop_btn = ttk.Button(self.root, text="Stop Server", command=self.stop_server, state=tk.DISABLED)
        self.stop_btn.grid(row=3, column=1, padx=5, pady=10)

    def browse_directory(self):
        dir_path = filedialog.askdirectory()
        if dir_path:
            self.dir_entry.delete(0, tk.END)
            self.dir_entry.insert(0, dir_path)

    def validate_inputs(self):
        # Validate IP
        try:
            socket.inet_pton(socket.AF_INET, self.ip_entry.get())
        except socket.error:
            try:
                socket.inet_pton(socket.AF_INET6, self.ip_entry.get())
            except socket.error:
                return False, "Invalid IP Address"
        
        # Validate Port
        try:
            port = int(self.port_entry.get())
            if not (1 <= port <= 65535):
                return False, "Port must be 1-65535"
        except ValueError:
            return False, "Invalid Port Number"
        
        # Validate Directory
        if not os.path.isdir(self.dir_entry.get()):
            return False, "Directory does not exist"
        
        return True, ""

    def start_server(self):
        valid, msg = self.validate_inputs()
        if not valid:
            messagebox.showerror("Error", msg)
            return

        self.start_btn.config(state=tk.DISABLED)
        self.stop_btn.config(state=tk.NORMAL)
        
        server_args = (
            self.ip_entry.get(),
            int(self.port_entry.get()),
            self.dir_entry.get()
        )
        
        self.server_thread = threading.Thread(
            target=self.run_server,
            args=server_args,
            daemon=True
        )
        self.server_thread.start()

    def stop_server(self):
        if self.server:
            self.server.shutdown()
            self.server = None

    def run_server(self, bind, port, directory):
        handler = partial(SimpleHTTPRequestHandler, directory=directory)
        self.server = DualStackServer((bind, port), handler)
        
        try:
            print(f"Serving {directory} on {bind}:{port}")
            self.server.serve_forever()
        finally:
            self.server.server_close()
            self.root.event_generate("<<ServerStopped>>")

    def on_server_stopped(self, event):
        self.start_btn.config(state=tk.NORMAL)
        self.stop_btn.config(state=tk.DISABLED)
        print("Server stopped")

if __name__ == "__main__":
    root = tk.Tk()
    app = HTTPGUI(root)
    root.mainloop()
```
```md
from http.server import SimpleHTTPRequestHandler
from http.server import CGIHTTPRequestHandler
from http.server import ThreadingHTTPServer
from functools import partial
import contextlib
import sys
import os
import socket  # 需补上缺失的 socket 模块导入


class DualStackServer(ThreadingHTTPServer):
    def server_bind(self):
        with contextlib.suppress(Exception):
            self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
        return super().server_bind()


def run(
    server_class=DualStackServer,
    handler_class=SimpleHTTPRequestHandler,
    port=8000,
    bind="127.0.0.1",
    cgi=False,
    directory=os.getcwd(),  # 默认目录已改为用户指定路径
):
    if cgi:
        handler_class = partial(CGIHTTPRequestHandler, directory=directory)
    else:
        handler_class = partial(SimpleHTTPRequestHandler, directory=directory)

    with server_class((bind, port), handler_class) as httpd:
        print(f"Serving HTTP on {bind} port {port} (http://{bind}:{port}/) ...")
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\nKeyboard interrupt received, exiting.")
            sys.exit(0)


if __name__ == "__main__":
    # 指定目标目录(注意 Windows 路径需转义或使用原始字符串)
    run(
        port=8000,
        bind="127.0.0.1",
        directory=r"C:\Users\daozun\Desktop\11608",  # 关键修改点
    )
```

三、下载M3U8合并器

更新: 5/28/2025 字数: 0 字 时长: 0 分钟

N_m3u8DL-CLI_v3.0.2_with_ffmpeg_and_SimpleG.zip

四、修改index.m3u8配置文件

更新: 5/28/2025 字数: 0 字 时长: 0 分钟

image

五、修改软件配置文件

更新: 5/28/2025 字数: 0 字 时长: 0 分钟

image

Released under the MIT License.

本站访客数 人次 本站总访问量