diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index d4ba1c0..0000000 --- a/INSTALL.md +++ /dev/null @@ -1,198 +0,0 @@ -# pyTorrent stack installer - -This document describes the one-command installer for installing **rTorrent + pyTorrent** from a clean server. - -The installer is split into two layers: - -- `scripts/install_stack.sh` - public bootstrap script intended to be downloaded directly from Git. -- `scripts/stack_installers/` - OS-specific installers and helper scripts used by the bootstrap script. - -## Quick install - -Run as root or through `sudo`: - -```bash -curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh | sudo bash -``` - -The bootstrap script downloads the current pyTorrent repository, detects the operating system family, and runs the matching installer: - -- Debian / Ubuntu: `scripts/stack_installers/install_stack_debian_ubuntu.sh` -- RHEL-compatible systems: `scripts/stack_installers/install_stack_rhel.sh` - -Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Fedora-like systems where `dnf` or `yum` is available. - -## What gets installed - -Default installation includes: - -- rTorrent `v0.16.11` -- libtorrent `v0.16.11` -- minimal rTorrent build without c-ares/custom curl -- rTorrent system user: `rtorrent` -- rTorrent SCGI endpoint: `scgi://127.0.0.1:5000` -- rTorrent incoming BitTorrent port: `51300` -- pyTorrent application directory: `/opt/pytorrent` -- pyTorrent HTTP port: `8090` -- pyTorrent profile configured through the HTTP API - -The installer creates or updates a pyTorrent rTorrent profile through API after both services are installed. - -## Recommended usage with overrides - -Environment variables must be passed to the `sudo bash` process. - -Example: - -```bash -curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \ - | sudo PYTORRENT_PORT=8091 RTORRENT_SCGI_PORT=5001 bash -``` - -Another example with a custom profile name: - -```bash -curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \ - | sudo PYTORRENT_PROFILE_NAME="Local rTorrent" PYTORRENT_PORT=8090 bash -``` - -## Bootstrap parameters - -These variables are used by `scripts/install_stack.sh`. - -| Variable | Default | Description | -| --- | --- | --- | -| `PYTORRENT_REPO_URL` | `https://git.linuxiarz.pl/gru/pyTorrent` | Git repository base URL. | -| `PYTORRENT_REPO_BRANCH` | `master` | Branch used to download the repository archive. | -| `PYTORRENT_ARCHIVE_URL` | derived from repo URL and branch | Custom repository archive URL. | -| `PYTORRENT_BOOTSTRAP_DIR` | `/tmp/pytorrent-stack-installer` | Temporary directory used by the bootstrap script. | -| `PYTORRENT_KEEP_BOOTSTRAP_DIR` | `0` | Set to `1` to keep the temporary directory after installation. | - -Example using a different branch: - -```bash -curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \ - | sudo PYTORRENT_REPO_BRANCH=develop bash -``` - -## rTorrent parameters - -These variables are used by both stack installers. - -| Variable | Default | Description | -| --- | --- | --- | -| `RTORRENT_USER` | `rtorrent` | System user used to run rTorrent. | -| `RTORRENT_HOME` | `/home/${RTORRENT_USER}` | Home directory for the rTorrent user. | -| `RTORRENT_BASE_DIR` | `/opt/rtorrent_build` | Build and install directory for xmlrpc-c, libtorrent and rTorrent. | -| `RTORRENT_SCGI_PORT` | `5000` | Local SCGI port for rTorrent XMLRPC/SCGI. | -| `RTORRENT_TORRENT_PORT` | `51300` | Incoming BitTorrent listen port. | -| `RTORRENT_REF` | `v0.16.11` | rTorrent Git tag, branch, or commit. | -| `LIBTORRENT_REF` | `v0.16.11` | libtorrent Git tag, branch, or commit. | - -Example: - -```bash -curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \ - | sudo RTORRENT_USER=rtorrent RTORRENT_SCGI_PORT=5001 RTORRENT_TORRENT_PORT=51400 bash -``` - -## pyTorrent parameters - -| Variable | Default | Description | -| --- | --- | --- | -| `PYTORRENT_APP_DIR` | `/opt/pytorrent` | pyTorrent installation directory. | -| `PYTORRENT_PORT` | `8090` | HTTP port used by the pyTorrent service. | -| `PYTORRENT_BASE_URL` | `http://127.0.0.1:${PYTORRENT_PORT}` | Base URL used by the API configurator. | -| `PYTORRENT_PROFILE_NAME` | `Local rTorrent` | Name of the rTorrent profile created in pyTorrent. | -| `PYTORRENT_API_TOKEN` | empty | Bearer token used when pyTorrent API authentication is enabled. | -| `PYTORRENT_SERVICE_NAME` | `pytorrent` | systemd service name for pyTorrent. | -| `PYTORRENT_RTORRENT_SCGI_URL` | `scgi://127.0.0.1:${RTORRENT_SCGI_PORT}` | SCGI URL saved in the pyTorrent rTorrent profile. | - -Example with API token: - -```bash -curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \ - | sudo PYTORRENT_API_TOKEN="pt_xxx" bash -``` - -## API configurator parameters - -The API configurator can be run manually: - -```bash -/opt/pytorrent/venv/bin/python /opt/pytorrent/scripts/stack_installers/configure_pytorrent_api.py \ - --base-url http://127.0.0.1:8090 \ - --profile-name "Local rTorrent" \ - --scgi-url scgi://127.0.0.1:5000 -``` - -CLI options: - -| Option | Environment variable | Default | Description | -| --- | --- | --- | --- | -| `--base-url` | `PYTORRENT_BASE_URL` | `http://127.0.0.1:8090` | pyTorrent API base URL. | -| `--api-token` | `PYTORRENT_API_TOKEN` | empty | Bearer token for authenticated API calls. | -| `--profile-name` | `PYTORRENT_RTORRENT_PROFILE_NAME` | `Local rTorrent` | Profile name to create or update. | -| `--scgi-url` | `PYTORRENT_RTORRENT_SCGI_URL` | `scgi://127.0.0.1:5000` | rTorrent SCGI URL. | -| `--timeout` | `PYTORRENT_RTORRENT_TIMEOUT` | `10` | rTorrent request timeout in seconds. | -| `--wait` | `PYTORRENT_API_WAIT_SECONDS` | `90` | Time to wait for the pyTorrent API to become available. | -| `--remote` | `PYTORRENT_RTORRENT_REMOTE` | `0` | Mark profile as remote. Accepts `1`, `true`, `yes`, `on`. | - -## Local installation without bootstrap - -If the repository is already cloned: - -Debian / Ubuntu: - -```bash -sudo bash scripts/stack_installers/install_stack_debian_ubuntu.sh -``` - -RHEL-compatible systems: - -```bash -sudo bash scripts/stack_installers/install_stack_rhel.sh -``` - -## Installed service hints - -Check services: - -```bash -systemctl status pytorrent -systemctl status rtorrent@rtorrent.service -``` - -Check logs: - -```bash -tail -f /data/logs/app.log /data/logs/error.log -journalctl -u pytorrent -f -journalctl -u rtorrent@rtorrent.service -f -``` - -## Notes - -- The default rTorrent build is intentionally minimal. -- c-ares and custom curl are not enabled by the stack installer defaults. -- The rTorrent installer overwrites the generated `.rtorrent.rc` because the stack installer passes `--force-config`. -- pyTorrent is configured through the HTTP API after the service starts. -- If API authentication is enabled before profile configuration, pass `PYTORRENT_API_TOKEN`. - - -## Build logs and troubleshooting - -The stack installer writes quiet build output to `/var/log/pytorrent-installer` by default. -Override it with: - -```bash -PYTORRENT_STACK_LOG_DIR=/tmp/pytorrent-build-logs -``` - -For full command output during rTorrent/libtorrent compilation, run with: - -```bash -PYTORRENT_DEBUG_INSTALL=1 -``` - -On RHEL-compatible systems the installer also tries to enable CRB/PowerTools and installs `libcurl-devel`, `redhat-rpm-config`, `patch`, `diffutils`, `findutils`, `file`, and `libstdc++-devel`, because minimal Alma/Rocky images often do not include enough build tooling. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 2789310..5380e0d 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,325 @@ # pyTorrent -Single-page web UI for rTorrent inspired by the ruTorrent workflow. +Modern single-page web UI for managing rTorrent through SCGI/XML-RPC. pyTorrent focuses on fast live updates, multi-profile support, automation, diagnostics and a clean browser-based workflow inspired by ruTorrent. -## Features +> pyTorrent is a controller for your own rTorrent instance. It does not include a BitTorrent engine and does not bypass tracker, copyright or network rules. -- 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. +## Highlights -## Complete Debian / Ubuntu install +- Live torrent table with WebSocket updates and patch-based refreshes. +- Multiple rTorrent profiles, including local and remote hosts. +- Profile-level permissions, user management and API tokens. +- Bulk torrent actions: start, pause, stop, resume, recheck, remove and move. +- Background move/remove jobs with operation history. +- Smart Queue with recent job status and expandable history. +- Download Planner with quiet hours, speed limits, CPU/disk protection and dry-run mode. +- Adaptive Poller with configurable intervals and diagnostics. +- RSS tools, automation rules and cleanup helpers. +- Torrent details: general data, files, peers, trackers and logs. +- Peer GeoIP lookup with MaxMind GeoLite2 database support. +- Dashboard, smart views, global search and notification center. +- OpenAPI docs available from the app. +- Offline frontend assets support for self-hosted deployments. -The repository includes a full installer for Debian and Ubuntu: +## Screenshots -```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 +```md +![pyTorrent dashboard](docs/ss1.png) ``` -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. +## Requirements -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 +### Application + +- Python 3.10+ +- rTorrent with SCGI/XML-RPC enabled +- Linux server recommended for production + +### Python packages + +The project uses Flask, Flask-SocketIO, python-dotenv, psutil, geoip2, gunicorn and related runtime dependencies listed in `requirements.txt`. + +## Quick start + +Clone the repository and run the local installer: ```bash +git clone https://github.com/zdzichu6969/pyTorrent.git +cd pyTorrent ./install.sh . venv/bin/activate python app.py ``` -Default URL: `http://127.0.0.1:8090`. +Default URL: + +```text +http://127.0.0.1:8090 +``` + +Copy the example environment file before customizing the app: + +```bash +cp .env.example .env +``` + +## rTorrent SCGI profile + +Example pyTorrent profile URL: + +```text +scgi://127.0.0.1:5000/RPC2 +``` + +Example rTorrent configuration: + +```text +network.scgi.open_port = 127.0.0.1:5000 +``` + +For production, keep SCGI bound to localhost or a private trusted network only. + +## Stack installer + +The repository includes a stack installer for a clean server. It can install and configure rTorrent + pyTorrent together. + +Supported systems: + +- Debian / Ubuntu +- RHEL-compatible distributions: RHEL, Rocky Linux, AlmaLinux, CentOS Stream, Fedora-like systems with `dnf` or `yum` +- Arch Linux + +After cloning the repository: + +```bash +sudo bash scripts/install_stack.sh +``` + +The default stack install creates: + +| Component | Default | +| --- | --- | +| rTorrent user | `rtorrent` | +| rTorrent SCGI | `scgi://127.0.0.1:5000` | +| BitTorrent port | `51300` | +| pyTorrent app dir | `/opt/pytorrent` | +| pyTorrent HTTP port | `8090` | +| pyTorrent service | `pytorrent` | + +### One-line install with rtorrent + +After publishing the repository, replace `zdzichu6969` and branch name if needed: + +```bash +curl -fsSL https://raw.githubusercontent.com/zdzichu6969/pyTorrent/main/scripts/install_stack.sh \ + | sudo PYTORRENT_REPO_URL=https://github.com/zdzichu6969/pyTorrent \ + PYTORRENT_REPO_BRANCH=main \ + PYTORRENT_ARCHIVE_URL=https://github.com/zdzichu6969/pyTorrent/archive/refs/heads/main.tar.gz \ + bash +``` + +Common overrides: + +```bash +curl -fsSL https://raw.githubusercontent.com/zdzichu6969/pyTorrent/main/scripts/install_stack.sh \ + | sudo PYTORRENT_REPO_URL=https://github.com/zdzichu6969/pyTorrent \ + PYTORRENT_REPO_BRANCH=main \ + PYTORRENT_ARCHIVE_URL=https://github.com/zdzichu6969/pyTorrent/archive/refs/heads/main.tar.gz \ + PYTORRENT_PORT=8091 \ + RTORRENT_SCGI_PORT=5001 \ + PYTORRENT_PROFILE_NAME="Local rTorrent" \ + bash +``` + +## Installer variables + +### Bootstrap + +| Variable | Default | Description | +| --- | --- | --- | +| `PYTORRENT_REPO_URL` | repository URL | Repository base URL. | +| `PYTORRENT_REPO_BRANCH` | `master` | Branch used by the bootstrap installer. | +| `PYTORRENT_ARCHIVE_URL` | derived | Custom repository archive URL. Required for GitHub one-line install unless the script default is updated. | +| `PYTORRENT_BOOTSTRAP_DIR` | `/tmp/pytorrent-stack-installer` | Temporary bootstrap directory. | +| `PYTORRENT_KEEP_BOOTSTRAP_DIR` | `0` | Set to `1` to keep bootstrap files after install. | + +### rTorrent + +| Variable | Default | Description | +| --- | --- | --- | +| `RTORRENT_USER` | `rtorrent` | System user used to run rTorrent. | +| `RTORRENT_HOME` | `/home/${RTORRENT_USER}` | Home directory for the rTorrent user. | +| `RTORRENT_BASE_DIR` | `/opt/rtorrent_build` | Build/install directory for source installs. | +| `RTORRENT_SCGI_PORT` | `5000` | Local SCGI port. | +| `RTORRENT_TORRENT_PORT` | `51300` | Incoming BitTorrent port. | +| `RTORRENT_REF` | `v0.16.11` | rTorrent Git tag, branch or commit for source builds. | +| `LIBTORRENT_REF` | `v0.16.11` | libtorrent Git tag, branch or commit for source builds. | +| `RTORRENT_WITH_XMLRPC_C` | `0` | Set to `1` to build with classic xmlrpc-c. | +| `RTORRENT_BUILD_FROM_SOURCE` | distro-specific | On Arch, set to `1` to compile instead of using `pacman`. | +| `RTORRENT_FORCE_CONFIG` | `1` | Overwrite generated `.rtorrent.rc` when supported. | + +### pyTorrent + +| Variable | Default | Description | +| --- | --- | --- | +| `PYTORRENT_APP_DIR` | `/opt/pytorrent` | Installation directory. | +| `PYTORRENT_PORT` | `8090` | HTTP port. | +| `PYTORRENT_BASE_URL` | `http://127.0.0.1:${PYTORRENT_PORT}` | Base URL used by the API configurator. | +| `PYTORRENT_PROFILE_NAME` | `Local rTorrent` | rTorrent profile created in pyTorrent. | +| `PYTORRENT_API_TOKEN` | empty | Bearer token for authenticated API calls during setup. | +| `PYTORRENT_SERVICE_NAME` | `pytorrent` | systemd service name. | +| `PYTORRENT_RTORRENT_SCGI_URL` | `scgi://127.0.0.1:${RTORRENT_SCGI_PORT}` | SCGI URL saved in the generated profile. | ## Production run -Preferred mode without development Werkzeug: +Recommended production command: ```bash . venv/bin/activate -gunicorn --worker-class gthread --workers 1 --threads 32 --bind 0.0.0.0:8090 --access-logfile - --error-logfile - wsgi:app +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. +pyTorrent uses Flask-SocketIO with threading mode. Multiple Gunicorn workers are not a drop-in replacement unless a Socket.IO message queue such as Redis, RabbitMQ or Kafka is configured. -Alternatives reviewed but not enabled by default: +## systemd -- 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. +Useful service commands after stack installation: + +```bash +sudo systemctl status pytorrent +sudo systemctl status rtorrent@rtorrent.service +sudo journalctl -u pytorrent -f +sudo journalctl -u rtorrent@rtorrent.service -f +``` + +Application logs may also be available in: + +```text +data/logs/ +``` ## Reverse proxy -When pyTorrent is served behind a reverse proxy, enable proxy header handling only when the proxy is trusted: +Enable proxy header handling only when pyTorrent is behind a trusted proxy: ```env PYTORRENT_PROXY_FIX_ENABLE=true PYTORRENT_SESSION_COOKIE_SECURE=true ``` -The proxy should forward at least: +Forward these headers from the proxy: -```txt +```text 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`. +If pyTorrent is mounted under a sub-path, also forward: -## SCGI profile - -Example: - -```txt -scgi://127.0.0.1:5000/RPC2 +```text +X-Forwarded-Prefix ``` -On the rTorrent side: +For HTTPS deployments, set allowed origins explicitly: -```txt -network.scgi.open_port = 127.0.0.1:5000 +```env +PYTORRENT_SOCKETIO_CORS_ALLOWED_ORIGINS=https://pytorrent.example.com +PYTORRENT_API_ALLOWED_ORIGINS=https://pytorrent.example.com +``` + +## Authentication + +pyTorrent supports three authentication providers: + +| Provider | Description | +| --- | --- | +| `local` | Built-in pyTorrent login screen with username and password. | +| `tinyauth` | External authentication through Tinyauth and a trusted reverse proxy header. | +| `proxy` | Generic external authentication through a trusted reverse proxy header. | + +Enable authentication: + +```env +PYTORRENT_AUTH_ENABLE=true +PYTORRENT_AUTH_PROVIDER=local +``` + +Reset a local user's password: + +```bash +. venv/bin/activate +python -m pytorrent.cli reset-password admin new_password +``` + +Without the password argument, the command asks interactively: + +```bash +python -m pytorrent.cli reset-password admin +``` + +### API tokens + +When authentication is enabled, API requests can use a browser session cookie or a per-user API token. Admin users can generate tokens in: + +```text +Tools -> Users -> Generate token +``` + +Use the token as a bearer token or API key: + +```bash +curl -H "Authorization: Bearer pt_xxx" http://127.0.0.1:8090/api/system/status +curl -H "X-API-Key: pt_xxx" http://127.0.0.1:8090/api/system/status +``` + +Token permissions follow the owning user's role and profile permissions. Revoked tokens stop working immediately. + +### External auth through Tinyauth or proxy + +Example Tinyauth configuration: + +```env +PYTORRENT_AUTH_ENABLE=true +PYTORRENT_AUTH_PROVIDER=tinyauth +PYTORRENT_AUTH_PROXY_USER_HEADER=Remote-User +PYTORRENT_AUTH_PROXY_AUTO_CREATE=true +PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=admin +PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw +``` + +Example generic proxy configuration: + +```env +PYTORRENT_AUTH_ENABLE=true +PYTORRENT_AUTH_PROVIDER=proxy +PYTORRENT_AUTH_PROXY_USER_HEADER=X-Forwarded-User +PYTORRENT_AUTH_PROXY_AUTO_CREATE=true +PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=user +PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw +``` + +`rw` is accepted as an alias for `full`. Admin users can access all profiles. + +Do not use auth bypass on public hostnames. Limit bypass hosts to trusted private addresses only: + +```env +PYTORRENT_AUTH_BYPASS_HOSTS=10.11.1.11:8090,10.11.1.11 +PYTORRENT_AUTH_BYPASS_USER=admin ``` ## GeoIP -The installer downloads GeoLite2-City once to: +The installer can download the GeoLite2 City database to: -```txt +```text data/GeoLite2-City.mmdb ``` @@ -128,42 +329,155 @@ Manual download: ./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`. +Configure the database path: -## API docs +```env +PYTORRENT_GEOIP_DB=data/GeoLite2-City.mmdb +``` -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. +## OpenAPI -`/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. +OpenAPI documentation is available at: -## Admin CLI +```text +/docs +/api/openapi.json +``` -Reset an existing user's password: +The API includes profile management, torrent actions, preferences, port checks, system status, planner, poller, RSS, backups and diagnostics endpoints. + +## Configuration reference + +Common environment variables: + +```env +PYTORRENT_SECRET_KEY=change-me +PYTORRENT_DB_PATH=data/pytorrent.sqlite3 +PYTORRENT_HOST=0.0.0.0 +PYTORRENT_PORT=8090 +PYTORRENT_DEBUG=0 +PYTORRENT_POLL_INTERVAL=1 +PYTORRENT_WORKERS=16 +PYTORRENT_USE_OFFLINE_LIBS=true +PYTORRENT_LOG_ENABLE=false +PYTORRENT_LOG_DIR=data/logs +``` + +Retention settings: + +```env +PYTORRENT_TRAFFIC_HISTORY_RETENTION_DAYS=90 +PYTORRENT_JOBS_RETENTION_DAYS=30 +PYTORRENT_SMART_QUEUE_HISTORY_RETENTION_DAYS=30 +PYTORRENT_LOG_RETENTION_DAYS=30 +``` + +Database maintenance: + +```env +PYTORRENT_DB_VACUUM_ENABLE=true +PYTORRENT_DB_VACUUM_EVERY_SECONDS=86400 +PYTORRENT_DB_VACUUM_MIN_FREE_MB=512 +PYTORRENT_DB_VACUUM_MIN_FREE_RATIO=0.25 +``` + +See `.env.example` for the full list. + +## Troubleshooting + +### Service does not start + +```bash +sudo journalctl -u pytorrent -n 100 --no-pager +sudo systemctl status pytorrent +``` + +### rTorrent connection fails + +Check that rTorrent exposes SCGI locally and that the pyTorrent profile uses the same port: + +```text +scgi://127.0.0.1:5000/RPC2 +``` + +### External auth creates users without profiles + +Use admin auto-create mode: + +```env +PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=admin +``` + +Or grant read-write profile permissions to non-admin users: + +```env +PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=user +PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw +``` + +### Socket.IO badge stays offline behind reverse proxy + +Forward the same authenticated user header to all pyTorrent paths, including `/socket.io/`: + +```nginx +auth_request_set $auth_user $upstream_http_remote_user; +proxy_set_header Remote-User $auth_user; +``` + +### Build logs + +Source-build installers write logs to: + +```text +/var/log/pytorrent-installer +``` + +Enable verbose installer output: + +```bash +PYTORRENT_DEBUG_INSTALL=1 sudo bash scripts/install_stack.sh +``` + +## Security notes + +- Do not expose rTorrent SCGI directly to the public internet. +- Use HTTPS and authentication for remote access. +- Set a strong `PYTORRENT_SECRET_KEY` before production use. +- Review auth bypass settings before publishing or deploying. +- Keep `.env` out of Git. Use `.env.example` for public defaults. + +## Development ```bash . venv/bin/activate -python -m pytorrent.cli reset-password admin new_password +python app.py ``` -Without the password argument, the CLI asks for it interactively: +Run a quick Python compile check: ```bash -python -m pytorrent.cli reset-password admin +python -m compileall pytorrent app.py wsgi.py ``` -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: +Download offline frontend assets when needed: ```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 +python scripts/download_frontend_libs.py ``` -Token permissions follow the owning user's role and rTorrent profile permissions. Revoked tokens stop working immediately. +## Project structure + +```text +pytorrent/ Application package +pytorrent/routes/ Flask routes and API modules +pytorrent/services/ rTorrent, planner, queue and helper services +pytorrent/static/ Frontend JavaScript and CSS +pytorrent/templates/ HTML templates +scripts/ Installers and maintenance tools +systemd/ systemd service files +data/ Runtime data directory +``` + +## License + +AGPL-3 \ No newline at end of file diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 4ca7d63..0000000 --- a/TODO.md +++ /dev/null @@ -1,265 +0,0 @@ -# TODO - -## Done - -- Fixed remote system statistics after the rTorrent service split so CPU/RAM are read from the rTorrent host again. -- Fixed split system service dependencies for `default_download_path` and `list_torrents`, restoring disk/system status calls. -- Fixed split rTorrent package exports so private compatibility helpers, remote caches and post-check state remain visible after refactor. -- Restored remote directory browsing in the split rTorrent system service. -- Split the largest backend files into smaller route modules while keeping existing API behavior. -- Split rTorrent service logic into a package with focused modules and compatibility exports. -- Updated OpenAPI coverage for backend routes, including Planner and Poller endpoints. -- Split Planner and Adaptive Poller into separate Tools tabs. -- Added Download Planner settings: - - master enable switch, - - night-only downloads as a separate option, - - quiet hours, - - weekday and weekend speed limits, - - CPU protection, - - disk protection, - - auto-resume for planner-paused torrents. -- Added speed presets and Mbit/s sliders while keeping exact B/s fields for rTorrent values. -- Moved disk protection configuration out of Preferences and into Planner. -- Kept worker-side disk-start protection wired to Planner disk settings. -- Added footer Planner shortcut visible only when Planner is enabled. -- Added Adaptive Poller settings: - - active interval, - - idle interval, - - error interval, - - system stats interval, - - slow stats interval, - - heartbeat interval. -- Reduced unnecessary heartbeat emissions. -- Added tick duration tracking for the poller. -- Cleaned stale backup files from the package. -- Normalized Planner and Poller UX to match Smart Queue style. -- Cleaned Planner/Poller CSS and removed redundant UI wrappers. -- Kept the WebSocket live refresh responsive by moving slow poller tasks (torrent stats, Smart Queue, automations and Planner enforce) into a guarded background task. -- Added a regression smoke check for fixed-mode poller metrics while a slow background task is running. -- Set Adaptive Poller startup defaults to the requested fast-live profile: active/torrent loop 0.5s, idle 3s, errors 2s, system stats 1s, queue 5s, heartbeat 5s, slow threshold 10000ms and slowdown multiplier 1. -- Added poller runtime diagnostics for real tick gap, effective interval and configured minimum interval so 0.5s polling can be verified from the UI. - -## Planned - -### Phase 1 - Stabilization and maintainability - -- Split `static/app.js` into smaller frontend modules: - - `api.js`, - - `state.js`, - - `torrents.js`, - - `modals.js`, - - `smartQueue.js`, - - `planner.js`, - - `poller.js`, - - `rss.js`, - - `charts.js`. -- Add request validation for API endpoints instead of repeated manual `request.json` parsing. -- Add typed application exceptions: - - `RtorrentError`, - - `RtorrentTimeout`, - - `ProfileAccessError`, - - `ValidationError`, - - `UnsafePathError`, - - `BackgroundJobError`. -- Reduce broad `except Exception` blocks and map expected errors to clear API responses. -- Add structured logging with request ID, profile ID and operation timing. -- Add endpoint timing metrics for API calls and rTorrent operations. -- Add a deeper healthcheck endpoint covering: - - database readability/writability, - - active profile state, - - rTorrent connection, - - background queue state, - - poller state. - -### Phase 2 - Tests and safety - -- Add unit tests for torrent parsing. -- Add unit tests for Smart Queue decisions. -- Add unit tests for Planner schedule windows. -- Add unit tests for quiet hours. -- Add unit tests for Planner speed limit selection. -- Add unit tests for disk protection and CPU protection. -- Add unit tests for RSS rule matching. -- Add unit tests for ratio rules. -- Add unit tests for profile validation. -- Add auth and permission tests. -- Add path safety tests for move, remove and ZIP download operations. -- Add mocked rTorrent integration tests for Planner pause/resume and speed limit application. -- Add mocked poller tests for adaptive cadence without requiring a live rTorrent instance. -- Add visual regression checks for Tools tabs on narrow screens. -- Add CI checks for Python compile, JS syntax, linting and tests. - -### Phase 3 - Planner improvements - -- [x] Add named Planner profiles: - - night mode, - - weekend mode, - - low power mode, - - unlimited mode. -- [x] Keep Planner settings per active rTorrent profile. -- [x] Add Planner preview with the currently matched rule and next scheduled change. -- [x] Add Planner action history: - - paused torrents, - - resumed torrents, - - speed limit changes, - - CPU protection triggers, - - disk protection triggers. -- [x] Add dry-run mode for Planner actions. -- [x] Add optional network/load protection rules. -- [x] Add configurable grace period before auto-resume. -- [x] Add manual override timeout, including `disable Planner for 1 hour`. -- [x] Add clearer status badges in the footer and Tools panel. - -Implementation notes: -- Frontend settings live in the Planner tab and are stored through `/api/download-planner`. -- Preview/history are exposed through `/api/download-planner/preview`. -- Manual override is exposed through `/api/download-planner/override`. -- Dry-run mode records intended actions without calling rTorrent mutations. - -### Phase 4 - Adaptive poller improvements - -- [x] Make polling intervals configurable per rTorrent profile. -- [x] Add automatic slowdown when rTorrent responses are slow. -- [x] Add automatic recovery after repeated rTorrent errors. -- [x] Split polling loop configuration by data type: - - torrent list, - - system stats, - - tracker stats, - - disk stats, - - queue/job stats. -- [x] Emit WebSocket torrent updates only when data changed, with heartbeat fallback. -- [x] Add per-tick metrics: - - duration, - - emitted payload size, - - rTorrent call count, - - skipped emissions, - - current adaptive mode. -- [x] Add a Poller diagnostics panel. -- [x] Add safe fallback mode if adaptive polling is misconfigured. - -Implementation notes: -- Frontend settings live in the Poller tab and are stored through `/api/poller/settings`. -- Runtime metrics are included in heartbeat/system stats payloads and shown in Poller diagnostics. -- Fallback mode clamps unsafe intervals during normalization. - -### Phase 5 - UX and dashboard - -- [x] Add a torrent health dashboard with sections for: - - torrents without seeders, - - stopped torrents that should be active, - - tracker errors, - - duplicate torrents, - - slowest torrents, - - dead torrents, - - largest torrents, - - torrents below target ratio. -- [x] Add Smart Views: - - Needs attention, - - Large and slow, - - Seeding too long, - - New from RSS, - - No label, - - Private trackers. -- [x] Add global search across: - - torrent name, - - hash, - - label, - - tracker, - - path, - - ratio group, - - error status. -- [x] Add a persistent notification center for: - - rTorrent errors, - - RSS errors, - - automation errors, - - disk warnings, - - Smart Queue decisions, - - Planner actions, - - port status. -- [x] Add a Diagnostics page for profile, rTorrent, poller, database and worker state. - -Implementation notes: -- Health and Smart Views are calculated client-side from the live torrent snapshot. -- `Seeding too long` uses rTorrent completion timestamp when available and falls back safely when older rTorrent builds do not expose it. -- Global search uses torrent name, hash, label, tracker domain, path, ratio group and warning/error text. -- App Status now stays application-focused: process, workers, database and cleanup counters. -- Diagnostics owns profile, rTorrent connection, poller, planner, database and worker snapshots to avoid duplicated status cards. - -### Phase 6 - RSS and automation - -- Add RSS feed preview before saving a rule. -- Add RSS rule testing against the latest feed entries. -- Add RSS dry-run mode. -- Add duplicate detection by info-hash where possible. -- Add RSS rule priorities. -- Add RSS history explaining why an item was accepted or rejected. -- Add cleanup rules: - - remove completed torrents after target ratio, - - move completed data to a destination path, - - remove dead torrents after a configurable time, - - remove torrents with missing data, - - stop seeding after a configured upload amount. -- Add import/export for automation rules. - -### Phase 7 - File and torrent operations - -- Improve the Files view with extension filters. -- Add bulk priority actions by file type, for example `.mkv`, `.srt`, `.nfo`. -- Add folder-level priority actions by path pattern. -- Add safer selected-file download handling for large selections. -- Add missing-file detection. -- Add duplicate torrent detection and merge/cleanup suggestions. - -### Phase 8 - Profiles and rTorrent diagnostics - -- Add SCGI connection test before saving a profile. -- Add profile diagnostics: - - rTorrent version, - - base paths, - - write permissions, - - free disk space, - - response time. -- Add import/export for profiles. -- Show profile status in the profile picker: - - online, - - offline, - - slow, - - error. -- Add per-profile API and polling limits. - -### Phase 9 - Security and API - -- Require changing default admin credentials on first login when auth is enabled. -- Add login rate limiting. -- Add optional TOTP/2FA. -- Add stronger CSRF protection for state-changing requests. -- Set secure session flags when running behind HTTPS. -- Add API tokens: - - read-only token, - - full-access token, - - profile-limited token, - - token revocation, - - token usage log. -- Generate or validate OpenAPI schemas from backend request/response models. -- Add generated JS API client from OpenAPI. - -### Phase 10 - Database, backup and release quality - -- Add explicit database migrations with version numbers. -- Add `PRAGMA busy_timeout` configuration. -- Add periodic `VACUUM` or WAL checkpoint maintenance. -- Add indexes for history and frequently filtered data. -- Add retention limits for RSS history, automation history and Planner history. -- Add backup checksums. -- Add backup restore validation. -- Keep release archives free from `.bak`, cache and local debug files. - - -## Phase 5 implementation status - -- [x] Torrent health dashboard in Tools. -- [x] Smart Views filters, including completion-time based `Seeding too long`. -- [x] Global search expanded to hash, label, tracker, path, ratio group and error/status. -- [x] Persistent local notification center. -- [x] Diagnostics tool panel for profile, rTorrent, poller, database and workers. - diff --git a/auth.md b/auth.md deleted file mode 100644 index 9747be2..0000000 --- a/auth.md +++ /dev/null @@ -1,233 +0,0 @@ -# Authentication configuration - -## Overview - -pyTorrent supports three authentication modes: - -- `local` - built-in pyTorrent login screen with username and password. -- `tinyauth` - external authentication through Tinyauth and a trusted reverse proxy username header. -- `proxy` - generic external authentication through a trusted reverse proxy username header. - -When `tinyauth` or `proxy` is used, pyTorrent does not show the local login form. The reverse proxy must authenticate the request first and pass the authenticated username to pyTorrent in the configured header. - -## Environment variables - -```env -PYTORRENT_AUTH_ENABLE=true - -# local | tinyauth | proxy -PYTORRENT_AUTH_PROVIDER=tinyauth - -# Header that contains the authenticated username. -PYTORRENT_AUTH_PROXY_USER_HEADER=Remote-User - -# Create a local pyTorrent user when the external user is missing. -PYTORRENT_AUTH_PROXY_AUTO_CREATE=true - -# Role for auto-created external users: user | admin -PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=admin - -# Permission for auto-created role=user accounts: none | ro | rw | full -# rw is accepted as an alias of full. -# Admin users ignore this value and can access all profiles. -PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw - -# Optional: trusted direct-IP/local hosts that should skip pyTorrent auth. -# Use this only on private networks, never on public proxy hostnames. -PYTORRENT_AUTH_BYPASS_HOSTS=10.11.1.11:8090,10.11.1.11 - -# Existing active user used by bypassed requests. Defaults to admin. -PYTORRENT_AUTH_BYPASS_USER=admin -``` - - -## Reverse proxy origin checks - -pyTorrent blocks unsafe API requests when the browser `Origin`/`Referer` does not match the application origin. Behind HTTPS reverse proxy this requires either correct forwarded headers or an explicit API origin allowlist. - -Recommended variables for reverse proxy mode: - -```env -PYTORRENT_PROXY_FIX_ENABLE=true -PYTORRENT_SESSION_COOKIE_SECURE=true -PYTORRENT_SOCKETIO_CORS_ALLOWED_ORIGINS=https://pytorrent.example.com -PYTORRENT_API_ALLOWED_ORIGINS=https://pytorrent.example.com -``` - -`PYTORRENT_API_ALLOWED_ORIGINS` accepts a comma-separated list, for example: - -```env -PYTORRENT_API_ALLOWED_ORIGINS=https://pytorrent.example.com -``` - -If `PYTORRENT_API_ALLOWED_ORIGINS` is not set, pyTorrent reuses `PYTORRENT_SOCKETIO_CORS_ALLOWED_ORIGINS` for API origin checks. - -## Local authentication - -Use this when pyTorrent should manage its own login screen and passwords. - -```env -PYTORRENT_AUTH_ENABLE=true -PYTORRENT_AUTH_PROVIDER=local -``` - -Password reset example: - -```bash -python -m pytorrent.cli reset-password admin new_Pass -``` - -## Tinyauth authentication - -Use this when Tinyauth protects pyTorrent before the request reaches the application. - -```env -PYTORRENT_AUTH_ENABLE=true -PYTORRENT_AUTH_PROVIDER=tinyauth -PYTORRENT_AUTH_PROXY_USER_HEADER=Remote-User -PYTORRENT_AUTH_PROXY_AUTO_CREATE=true -PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=admin -PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw -``` - -Behavior: - -- Tinyauth authenticates the browser request. -- The reverse proxy forwards the authenticated username in `Remote-User`. -- pyTorrent reads only that username header. -- If the username already exists in pyTorrent, that user is used. -- If the username does not exist and `PYTORRENT_AUTH_PROXY_AUTO_CREATE=true`, pyTorrent creates it. -- Passwordless external users are synchronized with `PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE` and `PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION` on login. - -## Example Nginx / Nginx Proxy Manager advanced vhost - -```nginx -location / { - proxy_pass $forward_scheme://$server:$port; - auth_request /tinyauth; - error_page 401 = @tinyauth_login; - - auth_request_set $redirection_url $upstream_http_x_tinyauth_location; - auth_request_set $auth_user $upstream_http_remote_user; - proxy_set_header Remote-User $auth_user; - -} - -location /tinyauth { - proxy_pass http://10.11.1.11:3000/api/auth/nginx; - proxy_set_header x-forwarded-proto $scheme; - proxy_set_header x-forwarded-host $http_host; - proxy_set_header x-forwarded-uri $request_uri; -} - -location @tinyauth_login { - return 302 http://auth.example.com/login?redirect_uri=$scheme://$http_host$request_uri; -} -``` - -Use `PYTORRENT_AUTH_PROXY_USER_HEADER=Remote-User` when this setup forwards `Remote-User` to pyTorrent. - -## Direct-IP auth bypass - -Use this only when pyTorrent is reachable on a trusted private IP and you want: - -- reverse proxy hostname protected by Tinyauth; -- direct private IP access without pyTorrent login. - -Example: - -```env -PYTORRENT_AUTH_ENABLE=true -PYTORRENT_AUTH_PROVIDER=tinyauth -PYTORRENT_AUTH_BYPASS_HOSTS=10.11.1.11:8090,10.11.1.11 - -# Existing active user used by bypassed requests. Defaults to admin. -PYTORRENT_AUTH_BYPASS_USER=admin -``` - -Behavior: - -- requests with `Host: 10.11.1.11:8090` or `Host: 10.11.1.11` use the built-in default admin user; -- requests through the reverse proxy still require the configured auth provider; -- `PYTORRENT_AUTH_BYPASS_USER` must point to an existing active user; when unset, pyTorrent uses `admin`; -- if the bypass user is `admin`, profile permissions are ignored because admins can access all profiles; -- when no active profile is saved for the bypass user, pyTorrent opens the profile picker instead of silently selecting the first profile; -- after selecting a profile, the choice is saved in the bypass user's preferences and reused on the next direct-IP visit. - -Do not add public domains to this list. - -## Generic reverse proxy authentication - -Use this when another proxy authenticates users and sends a username header. - -```env -PYTORRENT_AUTH_ENABLE=true -PYTORRENT_AUTH_PROVIDER=proxy -PYTORRENT_AUTH_PROXY_USER_HEADER=X-Forwarded-User -PYTORRENT_AUTH_PROXY_AUTO_CREATE=true -PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=user -PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw -``` - -## Auto-created user permissions - -`PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=admin`: - -- user is created as admin; -- profile permissions are not needed; -- all profiles are visible and writable. - -`PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=user`: - -- `none` - creates the user without profile access; -- `ro` - grants read-only access to all profiles; -- `rw` - grants read-write access to all profiles; -- `full` - same as `rw`. - -## Connection badge behind Tinyauth - -The top-right badge shows Socket.IO connectivity, not REST API health. - -If the application loads data through REST API but the badge stays `offline`, the most common cause is that the Socket.IO handshake or follow-up events are not authenticated with the same external identity header. pyTorrent resolves external auth during Socket.IO connect/events as well as normal REST requests. - -For Tinyauth, make sure the same location that proxies pyTorrent also forwards `Remote-User` to all paths, including `/socket.io/`: - -```nginx -auth_request_set $auth_user $upstream_http_remote_user; -proxy_set_header Remote-User $auth_user; -``` - -No separate badge-disable option is needed. The badge should become `online` when Socket.IO connects correctly. - -## Troubleshooting - -If the user is created but profiles are missing: - -1. Check the created user's role in pyTorrent user management. -2. For admin access, use: - -```env -PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=admin -``` - -3. For non-admin read-write access, use: - -```env -PYTORRENT_AUTH_PROXY_AUTO_CREATE_ROLE=user -PYTORRENT_AUTH_PROXY_AUTO_CREATE_PERMISSION=rw -``` - -4. Delete the wrongly auto-created external user or log in again. Passwordless external users are synchronized on login by the current config. - -If login fails completely, verify that the configured header reaches pyTorrent: - -```env -PYTORRENT_AUTH_PROXY_USER_HEADER=Remote-User -``` - -The configured header must contain a non-empty username. -## External provider logout - -When `PYTORRENT_AUTH_PROVIDER=tinyauth` or `PYTORRENT_AUTH_PROVIDER=proxy` is used, pyTorrent does not render an active logout action. The authenticated session is owned by the upstream provider, so logging out must be handled by that provider, for example through the Tinyauth logout endpoint or its own UI. - -The `/logout` route becomes a safe no-op redirect to the main page for external auth providers. Local authentication keeps the original pyTorrent logout behavior. diff --git a/docs/ss1.png b/docs/ss1.png new file mode 100644 index 0000000..acf5394 Binary files /dev/null and b/docs/ss1.png differ diff --git a/pytorrent/templates/index.html b/pytorrent/templates/index.html index 2f188fc..7d0cca4 100644 --- a/pytorrent/templates/index.html +++ b/pytorrent/templates/index.html @@ -355,17 +355,17 @@
pyTorrent
-

Lightweight web panel for rTorrent management, queue control and live torrent diagnostics.

+

Web panel for rTorrent management, queue control and more!

Repository
git.linuxiarz.pl/gru/pyTorrent
-
License
Open source
-
Author
linuxiarz.pl
+
License
AGPL-3.0
+
Author
Mateusz GruszczyƄski aka zdzichu6969 (www.linuxiarz.pl)
Backend
Python, Flask, Flask-SocketIO, SQLite
-
Frontend
Bootstrap, vanilla JavaScript, Chart.js, Font Awesome
+
Frontend
Bootstrap, JavaScript, Chart.js, Font Awesome
Runtime
Gunicorn, systemd, rTorrent over SCGI
-
Features
Magnet and torrent upload, file priorities, labels, ratio groups, Smart Queue, automation rules, RSS, traffic charts, port checker, system status.
+
Features
Magnet and torrent upload, file priorities, labels, ratio groups, Smart Queue, automation rules, RSS, traffic charts, port checker, system status and more