fixing small things
Some checks failed
Build and Deploy (internal) / Build Transmission Manager Image (push) Failing after 9s
Build and Deploy (internal) / Deploy Transmission Manager (internal) (push) Has been skipped

This commit is contained in:
2026-07-08 20:34:38 -03:00
parent 052885b05e
commit 84cd6431d5
5 changed files with 115 additions and 38 deletions

View File

@@ -7,7 +7,9 @@ on:
workflow_dispatch: {} workflow_dispatch: {}
env: env:
IMAGE: git.ivanch.me/ivanch/transmission-manager APP: transmission-manager
IMAGE: git.ivanch.me/ivanch/${{ APP }}:latest
NAMESPACE: media
jobs: jobs:
build_transmission_manager: build_transmission_manager:
@@ -33,5 +35,5 @@ jobs:
uses: https://git.ivanch.me/ivanch/pipeline-actions/deploy-restart@main uses: https://git.ivanch.me/ivanch/pipeline-actions/deploy-restart@main
with: with:
kube_config: ${{ secrets.KUBE_CONFIG }} kube_config: ${{ secrets.KUBE_CONFIG }}
deployment_name: transmission-manager deployment_name: ${{ env.APP }}
namespace: media namespace: ${{ env.NAMESPACE }}

View File

@@ -6,29 +6,6 @@ Always read `project-context.md` before making code or documentation changes. If
## Quick Summary ## Quick Summary
Transmission Manager is a lightweight single-binary Go web app for managing and viewing torrents in a Transmission RPC client. It serves a dark-mode vanilla HTML/CSS/JS SPA and proxies Transmission RPC calls through a minimal Go backend. Transmission Manager is a lightweight single-binary Go web app for managing and viewing torrents in a Transmission RPC client. It serves a dark-mode vanilla HTML/CSS/JS SPA and proxies Transmission RPC calls through a minimal Go backend.
## Stack
- Backend: Go 1.24, standard library only.
- Frontend: Vanilla HTML, CSS, and JavaScript. No framework or build step.
- Static assets: embedded with Go `embed` from `web/`.
- Runtime port: `8080`.
- Container: multi-stage Docker build from `golang:1.24-alpine` to `alpine:latest`.
## Current Files
- `project-context.md` - canonical project context and implementation rules for agents.
- `main.go` - HTTP server, embedded static file serving, environment-driven Transmission RPC client, connection warning page, API routes.
- `web/index.html` - SPA shell and toolbar controls.
- `web/app.js` - frontend state, polling, in-place rendering, sorting, pause/resume actions.
- `web/styles.css` - dark-only UI theme and responsive layout.
- `go.mod` - module `transmission-manager`, Go 1.24.
- `Dockerfile` - production container build.
## Core API Surface
- `GET /` serves a Transmission connection warning page when setup fails; otherwise it serves the embedded frontend.
- `GET /api/torrents` returns Transmission torrent data.
- `GET /api/stats` returns global session stats.
- `POST /api/torrents/{id}/pause` maps to Transmission `torrent-stop`.
- `POST /api/torrents/{id}/resume` maps to queue-respecting Transmission `torrent-start`.
## Implementation Guidelines ## Implementation Guidelines
- Keep the backend stdlib-only. Do not add Gin, Fiber, Chi, Gorilla, or other Go web frameworks. - Keep the backend stdlib-only. Do not add Gin, Fiber, Chi, Gorilla, or other Go web frameworks.
- Keep the frontend dependency-free. Do not add React, Vue, Svelte, bundlers, package managers, or transpilers. - Keep the frontend dependency-free. Do not add React, Vue, Svelte, bundlers, package managers, or transpilers.
@@ -39,8 +16,7 @@ Transmission Manager is a lightweight single-binary Go web app for managing and
- Keep UI dark-only, modern, compact, responsive, and based on CSS variables. - Keep UI dark-only, modern, compact, responsive, and based on CSS variables.
## Transmission RPC Notes ## Transmission RPC Notes
- Default RPC URL: `http://192.168.20.22:3210/transmission/rpc`. - RPC URL read from `TRANSMISSION_URL` (must be set).
- Override the RPC URL with `TRANSMISSION_URL`.
- Optional HTTP Basic Auth credentials come from `TRANSMISSION_RPC_USERNAME` and `TRANSMISSION_RPC_PASSWORD`; unset, empty, or literal `null` values mean no credential value. - Optional HTTP Basic Auth credentials come from `TRANSMISSION_RPC_USERNAME` and `TRANSMISSION_RPC_PASSWORD`; unset, empty, or literal `null` values mean no credential value.
- Handle the Transmission session-ID handshake: - Handle the Transmission session-ID handshake:
1. POST to the RPC URL. 1. POST to the RPC URL.

103
README.md Normal file
View File

