first commit
This commit is contained in:
169
README.md
Normal file
169
README.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# pyTorrent
|
||||
|
||||
Single-page web UI for rTorrent inspired by the ruTorrent workflow.
|
||||
|
||||
## Features
|
||||
|
||||
- Flask + Flask-SocketIO.
|
||||
- SQLite storage for preferences, SCGI profiles, Bootstrap theme and UI font.
|
||||
- Multiple rTorrent profiles per user.
|
||||
- Profiles can be added and edited from the UI; the remote profile flag hides local CPU/RAM usage to avoid confusing it with remote rTorrent host resources.
|
||||
- Active rTorrent profile switching from the UI.
|
||||
- Live torrent list over WebSocket.
|
||||
- Application-side cache with patch updates instead of full table reloads.
|
||||
- User operations executed through ThreadPoolExecutor.
|
||||
- `move` and `remove` actions are executed per profile in request order, so later deletes wait for earlier moves.
|
||||
- Job log shows a short date/time in the table and the full timestamp in the tooltip.
|
||||
- Bulk start, pause, stop, resume, recheck, remove and move.
|
||||
- Move supports `move_data=true`; data is physically moved on the rTorrent side in the background and status is polled from a marker file, so long `mv` operations do not hit the SCGI timeout.
|
||||
- Multi-magnet add modal.
|
||||
- Bottom status bar with CPU, RAM, rTorrent version, speeds, limits, total DL/UP and port-check status when enabled.
|
||||
- Torrent context menu.
|
||||
- Keyboard shortcuts.
|
||||
- Details tabs: General, Files, Peers, Trackers and Log.
|
||||
- Smart Queue shows the last 10 operations by default and can expand history to 100 rows.
|
||||
- Peer GeoIP with MaxMind GeoLite2-City.mmdb and IP cache.
|
||||
- Static cache busting with MD5 and cache headers.
|
||||
- Appearance preferences: default Bootstrap or Bootswatch themes Flatly, Litera, Lumen, Minty, Sketchy, Solar, Spacelab, United and Zephyr.
|
||||
- Font preferences: default theme font, Adwaita Mono and additional matching fonts.
|
||||
|
||||
## Complete Debian / Ubuntu install
|
||||
|
||||
The repository includes a full installer for Debian and Ubuntu:
|
||||
|
||||
```bash
|
||||
wget -qO /tmp/install_debian_ubuntu.sh "https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_debian_ubuntu.sh" && sudo bash /tmp/install_debian_ubuntu.sh
|
||||
```
|
||||
|
||||
The installer installs system packages, creates the dedicated `pytorrent` system user, copies the app to `/opt/pytorrent`, creates a virtual environment, installs Python dependencies, downloads offline frontend libraries and GeoIP data when helper scripts are available, then creates and starts the `pytorrent` systemd service.
|
||||
|
||||
Optional environment variables:
|
||||
|
||||
```bash
|
||||
PYTORRENT_USER=pytorrent \
|
||||
PYTORRENT_APP_DIR=/opt/pytorrent \
|
||||
PYTORRENT_SERVICE_NAME=pytorrent \
|
||||
sudo -E bash scripts/install_debian_ubuntu.sh
|
||||
```
|
||||
|
||||
Check the service with:
|
||||
|
||||
```bash
|
||||
sudo systemctl status pytorrent
|
||||
sudo journalctl -u pytorrent -f
|
||||
```
|
||||
|
||||
## Run locally
|
||||
|
||||
```bash
|
||||
./install.sh
|
||||
. venv/bin/activate
|
||||
python app.py
|
||||
```
|
||||
|
||||
Default URL: `http://127.0.0.1:8090`.
|
||||
|
||||
## Production run
|
||||
|
||||
Preferred mode without development Werkzeug:
|
||||
|
||||
```bash
|
||||
. venv/bin/activate
|
||||
gunicorn --worker-class gthread --workers 1 --threads 32 --bind 0.0.0.0:8090 --access-logfile - --error-logfile - wsgi:app
|
||||
```
|
||||
|
||||
Note: the app keeps `async_mode="threading"`, so WebSocket, `start_background_task`, operation queues and the poller run in the same model as before.
|
||||
|
||||
Alternatives reviewed but not enabled by default:
|
||||
|
||||
- Gunicorn with `eventlet`: works with Flask-SocketIO, but requires green threads and monkey patching, which increases regression risk for file and SCGI operations.
|
||||
- Gunicorn with `gevent`: a valid production option, but it needs extra dependencies and compatibility testing.
|
||||
- Multiple Gunicorn workers: requires Redis, RabbitMQ or Kafka as the Socket.IO message queue, so it is not a drop-in replacement.
|
||||
|
||||
## Reverse proxy
|
||||
|
||||
When pyTorrent is served behind a reverse proxy, enable proxy header handling only when the proxy is trusted:
|
||||
|
||||
```env
|
||||
PYTORRENT_PROXY_FIX_ENABLE=true
|
||||
PYTORRENT_SESSION_COOKIE_SECURE=true
|
||||
```
|
||||
|
||||
The proxy should forward at least:
|
||||
|
||||
```txt
|
||||
X-Forwarded-For
|
||||
X-Forwarded-Proto
|
||||
X-Forwarded-Host
|
||||
X-Forwarded-Port
|
||||
```
|
||||
|
||||
This keeps login redirects, session cookies and same-origin API checks correct when HTTPS is terminated by the proxy. If pyTorrent is mounted under a sub-path, also forward `X-Forwarded-Prefix`.
|
||||
|
||||
## SCGI profile
|
||||
|
||||
Example:
|
||||
|
||||
```txt
|
||||
scgi://127.0.0.1:5000/RPC2
|
||||
```
|
||||
|
||||
On the rTorrent side:
|
||||
|
||||
```txt
|
||||
network.scgi.open_port = 127.0.0.1:5000
|
||||
```
|
||||
|
||||
## GeoIP
|
||||
|
||||
The installer downloads GeoLite2-City once to:
|
||||
|
||||
```txt
|
||||
data/GeoLite2-City.mmdb
|
||||
```
|
||||
|
||||
Manual download:
|
||||
|
||||
```bash
|
||||
./scripts/download_geoip.sh
|
||||
```
|
||||
|
||||
The script uses `https://git.io/GeoLite2-City.mmdb` as the primary source and `https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb` as fallback. The `data` directory is set to `755`, and the database file is set to `644`.
|
||||
|
||||
## API docs
|
||||
|
||||
OpenAPI documentation is available at `/docs`. `/api/profiles` supports `max_parallel_jobs` with default value `5` and `is_remote`; `PUT /api/profiles/{profile_id}` edits an existing profile. `/api/preferences` supports fields including `theme`, `bootstrap_theme`, `font_family`, `table_columns_json`, `peers_refresh_seconds` and `port_check_enabled`. `/api/port-check` returns port status with `checked_at`; for remote profiles the public IP is read through rTorrent with fallbacks when supported. `/api/system/status` returns `usage_available=false` for remote profiles and does not read local CPU/RAM.
|
||||
|
||||
`/api/openapi.json` includes reusable schemas for main API responses, including `TorrentListResponse`, `TorrentSummary`, `TorrentFilterSummary`, `CleanupSummary` and `AppStatus`. `GET /api/torrents` documents the `summary` field used by sidebar filters.
|
||||
|
||||
## Admin CLI
|
||||
|
||||
Reset an existing user's password:
|
||||
|
||||
```bash
|
||||
. venv/bin/activate
|
||||
python -m pytorrent.cli reset-password admin new_password
|
||||
```
|
||||
|
||||
Without the password argument, the CLI asks for it interactively:
|
||||
|
||||
```bash
|
||||
python -m pytorrent.cli reset-password admin
|
||||
```
|
||||
|
||||
The command uses the same database as the app and respects `PYTORRENT_DB_PATH` from `.env`. The reset changes only the password hash and leaves role and permissions unchanged.
|
||||
|
||||
## API authentication tokens
|
||||
|
||||
When `PYTORRENT_AUTH_ENABLE=0`, API endpoints work without authentication.
|
||||
|
||||
When `PYTORRENT_AUTH_ENABLE=1`, API access can use either the browser session cookie or a per-user API token. Admin users can generate a token in **Tools -> Users** with **Generate token**. Copy the token immediately; only its prefix and metadata are stored afterwards.
|
||||
|
||||
Use a token in one of these forms:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer pt_xxx" http://127.0.0.1:8080/api/system/status
|
||||
curl -H "X-API-Key: pt_xxx" http://127.0.0.1:8080/api/system/status
|
||||
```
|
||||
|
||||
Token permissions follow the owning user's role and rTorrent profile permissions. Revoked tokens stop working immediately.
|
||||
Reference in New Issue
Block a user