m3u8下载合并视频
更新: 5/28/2025 字数: 0 字 时长: 0 分钟
一、下载python
更新: 5/28/2025 字数: 0 字 时长: 0 分钟
二、利用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 分钟

五、修改软件配置文件
更新: 5/28/2025 字数: 0 字 时长: 0 分钟
