adding scheduler
Build and Deploy (internal) / Build Transmission Manager Image (push) Successful in 3m13s
Build and Deploy (internal) / Deploy Transmission Manager (internal) (push) Successful in 3s

This commit is contained in:
2026-09-23 17:32:39 -03:00
parent 44889338c2
commit c98af34202
12 changed files with 1430 additions and 8 deletions
+15 -5
View File
@@ -6,22 +6,24 @@ This file is the canonical project context for AI agents working on Transmission
Transmission Manager is a lightweight local/LAN web app for viewing and managing torrents from a Transmission RPC daemon. The product goal is a fast, clean, dark-mode SPA that feels modern while remaining simple to build, deploy, and inspect.
The app is intentionally small: one Go binary serves both the API and embedded frontend assets. The frontend is vanilla JavaScript, HTML, and CSS, with no package manager, no compile step, and no JS framework.
The app is intentionally small: one Go binary serves both the API and embedded frontend assets. The frontend is vanilla JavaScript, HTML, and CSS, with no package manager, no compile step, and no JS framework. A server-side scheduler rotates opted-in completed torrents through a limited number of seed slots and records cycle history.
## Technology Stack
- Go module: `transmission-manager`
- Go version: `1.24`
- Backend dependencies: standard library only
- Backend dependencies: standard library plus the approved pure-Go `modernc.org/sqlite` driver for scheduler persistence
- Frontend dependencies: none
- Static assets: embedded with Go `embed`
- Runtime port: `8080`
- Docker build: `golang:1.24-alpine` builder, `alpine:latest` runtime
- Runtime RPC configuration: `TRANSMISSION_URL`, `TRANSMISSION_RPC_USERNAME`, and `TRANSMISSION_RPC_PASSWORD`
- Scheduler database: `SCHEDULER_DB_PATH` (default `./data/scheduler.db`); mount `/app/data` in Docker for persistence
## Repository Organization
- `main.go`: backend entrypoint. Owns the HTTP server, embedded static file serving, environment-driven Transmission RPC client configuration, session-ID handshake, connection warning page, JSON helpers, and API routes.
- `scheduler.go`: SQLite persistence, background scheduling loop, Transmission seed-slot reconciliation, and scheduler API routes.
- `web/index.html`: SPA shell. Defines the header, stats pills, alternative-speed controls, filter input, sort buttons, list container, empty state, error state, footer, and script/style links.
- `web/icon.svg`: editable vector source for the app icon.
- `web/icon.png`: reusable raster app icon used by the SPA header and browser tab.
@@ -42,6 +44,10 @@ The backend uses `net/http` with a single `http.ServeMux`. It exposes:
- `POST /api/session/alternative-speed`: validates an `{"enabled": boolean}` body and sends Transmission `session-set` to toggle alternative speeds.
- `POST /api/torrents/{id}/pause`: validates a positive numeric torrent id and sends `torrent-stop`.
- `POST /api/torrents/{id}/resume`: validates a positive numeric torrent id and sends queue-respecting `torrent-start`.
- `GET /api/scheduler`: returns slot settings, completed torrent opt-ins, active/waiting states, and scheduler errors.
- `POST /api/scheduler/settings`: accepts `{"maxActive": 1..100}`.
- `POST /api/scheduler/torrents/{hash}/opt-in`: accepts `{"enabled": boolean}`; enabling requires a complete, error-free torrent.
- `GET /api/scheduler/history?before=<id>`: returns up to 50 cycle events and a `hasMore` flag.
- `/`: checks the Transmission connection and serves a warning page with the connection error when setup fails; otherwise serves embedded files from `web/`.
Transmission RPC calls must reuse the existing `Client.rpc` path so session-ID handling is consistent. The session ID is cached in `Client.sessionID` and guarded by `sync.Mutex`.
@@ -57,7 +63,7 @@ Transmission usually rejects the first request or an expired session with HTTP `
Torrent list requests should include:
```text
id, name, totalSize, downloadedEver, uploadedEver, uploadRatio,
id, hashString, name, totalSize, downloadedEver, uploadedEver, uploadRatio,
percentDone, status, eta, error, errorString, doneDate, isFinished,
rateDownload, rateUpload, peersConnected, peersGettingFromUs, peersSendingToUs,
availability, peers
@@ -71,9 +77,13 @@ The UI availability value comes from Transmission's `availability` per-piece arr
Alternative-speed controls use the effective profile: alternative caps when `alt-speed-enabled` is true, otherwise enabled normal caps. Positive caps are displayed in the header; zero or negative values are treated as unrestricted.
The scheduler uses torrent hashes because Transmission numeric IDs can change after a daemon restart. It makes a lightweight `torrent-get` request for `hashString`, `name`, `percentDone`, `status`, `uploadedEver`, and `error`. It uses `torrent-start-now` for managed slots and `torrent-stop` for rotation; ordinary manual Resume keeps using `torrent-start`. Only opted-in, complete, error-free torrents are eligible. Manual actions on opted-in torrents are temporary; the next scheduler check restores the selected slot allocation.
The scheduler checks every 30 seconds independently of the browser. It defaults to one slot, allows 1–100, and only limits opted-in torrents. Each active slot tracks the last increase in `uploadedEver`; one hour without an increase makes it eligible to rotate to the least recently seeded waiting torrent. With no waiting torrent, the active one stays. A continuously uploading torrent may retain its slot indefinitely. SQLite retains settings, opt-ins, slot timestamps, and all cycle events across restarts; history is paged 50 events at a time.
## Frontend Architecture
The frontend is a single page with module-level state in `web/app.js`. It polls on a user-selectable interval, defaults to 3 seconds, and fetches torrents, stats, and session settings in parallel.
The frontend is a single page with module-level state in `web/app.js`. It polls on a user-selectable interval, defaults to 3 seconds, and fetches torrents, stats, and session settings in parallel. The Torrents and Scheduler views are accessible tabs. The Scheduler view fetches its state every 10 seconds while visible and loads history when it changes.
Important patterns:
@@ -106,7 +116,7 @@ Current sort keys:
## Implementation Rules
- Do not add external Go dependencies.
- Do not add external Go dependencies beyond the approved pure-Go SQLite driver.
- Do not add frontend dependencies, bundlers, or transpilation.
- Do not add auth unless explicitly requested.
- Do not add CI/CD, GitHub Actions, or repository setup.