Skip to content

Commit d8b3167

Browse files
EstrellaXDclaude
andcommitted
feat: migrate backend to uv package manager
Replace pip + requirements.txt with uv for dependency management. Multi-stage Dockerfile using ghcr.io/astral-sh/uv, CI updated to use astral-sh/setup-uv, and ruff config moved to [tool.ruff.lint]. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent bfba010 commit d8b3167

8 files changed

Lines changed: 1792 additions & 156 deletions

File tree

.github/workflows/build.yml

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,15 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v4
16-
- name: Set up Python 3.11
17-
uses: actions/setup-python@v3
16+
- uses: astral-sh/setup-uv@v4
1817
with:
19-
python-version: '3.11'
18+
version: "latest"
2019
- name: Install dependencies
21-
run: |
22-
python -m pip install --upgrade pip
23-
if [ -f backend/requirements.txt ]; then pip install -r backend/requirements.txt; fi
24-
pip install pytest
20+
run: cd backend && uv sync --group dev
2521
- name: Test
26-
working-directory: ./backend/src
2722
run: |
28-
mkdir -p config
29-
pytest
23+
mkdir -p backend/config
24+
cd backend && uv run pytest src/test -v
3025
3126
webui-test:
3227
runs-on: ubuntu-latest
@@ -295,10 +290,6 @@ jobs:
295290
echo ${{ needs.version-info.outputs.version }}
296291
echo "VERSION='${{ needs.version-info.outputs.version }}'" >> module/__version__.py
297292
298-
- name: Copy requirements.txt
299-
working-directory: ./backend
300-
run: cp requirements.txt src/requirements.txt
301-
302293
- name: Zip app
303294
run: |
304295
cd backend && zip -r app-v${{ needs.version-info.outputs.version }}.zip src

CLAUDE.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
AutoBangumi is an RSS-based automatic anime downloading and organization tool. It monitors RSS feeds from anime torrent sites (Mikan, DMHY, Nyaa), downloads episodes via qBittorrent, and organizes files into a Plex/Jellyfin-compatible directory structure with automatic renaming.
8+
9+
## Development Commands
10+
11+
### Backend (Python)
12+
13+
```bash
14+
# Install dependencies
15+
cd backend && uv sync
16+
17+
# Install with dev tools
18+
cd backend && uv sync --group dev
19+
20+
# Run development server (port 7892, API docs at /docs)
21+
cd backend/src && uv run python main.py
22+
23+
# Run tests
24+
cd backend && uv run pytest
25+
cd backend && uv run pytest src/test/test_xxx.py -v # run specific test
26+
27+
# Linting and formatting
28+
cd backend && uv run ruff check src
29+
cd backend && uv run black src
30+
31+
# Add a dependency
32+
cd backend && uv add <package>
33+
34+
# Add a dev dependency
35+
cd backend && uv add --group dev <package>
36+
```
37+
38+
### Frontend (Vue 3 + TypeScript)
39+
40+
```bash
41+
cd webui
42+
43+
# Install dependencies (uses pnpm, not npm)
44+
pnpm install
45+
46+
# Development server (port 5173)
47+
pnpm dev
48+
49+
# Build for production
50+
pnpm build
51+
52+
# Type checking
53+
pnpm test:build
54+
55+
# Linting and formatting
56+
pnpm lint
57+
pnpm lint:fix
58+
pnpm format
59+
```
60+
61+
### Docker
62+
63+
```bash
64+
docker build -t auto_bangumi:latest .
65+
docker run -p 7892:7892 -v /path/to/config:/app/config -v /path/to/data:/app/data auto_bangumi:latest
66+
```
67+
68+
## Architecture
69+
70+
```
71+
backend/src/
72+
├── main.py # FastAPI entry point, mounts API at /api
73+
├── module/
74+
│ ├── api/ # REST API routes (v1 prefix)
75+
│ │ ├── auth.py # Authentication endpoints
76+
│ │ ├── bangumi.py # Anime series CRUD
77+
│ │ ├── rss.py # RSS feed management
78+
│ │ ├── config.py # Configuration endpoints
79+
│ │ ├── program.py # Program status/control
80+
│ │ └── search.py # Torrent search
81+
│ ├── core/ # Application logic
82+
│ │ ├── program.py # Main controller, orchestrates all operations
83+
│ │ ├── sub_thread.py # Background task execution
84+
│ │ └── status.py # Application state tracking
85+
│ ├── models/ # SQLModel ORM models (Pydantic + SQLAlchemy)
86+
│ ├── database/ # Database operations (SQLite at data/data.db)
87+
│ ├── rss/ # RSS parsing and analysis
88+
│ ├── downloader/ # qBittorrent integration
89+
│ │ └── client/ # Download client implementations (qb, aria2, tr)
90+
│ ├── searcher/ # Torrent search providers (Mikan, DMHY, Nyaa)
91+
│ ├── parser/ # Torrent name parsing, metadata extraction
92+
│ │ └── analyser/ # TMDB, Mikan, OpenAI parsers
93+
│ ├── manager/ # File organization and renaming
94+
│ ├── notification/ # Notification plugins (Telegram, Bark, etc.)
95+
│ ├── conf/ # Configuration management, settings
96+
│ ├── network/ # HTTP client utilities
97+
│ └── security/ # JWT authentication
98+
99+
webui/src/
100+
├── api/ # Axios API client functions
101+
├── components/ # Vue components (basic/, layout/, setting/)
102+
├── pages/ # Router-based page components
103+
├── router/ # Vue Router configuration
104+
├── store/ # Pinia state management
105+
├── i18n/ # Internationalization (zh-CN, en-US)
106+
└── hooks/ # Custom Vue composables
107+
```
108+
109+
## Key Data Flow
110+
111+
1. RSS feeds are parsed by `module/rss/` to extract torrent information
112+
2. Torrent names are analyzed by `module/parser/analyser/` to extract anime metadata
113+
3. Downloads are managed via `module/downloader/` (qBittorrent API)
114+
4. Files are organized by `module/manager/` into standard directory structure
115+
5. Background tasks run in `module/core/sub_thread.py` to avoid blocking
116+
117+
## Code Style
118+
119+
- Python: Black (88 char lines), Ruff linter (E, F, I rules), target Python 3.10+
120+
- TypeScript: ESLint + Prettier
121+
- Run formatters before committing
122+
123+
## Git Branching
124+
125+
- `main`: Stable releases only
126+
- `X.Y-dev` branches: Active development (e.g., `3.1-dev`)
127+
- Bug fixes → PR to current released version's `-dev` branch
128+
- New features → PR to next version's `-dev` branch
129+
130+
## Notes
131+
132+
- Documentation and comments are in Chinese
133+
- Uses SQLModel (hybrid Pydantic + SQLAlchemy ORM)
134+
- External integrations: qBittorrent API, TMDB API, OpenAI API
135+
- Version tracked in `/config/version.info`

