AI摘要:本文讨论了在部署M3U8视频离线下载项目时遇到的问题及其解决方案。主要问题包括容器无法启动和布局错乱。针对启动问题,提供了三种解决方法,其中手动复制配置文件为最佳选择。布局问题则通过修改HTML文件解决。此外,文章还提到上传到Alist和使用aria2下载的相关问题,并提供了相应的代码示例。最终,经过调整,项目基本可用。
前言
最近在某知名网站上看到自己喜欢的视频就想着下载下来,每次都用客户端、软件下载太麻烦,就想着能不能整个网页,直接下载好一键传到网盘,然后就找到了这个项目M3U8dudu,但实测用docker部署会有一些问题。
无法启动
碰到的第一个问题就是使用作者给的命令后容器无法启动,根本原因是挂载的/root/config目录下未生成config.ini配置文件。
手动复制一份config.ini文件到/root/config目录下,并将启动命令修改为python app.py --config /root/config/config.ini
修改启动命令是因为,两边文件无法自动同步更改,不修改的话容器仍然以容器内部config.ini为准,后续管理起来麻烦。
直接删掉/root/config:/app/config,取消挂载配置文件也可以启动。不过后续配置麻烦,且容器更新的话,配置文件会丢失。
修改镜像文件,删除项目内config文件夹及里面config.ini,新建一个generate_config.py来创建配置文件,实测是可以的。不过本人测试环境误删了,导致代码保存下来
布局问题
项目启动后,使用电脑端访问布局错乱,手机端和平板显示正常,这里提供我修改好的index.html和play.html。
上传问题及aria2下载问题
使用原本上传代码,测试一直无法成功上传到alist上,不过脚本还可以完善,比如增加上传进度检测等,但实在是懒得整了,主打一个功能正常,能用就行。
import requests
from urllib.parse import quote
import os
import json
# 读取配置文件
import configparser
config = configparser.ConfigParser()
config.read("./config/config.ini", encoding="utf-8")
base_url = config.get("upload_settings", "base_url", fallback="")
remote_path = config.get("upload_settings", "remote_path", fallback="")
log_path_file = config.get("download_settings", "log_path_file", fallback="./log.txt")
def login():
"""
登录 Alist 并获取 token
"""
url = base_url + '/api/auth/login'
payload = {'Username': config.get("upload_settings", "UserName", fallback=""),
'Password': config.get("upload_settings", "PassWord", fallback="")}
try:
response = requests.post(url, data=payload)
response_data = response.json()
if response_data.get('code') in ['200', 200]:
return response_data.get('data').get('token')
else:
print(f"登录失败!错误信息:{response_data}")
return None
except Exception as e:
print(f"登录过程中发生错误!错误信息:{e}")
return None
def upload_alist(local_file_path, title):
"""
上传文件到 Alist
"""
token = login()
if not token:
print("获取 Alist token 失败,无法上传文件!")
return False
try:
# 构造请求
url = base_url + "/api/fs/put"
file_size = os.path.getsize(local_file_path)
ori_url = remote_path + title + ".mp4"
encode_url = quote(ori_url, 'utf-8')
headers = {
"Authorization": token,
"Content-Length": str(file_size),
"Content-Type": "video/mp4",
"File-Path": encode_url,
'As-Task': 'true',
}
# 上传文件
with open(local_file_path, "rb") as f:
response = requests.put(url, data=f, headers=headers)
# 读取响应内容(只读取一次)
response_data = response.json()
# 检查响应状态
if response_data.get("code") in ["200", 200]:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write(f"文件 {title}.mp4 上传成功!\n")
return True
else:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write(f"上传失败!错误信息:{response_data}\n")
return False
except Exception as e:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write(f"上传过程中发生错误!错误信息:{e}\n")
return False然后本人aria2-pro同样是docker部署,alist可以调用,但是这个脚本一直调用不了,所有稍微修改了一下,直接调用Alist添加 离线下载任务。
import http.client
import json
import configparser
import datetime
import time
import upload # 引用 upload.py 中的 login 函数
from typing import Optional, List
# 读取配置文件
config = configparser.ConfigParser()
config.read("./config/config.ini", encoding="utf-8")
# 配置项
try:
base_url = config.get("upload_settings", "base_url")
except:
base_url = "http://127.0.0.1:5244"
try:
download_path = config.get("aria2_settings", "download_path")
except:
download_path = "./"
try:
log_path_file = config.get("download_settings", "log_path_file")
except:
log_path_file = "./log.txt"
def update_last_line(filename, new_line):
"""
更新指定文件的最后一行
"""
try:
with open(filename, 'r', encoding='utf-8') as file:
lines = file.readlines()
if len(lines) > 0: # 如果读到内容,更新最后一行
lines[-1] = new_line + '\n'
with open(filename, 'w', encoding='utf-8') as file:
file.writelines(lines)
else: # 如果没有读到内容,直接写入
with open(filename, 'w', encoding='utf-8') as file:
file.writelines(new_line)
except FileNotFoundError:
with open(filename, 'w', encoding='utf-8') as file:
file.writelines(f"{filename} not found.")
def adduri(uri):
"""
提交离线下载任务到 Alist
"""
# 获取文件名
title = uri.split('/')[-1]
# 获取 Alist 的 token
token = upload.login()
if not token:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write("获取 Alist token 失败,无法提交离线下载任务!\n")
return
# 构造请求
conn = http.client.HTTPConnection(base_url.split('//')[1]) # 去掉协议部分
payload = json.dumps({
"path": download_path,
"urls": [uri],
"tool": "aria2",
"delete_policy": "delete_on_upload_succeed"
})
headers = {
'Authorization': token,
'Content-Type': 'application/json'
}
try:
# 提交任务
conn.request("POST", "/api/fs/add_offline_download", payload, headers)
res = conn.getresponse()
data = res.read().decode("utf-8")
res_data = json.loads(data)
if res_data.get("code") in [200, "200"]:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write(f"任务 {title} 已成功提交到 Alist 离线下载队列\n")
print(f"任务 {title} 已成功提交到 Alist 离线下载队列")
else:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write(f"提交任务失败!错误信息:{res_data.get('message')}\n")
print(f"提交任务失败!错误信息:{res_data.get('message')}")
except Exception as e:
with open(log_path_file, "a", encoding="utf-8") as log_file:
log_file.write(f"提交任务时发生错误!错误信息:{e}\n")
print(f"提交任务时发生错误!错误信息:{e}")
finally:
conn.close()后记
这样修改完基本属于可以使用了,本人基本也不太会代码修改,这里面的代码基本依靠deepseek完成相应调整及修改 