Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 50 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,58 @@
FROM python:3.12.7-alpine AS builder
WORKDIR /builder

RUN apk update && \
apk add --no-cache \
build-base \
linux-headers

# 安装构建依赖
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir cython setuptools

COPY setup.py setup.py
COPY app ./app

RUN python setup.py

RUN apk del build-base linux-headers && \
find app -type f \( -name "*.py" ! -name "main.py" ! -name "__init__.py" -o -name "*.c" \) -delete

FROM python:3.12.7-alpine

ENV TZ=Asia/Shanghai
VOLUME ["/config", "/logs", "/media","/fonts"]
VOLUME ["/config", "/logs", "/media", "/fonts"]
EXPOSE 8000

# 添加运行时依赖
RUN apk update && \
apk add --no-cache \
tzdata \
curl \
build-base \
linux-headers \
libgomp && \
cp /usr/share/zoneinfo/${TZ} /etc/localtime && \
echo ${TZ} > /etc/timezone

RUN apk update
RUN apk add --no-cache build-base linux-headers tzdata
# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt \
-i https://pypi.tuna.tsinghua.edu.cn/simple \
--default-timeout=100 \
&& rm requirements.txt \
&& pip install fastapi==0.109.0 uvicorn==0.27.0 --force-reinstall

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt && \
rm requirements.txt
# 清理构建工具
RUN apk del build-base linux-headers && \
rm -rf /var/cache/apk/*

COPY app /app
# 从构建阶段复制应用
COPY --from=builder /builder/app /app

RUN rm -rf /tmp/*
# 最终清理
RUN apk del curl && \
rm -rf /var/cache/apk/* && \
rm -rf /tmp/*

ENTRYPOINT ["python", "/app/main.py"]
ENTRYPOINT ["python", "/app/main.py", "--host", "0.0.0.0", "--port", "8000"]
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,23 @@
```bash
docker run -d --name autofilm -v ./config:/config -v ./media:/media -v ./logs:/logs akimio/autofilm
```

2. Docker 中手动触发特定任务
```bash
docker exec autofilm python /app/run.py <任务ID>
```
通过`docker exec`命令可以在运行中的容器内执行run.py脚本来手动触发特定任务。
2. Python 环境运行(Python3.12)
```bash
python app/main.py
```

3. 手动触发特定任务
```bash
python app/run.py <任务ID>
```
通过`run.py`可以手动触发配置文件中定义的特定任务,而不需要等待定时任务执行。

# Strm文件优点
- [x] 轻量化 Emby 服务器,降低 Emby 服务器的性能需求以及硬盘需求
- [x] 运行稳定
Expand Down Expand Up @@ -93,4 +105,4 @@
# Star History
<a href="https://github.com/Akimio521/AutoFilm/stargazers">
<img width="500" alt="Star History Chart" src="https://api.star-history.com/svg?repos=Akimio521/AutoFilm&type=Date">
</a>
</a>
33 changes: 33 additions & 0 deletions app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,39 @@ def Ani2AlistList(self) -> list[dict[str, Any]]:
return ani2alist_list

@property
def API_ENABLE(self) -> bool:
"""是否启用API服务"""
return self._get_config("Settings", "API_ENABLE", False)

@property
def API_PORT(self) -> int:
"""API服务监听端口"""
return self._get_config("Settings", "API_PORT", 8000)
def _get_config(self, section: str, key: str, default: Any) -> Any:
"""统一配置获取方法"""
# 修改前:使用 with self.CONFIG.open() as f:
# 修改后:
def load_config(self):
config_file = self.CONFIG_DIR / "config.yaml"
if config_file.exists():
with open(config_file, "r", encoding="utf-8") as f:
self._config = safe_load(f)

@property
def API_PORT(self) -> int:
"""API服务监听端口"""
return self._get_config("Settings", "API_PORT", 8000)
def _get_config(self, section: str, key: str, default: Any) -> Any:
"""统一配置获取方法"""
with self.CONFIG.open(mode="r", encoding="utf-8") as f:
config = safe_load(f)
return config.get(section, {}).get(key, default)

@property
def API_KEY(self) -> str:

"""API验证密钥"""
return self._get_config("Settings", "API_KEY", "")
def LibraryPosterList(self) -> list[dict[str, Any]]:
with self.CONFIG.open(mode="r", encoding="utf-8") as file:
library_poster_list = safe_load(file).get("LibraryPosterList", [])
Expand Down
34 changes: 32 additions & 2 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

from app.core import settings, logger
from app.extensions import LOGO
from app.modules import Alist2Strm, Ani2Alist
from fastapi import FastAPI
import uvicorn
from app.modules import Alist2Strm, Ani2Alist, LibraryPoster


Expand All @@ -21,12 +24,39 @@ def print_logo() -> None:
print(f" {settings.APP_NAME} {settings.APP_VERSION} ".center(65, "="))
print("")

from app.modules.api import router as api_router

def start_api_server():
app = FastAPI(title=settings.APP_NAME)
app.include_router(api_router)

uvicorn.run(
app,
host="0.0.0.0",
port=settings.API_PORT,
log_config=None
)

def __mkdir(self) -> None:
"""
创建目录
"""
# 修改前:使用 with self.CONFIG_DIR as dir_path:
if not self.CONFIG_DIR.exists():
self.CONFIG_DIR.mkdir(parents=True, exist_ok=True)

if not self.LOG_DIR.exists():
self.LOG_DIR.mkdir(parents=True, exist_ok=True)

if __name__ == "__main__":
print_logo()

logger.info(f"AutoFilm {settings.APP_VERSION} 启动中...")
logger.debug(f"是否开启 DEBUG 模式: {settings.DEBUG}")

# 启动API服务器
if settings.API_ENABLE:
from threading import Thread
Thread(target=start_api_server, daemon=True).start()
logger.info(f"API服务已启动在 {settings.API_PORT} 端口")

scheduler = AsyncIOScheduler()

Expand Down
50 changes: 50 additions & 0 deletions app/modules/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import APIKeyHeader

from app.core import settings, logger
from app.modules import Alist2Strm, Ani2Alist

router = APIRouter()
security = APIKeyHeader(name="X-API-Key", auto_error=False)

# 修改依赖声明方式(移除类型标注中的str)
async def get_api_key(api_key = Depends(security)):
if not api_key:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing API Key"
)
if api_key != settings.API_KEY:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid API Key"
)
return api_key

# 修改路由参数声明(移除类型标注中的str)
@router.post("/trigger/alist2strm")
async def trigger_alist2strm(
server_id: str,
_ = Depends(get_api_key)
):
logger.info(f"API触发Alist2Strm任务:{server_id}")
# 查找对应配置
server_config = next((s for s in settings.AlistServerList if s["id"] == server_id), None)
if not server_config:
raise HTTPException(status_code=404, detail="Server not found")

await Alist2Strm(**server_config).run()
return {"status": "success"}

@router.post("/trigger/ani2alist")
async def trigger_ani2alist(
server_id: str,
_ = Depends(get_api_key)
):
logger.info(f"API触发Ani2Alist任务:{server_id}")
server_config = next((s for s in settings.Ani2AlistList if s["id"] == server_id), None)
if not server_config:
raise HTTPException(status_code=404, detail="Server not found")

await Ani2Alist(**server_config).run()
return {"status": "success"}
118 changes: 118 additions & 0 deletions app/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env python3

import sys
import asyncio
from sys import path
from os.path import dirname

# 添加项目根目录到路径
path.append(dirname(dirname(__file__)))

from app.core.config import settings

# 延迟导入,避免sklearn依赖问题
# 只在需要时才导入相关模块
def get_alist2strm():
try:
from app.modules.alist2strm import Alist2Strm
return Alist2Strm
except ImportError as e:
print(f"导入Alist2Strm模块时出错: {e}")
print("请确保已安装所有依赖库,或者检查Docker环境中是否缺少必要的系统库(如libgomp.so.1)")
sys.exit(1)


def get_ani2alist():
try:
from app.modules.ani2alist import Ani2Alist
return Ani2Alist
except ImportError as e:
print(f"导入Ani2Alist模块时出错: {e}")
print("请确保已安装所有依赖库,或者检查Docker环境中是否缺少必要的系统库(如libgomp.so.1)")
sys.exit(1)


def get_libraryposter():
try:
from app.modules.libraryposter import LibraryPoster
return LibraryPoster
except ImportError as e:
print(f"导入LibraryPoster模块时出错: {e}")
print("请确保已安装所有依赖库,或者检查Docker环境中是否缺少必要的系统库(如libgomp.so.1)")
sys.exit(1)


def find_task_by_id(task_list, task_id):
"""根据ID查找任务配置"""
for task in task_list:
if task.get('id') == task_id:
return task
return None


def main():
if len(sys.argv) != 2:
print("使用方法: python run.py <任务ID>")
print("可用的任务ID:")

# 显示所有Alist2Strm任务ID
for task in settings.AlistServerList:
print(f" Alist2Strm: {task.get('id')}")

# 显示所有Ani2Alist任务ID
for task in settings.Ani2AlistList:
print(f" Ani2Alist: {task.get('id')}")

# 显示所有LibraryPoster任务ID
for task in settings.LibraryPosterList():
print(f" LibraryPoster: {task.get('id')}")

return

task_id = sys.argv[1]

# 查找Alist2Strm任务
alist_task = find_task_by_id(settings.AlistServerList, task_id)
if alist_task:
print(f"正在执行 Alist2Strm 任务: {task_id}")
Alist2Strm = get_alist2strm()
alist_instance = Alist2Strm(**alist_task)
asyncio.run(alist_instance.run())
return

# 查找Ani2Alist任务
ani_task = find_task_by_id(settings.Ani2AlistList, task_id)
if ani_task:
print(f"正在执行 Ani2Alist 任务: {task_id}")
Ani2Alist = get_ani2alist()
ani_instance = Ani2Alist(**ani_task)
asyncio.run(ani_instance.run())
return

# 查找LibraryPoster任务
poster_task = find_task_by_id(settings.LibraryPosterList(), task_id)
if poster_task:
print(f"正在执行 LibraryPoster 任务: {task_id}")
LibraryPoster = get_libraryposter()
poster_instance = LibraryPoster(**poster_task)
asyncio.run(poster_instance.run())
return

print(f"未找到ID为 '{task_id}' 的任务")
print("可用的任务ID:")

# 显示所有Alist2Strm任务ID
for task in settings.AlistServerList:
print(f" Alist2Strm: {task.get('id')}")

# 显示所有Ani2Alist任务ID
for task in settings.Ani2AlistList:
print(f" Ani2Alist: {task.get('id')}")

# 显示所有LibraryPoster任务ID
for task in settings.LibraryPosterList():
print(f" LibraryPoster: {task.get('id')}")


if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions config/config.yaml.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Settings:
API_ENABLE: True # 启用API接口
API_PORT: 8000 # API服务端口
API_KEY: your_secret_key # API访问密钥
DEV: False # 开发者模式(可选,默认 False)

Alist2StrmList:
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ aiofile==3.8.8
httpx[http2]==0.27.2
pydantic==2.9.2
pypinyin==0.53.0
fastapi==0.109.0
uvicorn==0.27.1
python-multipart==0.0.9
pillow==11.3.0
numpy==2.3.1
scikit-learn==1.7.0
Loading