Files
Auto_Bangumi/CLAUDE.md
Estrella Pan 122cf68eac fix(ci): release only from manually pushed tags, never from merged PRs
Merging PR #1063 ("Doc update", 3.3-dev -> main) triggered the stable
release path, which fell back to the raw PR title as the version string
and shipped a Docker image tagged Doc-update as :latest — every
container pulling latest then crashed on SemVer parsing (#1065).

The release trigger is now explicit:
- bare X.Y.Z tag -> stable release, refused unless the tagged commit is
  an ancestor of main
- tag containing alpha/beta -> pre-release (unchanged)
- PR merges only run tests and a docker build test

Also pass head.ref through an env var instead of inlining it in the
script (injection hardening), and take release notes solely from the
changelog file since tag pushes carry no PR body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jejs2dffkscAbhZkcjZ1oK
2026-07-08 16:25:09 +02:00

182 lines
8.0 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
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.
## Development Commands
### Backend (Python)
```bash
# Install dependencies
cd backend && uv sync
# Install with dev tools
cd backend && uv sync --group dev
# Run development server (port 7892, API docs at /docs)
cd backend/src && uv run python main.py
# Run tests
cd backend && uv run pytest
cd backend && uv run pytest src/test/test_xxx.py -v # run specific test
# Linting and formatting
cd backend && uv run ruff check src
cd backend && uv run black src
# Add a dependency
cd backend && uv add <package>
# Add a dev dependency
cd backend && uv add --group dev <package>
```
### Frontend (Vue 3 + TypeScript)
```bash
cd webui
# Install dependencies (uses pnpm, not npm)
pnpm install
# Development server (port 5173)
pnpm dev
# Build for production
pnpm build
# Type checking
pnpm test:build
# Linting and formatting
pnpm lint
pnpm lint:fix
pnpm format
```
### Docker
```bash
docker build -t auto_bangumi:latest .
docker run -p 7892:7892 -v /path/to/config:/app/config -v /path/to/data:/app/data auto_bangumi:latest
```
## Architecture
```
backend/src/
├── main.py # FastAPI entry point, mounts API at /api
├── module/
│ ├── api/ # REST API routes (v1 prefix)
│ │ ├── auth.py # Authentication endpoints
│ │ ├── bangumi.py # Anime series CRUD
│ │ ├── rss.py # RSS feed management
│ │ ├── config.py # Configuration endpoints
│ │ ├── program.py # Program status/control
│ │ └── search.py # Torrent search
│ ├── core/ # Application logic
│ │ ├── context.py # AppContext composition root (built in create_app, on app.state.ctx)
│ │ ├── scheduler.py # PeriodicTask + Scheduler (generic background-loop runner)
│ │ ├── loops.py # The individual periodic tick functions (rss/rename/offset/calendar)
│ │ └── offset_scanner.py
│ ├── models/ # SQLModel ORM models (Pydantic + SQLAlchemy)
│ ├── database/ # Async DB (aiosqlite) — repos + Database + migrations.py
│ ├── rss/ # RSS parsing and analysis
│ ├── downloader/ # qBittorrent integration
│ │ ├── base.py # Downloader Protocol + DownloaderCapabilities
│ │ └── client/ # Download client implementations (qb, aria2, mock)
│ ├── searcher/ # Torrent search providers (Mikan, DMHY, Nyaa)
│ ├── parser/ # Torrent name parsing, metadata extraction
│ │ └── analyser/ # TMDB, Mikan, OpenAI parsers
│ ├── manager/ # File organization and renaming
│ ├── notification/ # Notification plugins (Telegram, Bark, etc.)
│ ├── conf/ # Configuration management, settings
│ ├── network/ # HTTP client utilities
│ └── security/ # JWT authentication
webui/src/
├── api/ # Axios API client functions
├── components/ # Vue components (basic/, layout/, setting/)
├── pages/ # Router-based page components
├── router/ # Vue Router configuration
├── store/ # Pinia state management
├── i18n/ # Internationalization (zh-CN, en-US)
└── hooks/ # Custom Vue composables
```
## Key Data Flow
1. RSS feeds are parsed by `module/rss/` to extract torrent information
2. Torrent names are analyzed by `module/parser/analyser/` to extract anime metadata
3. Downloads are managed via `module/downloader/` (qBittorrent API)
4. Files are organized by `module/manager/` into standard directory structure
5. Periodic loops (`module/core/loops.py`) run under a `Scheduler` owned by the lifespan `AppContext` (`module/core/context.py`)
## Architecture conventions (3.3+)
- **Async DB throughout.** Everything runs on the async engine (`sqlite+aiosqlite`, WAL). Repositories (`database/{bangumi,rss,torrent,user,passkey}.py`) take an `AsyncSession` and are `async def`. `Database` is an async context manager owning one session with the repos attached (`db.rss`, `db.bangumi`, …).
- **Session per operation.** Get a session via `Depends(get_db)` in routes, or `async with Database() as db:` in loops/services. Never store a session on anything that outlives one request or one loop tick. `AppContext` holds no session.
- **Services take dependencies in their constructor** (composition, not inheritance): `RSSEngine(db)`, `TorrentManager(db)`, `Renamer(client)`, `SearchTorrent()`. They use `self.db.<repo>` internally; callers that only need a repo use `db.<repo>` directly.
- **Downloaders** implement the `Downloader` Protocol and declare `DownloaderCapabilities`; the facade (`DownloadClient`) skips-and-logs unsupported ops rather than crashing. The qB client is reused across operations (one login), not re-authed per call.
- **Config reloads** go through `AppContext.reload_settings()` (settings + http client + notifier + scheduler), not ad-hoc `settings.load()`.
## Code Style
- Python: Black (88 char lines), Ruff linter (E, F, I rules), target Python 3.10+
- TypeScript: ESLint + Prettier
- Run formatters before committing
## Git Branching
- `main`: Stable releases only
- `X.Y-dev` branches: Active development (e.g., `3.2-dev`)
- Bug fixes → PR to current released version's `-dev` branch
- New features → PR to next version's `-dev` branch
## Releasing
All releases are triggered by manually pushing a tag — merging a PR never releases.
### Beta Version
1. Update version in `backend/pyproject.toml`
2. Update `CHANGELOG.md` with the new version heading
3. Commit and push to the dev branch
4. Create and push a tag with the version name (e.g., `3.2.0-beta.4`):
```bash
git tag 3.2.0-beta.4
git push origin 3.2.0-beta.4
```
5. The CI/CD workflow (`.github/workflows/build.yml`) detects the tag contains "beta", uses the tag name as the VERSION string, generates `module/__version__.py`, and builds the Docker image (tagged `<version>` + `dev-latest`)
### Stable Version
1. Merge the dev branch into `main` via PR (this only runs tests and a build test)
2. Tag the merge commit on `main` with the bare semver version and push:
```bash
git tag 3.3.2 <merge-commit-on-main>
git push origin 3.3.2
```
3. CI validates the tag is `X.Y.Z` **and** points to a commit on `main` (refuses otherwise), then builds and pushes Docker images (tagged `<version>` + `latest`) and creates the GitHub release with notes from `docs/changelog/<X.Y>.md`
The VERSION is injected at build time via CI — `module/__version__.py` does not exist in the repo. At runtime, `module/conf/config.py` imports it or falls back to `"DEV_VERSION"`.
## Database Migrations
Schema migrations are tracked via a `schema_version` table in SQLite. To add a new migration:
1. Append a `Migration(version, "description", (…SQL…), already_applied=column_exists("table", "col"))` entry to the `MIGRATIONS` tuple in `backend/src/module/database/migrations.py` (`CURRENT_SCHEMA_VERSION` is derived from the list — do not edit it by hand)
2. Provide an `already_applied` guard (`column_exists` / `table_exists`) so a schema created out-of-band is detected and skipped
3. Migrations run automatically on startup via `run_migrations()` (each in a SAVEPOINT, stopping on first failure)
## Notes
- Documentation and comments are in Chinese
- Uses SQLModel (hybrid Pydantic + SQLAlchemy ORM)
- External integrations: qBittorrent API, TMDB API, OpenAI API
- Version tracked in `/config/version.info` (for cross-version upgrade detection)