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完成相应调整及修改

END
本文作者:
文章标题:部署M3U8视频离线下载遇到的问题及解决
本文地址:https://233.517128.xyz/archives/36.html
版权说明:若无注明,本文皆学习笔记原创,转载请保留文章出处。
最后修改:2025 年 11 月 13 日
如果觉得我的文章对你有用,请随意赞赏