@@ -0,0 +1,103 @@
# 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.
- **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. |
---
## Quick Start
### Using Docker
Run the container directly:
```bash
docker run -d \
--name transmission-manager \
-p 8080:8080 \
-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"
environment:
TRANSMISSION_URL: http://192.168.1.100:9091/transmission/rpc
TRANSMISSION_RPC_USERNAME: admin
TRANSMISSION_RPC_PASSWORD: secret
restart: unless-stopped
```
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`.

10
main.go
View File

@@ -23,7 +23,6 @@ import (
var webFS embed.FS var webFS embed.FS
const ( const (
defaultRPCURL = "http://192.168.20.22:3210/transmission/rpc"
envTransmissionURL = "TRANSMISSION_URL" envTransmissionURL = "TRANSMISSION_URL"
envTransmissionRPCUsername = "TRANSMISSION_RPC_USERNAME" envTransmissionRPCUsername = "TRANSMISSION_RPC_USERNAME"
envTransmissionRPCPassword = "TRANSMISSION_RPC_PASSWORD" envTransmissionRPCPassword = "TRANSMISSION_RPC_PASSWORD"
@@ -62,11 +61,7 @@ func NewClientFromEnv() (*Client, error) {
} }
func configuredRPCURL() string { func configuredRPCURL() string {
rpcURL := strings.TrimSpace(os.Getenv(envTransmissionURL)) return strings.TrimSpace(os.Getenv(envTransmissionURL))
if rpcURL == "" {
return defaultRPCURL
}
return rpcURL
} }
func optionalEnv(name string) string { func optionalEnv(name string) string {
@@ -78,6 +73,9 @@ func optionalEnv(name string) string {
} }
func validateRPCURL(raw string) error { func validateRPCURL(raw string) error {
if raw == "" {
return fmt.Errorf("%s environment variable must be set", envTransmissionURL)
}
parsed, err := url.Parse(raw) parsed, err := url.Parse(raw)
if err != nil { if err != nil {
return fmt.Errorf("%s is invalid: %w", envTransmissionURL, err) return fmt.Errorf("%s is invalid: %w", envTransmissionURL, err)

View File

@@ -17,7 +17,6 @@ The app is intentionally small: one Go binary serves both the API and embedded f
- Static assets: embedded with Go `embed` - Static assets: embedded with Go `embed`
- Runtime port: `8080` - Runtime port: `8080`
- Docker build: `golang:1.24-alpine` builder, `alpine:latest` runtime - Docker build: `golang:1.24-alpine` builder, `alpine:latest` runtime
- Default Transmission RPC target: `http://192.168.20.22:3210/transmission/rpc`
- Runtime RPC configuration: `TRANSMISSION_URL`, `TRANSMISSION_RPC_USERNAME`, and `TRANSMISSION_RPC_PASSWORD` - Runtime RPC configuration: `TRANSMISSION_URL`, `TRANSMISSION_RPC_USERNAME`, and `TRANSMISSION_RPC_PASSWORD`
## Repository Organization ## Repository Organization
@@ -28,6 +27,7 @@ The app is intentionally small: one Go binary serves both the API and embedded f
- `web/styles.css`: all styling. Owns dark theme variables, layout, cards, badges, progress bars, action buttons, empty/error states, and responsive rules. - `web/styles.css`: all styling. Owns dark theme variables, layout, cards, badges, progress bars, action buttons, empty/error states, and responsive rules.
- `go.mod`: Go module declaration. - `go.mod`: Go module declaration.
- `Dockerfile`: multi-stage production build. - `Dockerfile`: multi-stage production build.
- `README.md`: public project documentation, configuration guide, and deployment instructions.
- `AGENTS.md`: quick-start guide for coding agents. It must point agents back to this file. - `AGENTS.md`: quick-start guide for coding agents. It must point agents back to this file.
## Backend Architecture ## Backend Architecture
@@ -46,7 +46,7 @@ API errors return JSON with an `error` string. Invalid torrent action methods sh
## Transmission RPC Model ## Transmission RPC Model
The RPC endpoint defaults to `http://192.168.20.22:3210/transmission/rpc` and can be overridden with `TRANSMISSION_URL`. `TRANSMISSION_RPC_USERNAME` and `TRANSMISSION_RPC_PASSWORD` are optional; unset, empty, or literal `null` values mean no credential value. When either credential has a value, the backend sends HTTP Basic Auth on RPC requests. The RPC endpoint is configured via `TRANSMISSION_URL` (which must be set). `TRANSMISSION_RPC_USERNAME` and `TRANSMISSION_RPC_PASSWORD` are optional; unset, empty, or literal `null` values mean no credential value. When either credential has a value, the backend sends HTTP Basic Auth on RPC requests.
Transmission usually rejects the first request or an expired session with HTTP `409` and a fresh `X-Transmission-Session-Id` header. Correct behavior is to drain and close the response body, cache the new session ID, and retry the same JSON request once. Transmission usually rejects the first request or an expired session with HTTP `409` and a fresh `X-Transmission-Session-Id` header. Correct behavior is to drain and close the response body, cache the new session ID, and retry the same JSON request once.
@@ -122,5 +122,3 @@ node --check web\app.js
git diff --check git diff --check
docker build . docker build .
``` ```
Known local environment note from July 8, 2026: `go` and `gofmt` were not available in PATH, and Docker was configured to a remote builder with an SSH host-key mismatch. If that remains true, report the limitation instead of changing SSH trust settings automatically.