Dockerfile

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
# syntax=docker/dockerfile:1
22

3-
FROM alpine:3.18
3+
FROM ghcr.io/astral-sh/uv:0.5-python3.12-alpine AS builder
4+
5+
WORKDIR /app
6+
ENV UV_COMPILE_BYTECODE=1
7+
ENV UV_LINK_MODE=copy
8+
9+
# Install dependencies (cached layer)
10+
COPY backend/pyproject.toml backend/uv.lock ./
11+
RUN uv sync --frozen --no-dev --no-install-project
12+
13+
# Copy application source
14+
COPY backend/src ./src
15+
16+
17+
FROM python:3.12-alpine AS runtime
18+
19+
RUN apk add --no-cache \
20+
bash \
21+
su-exec \
22+
shadow \
23+
tini \
24+
tzdata
425

526
ENV LANG="C.UTF-8" \
627
TZ=Asia/Shanghai \
@@ -10,36 +31,19 @@ ENV LANG="C.UTF-8" \
1031

1132
WORKDIR /app
1233

13-
COPY backend/requirements.txt .
14-
RUN set -ex && \
15-
apk add --no-cache \
16-
bash \
17-
busybox-suid \
18-
python3 \
19-
py3-aiohttp \
20-
py3-bcrypt \
21-
py3-pip \
22-
su-exec \
23-
shadow \
24-
tini \
25-
openssl \
26-
tzdata && \
27-
python3 -m pip install --no-cache-dir --upgrade pip && \
28-
sed -i '/bcrypt/d' requirements.txt && \
29-
pip install --no-cache-dir -r requirements.txt && \
30-
# Add user
31-
mkdir -p /home/ab && \
32-
addgroup -S ab -g 911 && \
33-
adduser -S ab -G ab -h /home/ab -s /sbin/nologin -u 911 && \
34-
# Clear
35-
rm -rf \
36-
/root/.cache \
37-
/tmp/*
38-
39-
COPY --chmod=755 backend/src/. .
34+
# Copy venv and source from builder
35+
COPY --from=builder /app/.venv /app/.venv
36+
COPY --from=builder /app/src .
4037
COPY --chmod=755 entrypoint.sh /entrypoint.sh
4138

42-
ENTRYPOINT ["tini", "-g", "--", "/entrypoint.sh"]
39+
# Add user
40+
RUN mkdir -p /home/ab && \
41+
addgroup -S ab -g 911 && \
42+
adduser -S ab -G ab -h /home/ab -s /sbin/nologin -u 911
43+
44+
ENV PATH="/app/.venv/bin:$PATH"
4345

4446
EXPOSE 7892
45-
VOLUME [ "/app/config" , "/app/data" ]
47+
VOLUME ["/app/config", "/app/data"]
48+
49+
ENTRYPOINT ["tini", "-g", "--", "/entrypoint.sh"]

backend/pyproject.toml

Lines changed: 25 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,109 +4,58 @@ version = "3.1.0"
44
description = "AutoBangumi - Automated anime download manager"
55
requires-python = ">=3.10"
66
dependencies = [
7-
"anyio>=4.0.0",
8-
"beautifulsoup4>=4.12.0",
9-
"certifi>=2023.5.7",
10-
"charset-normalizer>=3.1.0",
11-
"click>=8.1.3",
127
"fastapi>=0.109.0",
13-
"h11>=0.14.0",
14-
"idna>=3.4",
15-
"pydantic>=2.0.0",
16-
"sniffio>=1.3.0",
17-
"soupsieve>=2.4.1",
18-
"typing_extensions>=4.0.0",
19-
"urllib3>=2.0.3",
208
"uvicorn>=0.27.0",
21-
"Jinja2>=3.1.2",
22-
"python-dotenv>=1.0.0",
9+
"httpx>=0.25.0",
10+
"httpx-socks>=0.9.0",
11+
"beautifulsoup4>=4.12.0",
12+
"sqlmodel>=0.0.14",
13+
"sqlalchemy[asyncio]>=2.0.0",
14+
"aiosqlite>=0.19.0",
15+
"pydantic>=2.0.0",
2316
"python-jose>=3.3.0",
2417
"passlib>=1.7.4",
2518
"bcrypt>=4.0.1,<4.1",
2619
"python-multipart>=0.0.6",
27-
"sqlmodel>=0.0.14",
28-
"sse-starlette>=1.6.5",
29-
"semver>=3.0.1",
20+
"python-dotenv>=1.0.0",
21+
"Jinja2>=3.1.2",
3022
"openai>=1.54.3",
31-
"httpx>=0.25.0",
32-
"httpx-socks>=0.9.0",
33-
"aiosqlite>=0.19.0",
34-
"sqlalchemy[asyncio]>=2.0.0",
23+
"semver>=3.0.1",
24+
"sse-starlette>=1.6.5",
3525
"webauthn>=2.0.0",
26+
"urllib3>=2.0.3",
3627
]
3728

38-
[project.optional-dependencies]
29+
[dependency-groups]
3930
dev = [
4031
"pytest>=8.0.0",
4132
"pytest-asyncio>=0.23.0",
4233
"ruff>=0.1.0",
4334
"black>=24.0.0",
35+
"pre-commit>=3.0.0",
4436
]
4537

4638
[tool.pytest.ini_options]
4739
testpaths = ["src/test"]
4840
asyncio_mode = "auto"
4941

5042
[tool.ruff]
51-
select = [
52-
# pycodestyle(E): https://beta.ruff.rs/docs/rules/#pycodestyle-e-w
53-
"E",
54-
# Pyflakes(F): https://beta.ruff.rs/docs/rules/#pyflakes-f
55-
"F",
56-
# isort(I): https://beta.ruff.rs/docs/rules/#isort-i
57-
"I"
58-
]
59-
ignore = [
60-
# E501: https://beta.ruff.rs/docs/rules/line-too-long/
61-
'E501',
62-
# F401: https://beta.ruff.rs/docs/rules/unused-import/
63-
# avoid unused imports lint in `__init__.py`
64-
'F401',
65-
]
66-
67-
# Allow autofix for all enabled rules (when `--fix`) is provided.
68-
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
69-
unfixable = []
70-
71-
# Exclude a variety of commonly ignored directories.
72-
exclude = [
73-
".bzr",
74-
".direnv",
75-
".eggs",
76-
".git",
77-
".git-rewrite",
78-
".hg",
79-
".mypy_cache",
80-
".nox",
81-
".pants.d",
82-
".pytype",
83-
".ruff_cache",
84-
".svn",
85-
".tox",
86-
".venv",
87-
"__pypackages__",
88-
"_build",
89-
"buck-out",
90-
"build",
91-
"dist",
92-
"node_modules",
93-
"venv",
94-
]
95-
per-file-ignores = {}
96-
97-
# Same as Black.
9843
line-length = 88
99-
100-
# Allow unused variables when underscore-prefixed.
101-
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
102-
103-
# Assume Python 3.10.
10444
target-version = "py310"
45+
exclude = [".venv", "venv", "build", "dist"]
46+
47+
[tool.ruff.lint]
48+
select = ["E", "F", "I"]
49+
ignore = ["E501", "F401"]
50+
fixable = ["ALL"]
51+
unfixable = []
10552

106-
[tool.ruff.mccabe]
107-
# Unlike Flake8, default to a complexity level of 10.
53+
[tool.ruff.lint.mccabe]
10854
max-complexity = 10
10955

56+
[tool.uv]
57+
package = false
58+
11059
[tool.black]
11160
line-length = 88
11261
target-version = ['py310', 'py311']

backend/requirements-dev.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)