diff --git a/Dockerfile b/Dockerfile index d49a04e..cd1c881 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,7 @@ FROM python:3.12.4-alpine ENV TZ=Asia/Shanghai \ - CONFIG_PATH=/config/config.yaml \ - LOG_LEVEL=INFO\ - INTERVAL=3600 + CONFIG_PATH=/config/config.yaml COPY entrypoint.sh entrypoint.sh diff --git a/app/autofilm.py b/app/autofilm.py deleted file mode 100644 index 9210f8a..0000000 --- a/app/autofilm.py +++ /dev/null @@ -1,88 +0,0 @@ -import logging -from pathlib import Path - -import yaml - -from modules import Alist2Strm - - -class AutoFilm: - def __init__( - self, - config_path: str, - ): - """ - 实例化 AutoFilm 对象 - - :param config_path: 配置文件路径 - """ - - self.base_dir: Path = Path(__file__).parent.absolute() - - config_path = Path(config_path) - self.config_path: Path = ( - Path(config_path) - if Path(config_path).is_absolute() - else self.base_dir / config_path - ) - - self.config_data = {} - - try: - with self.config_path.open(mode="r", encoding="utf-8") as f: - self.config_data = yaml.safe_load(f) - except Exception as e: - logging.critical( - f"配置文件{config_path}加载失败,程序即将停止,错误信息:{str(e)}" - ) - else: - try: - read_output_dir = Path(self.config_data["Settings"]["output_dir"]) - self.output_dir = ( - read_output_dir - if read_output_dir.is_absolute() - else self.base_dir / read_output_dir - ) - - self.library_mode = self.config_data["Settings"]["library_mode"] - if self.library_mode: - self.subtitle: bool = False - self.img: bool = False - self.nfo: bool = False - else: - self.subtitle: bool = self.config_data["Settings"]["subtitle"] - self.img: bool = self.config_data["Settings"]["img"] - self.nfo: bool = self.config_data["Settings"]["nfo"] - - except Exception as e: - logging.error(f"配置文件{self.config_path}读取错误,错误信息:{str(e)}") - - logging.info(f"输出目录:{self.output_dir}".center(50, "=")) - - def run_Alist2Strm(self) -> None: - """ - 运行 Alist2Strm 模块 - """ - - try: - alist_server_list: list[dict] = self.config_data["AlistServerList"] - except Exception as e: - logging.error(f"Alist服务器列表读取失败,错误信息:{str(e)}") - else: - logging.debug("Alist服务器加载成功") - for alist_server in alist_server_list: - alist2strm = Alist2Strm( - alist_server.get("url"), - alist_server.get("username"), - alist_server.get("password"), - alist_server.get("base_path"), - alist_server.get("token"), - self.output_dir, - self.subtitle, - self.img, - self.nfo, - self.library_mode, - alist_server.get("async_mode"), - alist_server.get("overwrite"), - ) - alist2strm.run() diff --git a/app/core/__init__.py b/app/core/__init__.py new file mode 100644 index 0000000..156144f --- /dev/null +++ b/app/core/__init__.py @@ -0,0 +1 @@ +from .config import settings \ No newline at end of file diff --git a/app/core/config.py b/app/core/config.py new file mode 100644 index 0000000..072cd19 --- /dev/null +++ b/app/core/config.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + + +import logging +from pathlib import Path +from yaml import safe_load + +from version import APP_VERSION + + +class SettingManager: + """ + 系统配置 + """ + + # APP 名称 + APP_NAME: str = "Autofilm" + # APP 版本 + APP_VERSION: int = APP_VERSION + # 时区 + TZ: str = "Asia/Shanghai" + + def __init__(self) -> None: + """ + 初始化 SettingManager 对象 + """ + self.__mkdir() + self.__init_logging() + + def __mkdir(self) -> None: + """ + 创建目录 + """ + with self.CONFIG_DIR as dir_path: + if not dir_path.exists(): + dir_path.mkdir(parents=True, exist_ok=True) + + def __init_logging(self): + """ + 初始化 loggging 日志模块内容 + """ + with self.CONFIG.open(mode="r", encoding="utf-8") as file: + log_level = safe_load(file).get("Settings").get("log_level") or "INFO" + + formatter = "[%(levelname)s]%(asctime)s - %(message)s" + logging.basicConfig(format=formatter, level=getattr(logging, log_level)) + + @property + def BASE_DIR(self) -> Path: + return Path(__file__).parents[2] + + @property + def CONFIG_DIR(self) -> Path: + return self.BASE_DIR / "config" + + @property + def CONFIG(self) -> Path: + return self.CONFIG_DIR / "config.yaml" + + @property + def AlistServerList(self) -> list[dict[str, any]]: + with self.CONFIG.open(mode="r", encoding="utf-8") as file: + alist_server_list = safe_load(file).get("Alist2StrmList", []) + return alist_server_list + + +settings = SettingManager() diff --git a/app/main.py b/app/main.py index d29d482..f5af0f7 100644 --- a/app/main.py +++ b/app/main.py @@ -1,29 +1,34 @@ -# -*- coding:utf-8 -*- -import argparse +#!/usr/bin/env python3 +# encoding: utf-8 + import logging +import asyncio +from sys import path +from os.path import dirname + +from apscheduler.schedulers.asyncio import AsyncIOScheduler +from apscheduler.triggers.cron import CronTrigger -import autofilm -from version import APP_VERSION +path.append(dirname(__file__)) +from core import settings +from modules import Alist2Strm if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Autofilm参数配置") - parser.add_argument( - "--config_path", type=str, help="配置文件路径", default="../config/config.yaml" - ) - parser.add_argument( - "--log_level", - type=str, - help="日志级别", - default="INFO", - choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], - ) - args = parser.parse_args() + logging.info(f"当前的APP版本是:{settings.APP_VERSION}") - formatter = "[%(asctime)s][%(levelname)s]%(funcName)s:%(message)s" - logging.basicConfig(format=formatter, level=getattr(logging, args.log_level)) + scheduler = AsyncIOScheduler() + + for server in settings.AlistServerList: + cron = server.get("cron") + if cron: + scheduler.add_job(Alist2Strm(**server).run,trigger=CronTrigger.from_crontab(cron)) + logging.info(f"{server["id"]}已被添加至后台任务") + else: + logging.warning(f"{server["id"]}未设置Cron") - logging.info(f"当前的APP版本是:{APP_VERSION}") - logging.info(f"配置文件路径:{args.config_path}") + scheduler.start() - my_autofilm = autofilm.AutoFilm(config_path=args.config_path) - my_autofilm.run_Alist2Strm() + try: + asyncio.get_event_loop().run_forever() + except (KeyboardInterrupt, SystemExit): + print("AutoFilm程序退出!") diff --git a/config/config.yaml.example b/config/config.yaml.example index c5891d3..929dc7b 100644 --- a/config/config.yaml.example +++ b/config/config.yaml.example @@ -1,34 +1,31 @@ Settings: - output_dir: /media # 输出路径 - subtitle: True # 是否下载字幕 - img: False # 是否下载图片 - nfo: True # 是否下载视频信息文件 - library_mode: False # 媒体库模式 + log_level: DEBUG # 日志输出等级(可选,默认 INFO) AlistServerList: - - id: 动漫A # 任意字符,用于标识Alist服务器 - url: https://alist.example.com # Alist服务器URL - username: alist # Alist账号 - password: adminadmin # Alist密码 - base_path: /ani/A/ # Alist服务器上文件夹路径 - token: # AList未启用签名时,设置为空字符串 - async_mode: False # 设置 subtitle,img,nfo 等二进制文件是否启用异步下载 - overwrite: False # 本地路径存在同名文件时是否重新生成/下载该文件 - - - id: 电影A - url: https://alist.example1.com + - cron: 0 20 * * * # 后台定时任务 Crontable 表达式 + url: https://alist.akimio.top # Alist 服务器地址 + username: admin # Alist 账号 + password: adminadmin # Alist 密码 + token: # AList 未启用签名时,设置为空字符串 + source_dir: /ani/A # Alist 服务器上文件夹路径 + target_dir: D:\media\ # 输出路径 + flatten_mode: False # 平铺模式,开启后 subtitle、image、nfo 强制关闭(可选,默认 False) + subtitle: False # 是否下载字幕文件(可选,默认 False) + image: False # 是否下载图片文件(可选,默认 False) + nfo: False # 是否下载 .nfo 文件(可选,默认 False) + overwrite: False # 覆盖模式,本地路径存在同名文件时是否重新生成/下载该文件(可选,默认 False) + max_workers: 5 # 下载文件最大并发数(可选,默认 5) + - cron: 0 0 7 * * + url: http://alist.example2.com:5244 username: alist - password: alist - base_path: /movie/A/ - token: - async_mode: True - overwrite: False - - - id: OneDrive - url: https://alist.example2.com - username: alist - password: adminadmin - base_path: /网盘/OneDrive/ + password: alist token: alist-a1b2c3d4-12... - async_mode: False - overwrite: True + source_dir: /ani/A + target_dir: ~/media/my_video + flatten_mode: False + subtitle: False + image: False + nfo: False + overwrite: False + max_workers: 5 + \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index b6bea36..ddd0335 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,15 +4,4 @@ if [[ ! -f $CONFIG_PATH ]]; then echo "配置文件 $CONFIG_PATH 不存在,请到映射目录下进行设置!" fi -if [[ "$INTERVAL" -eq 0 ]]; then - echo "正在执行主程序..." - python /app/main.py --config_path $CONFIG_PATH --log_level $LOG_LEVEL - echo "执行完成,容器即将退出。" -else - while true; do - echo "正在执行主程序..." - python /app/main.py --config_path $CONFIG_PATH --log_level $LOG_LEVEL - echo "等待 $INTERVAL 秒后再次执行..." - sleep $INTERVAL - done -fi \ No newline at end of file +python /app/main.py \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0f5af57..5c64809 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ aiofile == 3.8.8 PyYAML == 6.0.1 -python-alist == 0.0.13.0.2 \ No newline at end of file +python-alist == 0.0.13.0.2 +APScheduler == 3.10.4 \ No newline at end of file