Transmission Manager

A lightweight, modern, single-binary web application for viewing and managing torrents from a [Transmission](https://transmissionbt.com/) RPC daemon. Transmission Manager serves a fast, clean, dark-mode Single Page Application (SPA) and proxies Transmission RPC calls through a minimal Go backend—all contained within a single executable. --- ## Features - **Single Static Binary**: All frontend assets (`index.html`, `app.js`, `styles.css`) are embedded directly into the Go binary using `embed`. Zero runtime asset dependencies. - **Modern Dark-Mode UI**: Built with vanilla HTML5, CSS3 (using CSS variables), and JavaScript. Responsive, compact layout designed for both desktop and mobile screens. - **Live Polling & In-Place Updates**: Keyed DOM reconciliation updates existing torrent cards in place without screen flickering or scroll jumping. Selectable refresh interval (1s, 3s, 5s, 10s). - **Rich Sorting & Filtering**: - Filter torrents instantly by name. - Sort by **Status**, **Name**, **Progress**, **Ratio**, **Size**, **Speed**, or **Availability**. - **Interactive Controls**: Pause or resume individual torrents directly from the web interface. - **Smart Seed Scheduler**: Opt completed torrents in from the Scheduler tab, choose 1–100 managed seed slots, and rotate an idle slot to the least recently seeded waiting torrent after one hour without upload. A persistent cycle history shows activations and rotations. - **Robust Transmission RPC Support**: - Automatically handles Transmission `409 Conflict` session ID (`X-Transmission-Session-Id`) handshakes. - Supports optional HTTP Basic Authentication. --- ## Configuration Transmission Manager is configured entirely via environment variables: | Variable | Required | Description | | :--- | :---: | :--- | | `TRANSMISSION_URL` | **Yes** | Absolute HTTP or HTTPS RPC endpoint URL of your Transmission instance. | | `TRANSMISSION_RPC_USERNAME` | No | Basic Authentication username for Transmission RPC. | | `TRANSMISSION_RPC_PASSWORD` | No | Basic Authentication password for Transmission RPC. | | `SCHEDULER_DB_PATH` | No | SQLite database path (default `./data/scheduler.db`). | The scheduler runs in the server even when no browser is open. It manages only opted-in torrents. A scheduled torrent that continues uploading can keep its slot indefinitely, so rotation does not guarantee a fixed maximum waiting time. Manual pause or resume of an opted-in torrent is temporary; the scheduler restores its chosen state on its next check. --- ## Quick Start ### Using Docker Run the container directly: ```bash docker run -d \ --name transmission-manager \ -p 8080:8080 \ -v transmission-manager-data:/app/data \ -e TRANSMISSION_URL=http://192.168.1.100:9091/transmission/rpc \ -e TRANSMISSION_RPC_USERNAME=admin \ -e TRANSMISSION_RPC_PASSWORD=secret \ transmission-manager:latest ``` ### Using Docker Compose Create a `docker-compose.yml`: ```yaml services: transmission-manager: build: . container_name: transmission-manager ports: - "8080:8080" volumes: - transmission-manager-data:/app/data environment: TRANSMISSION_URL: http://192.168.1.100:9091/transmission/rpc TRANSMISSION_RPC_USERNAME: admin TRANSMISSION_RPC_PASSWORD: secret restart: unless-stopped volumes: transmission-manager-data: ``` Then start the application: ```bash docker compose up -d ``` Open your browser and navigate to `http://localhost:8080`. --- ## Building from Source ### Prerequisites - [Go](https://go.dev/) 1.24 or later ### Build Compile the single binary with embedded frontend assets: ```bash git clone https://github.com/your-repo/transmission-manager.git cd transmission-manager go build -ldflags="-s -w" -o transmission-manager . ``` ### Run ```bash export TRANSMISSION_URL="http://localhost:9091/transmission/rpc" ./transmission-manager ``` By default, the server listens on port `8080`. Keep the `data` directory (or the path set by `SCHEDULER_DB_PATH`) across restarts to preserve scheduler settings, opt-ins, and cycle history. The app creates the database directory on startup and exits with a clear error if it cannot open the database.