Commit graph

19 commits

Author SHA1 Message Date
Deivid Soto
3e0f3a5a64 feat(cli): upgrade command, rich status, and version cache
Some checks failed
Release / release (push) Failing after 0s
Release / docker (push) Has been skipped
Release / virustotal (push) Failing after 0s
- Replace `upgrade` stub with real command (alias for `self-update`)
- Also register `update` as alias: `unarr update` works too
- Rewrite `status` to show full config, disk usage, daemon state, and
  update availability with colored sections
- Add version check cache (1h TTL) so `status` is instant on repeat runs
- Guard against division by zero on empty filesystems
- Guard against negative durations from clock skew
- Guard against stale PID via heartbeat recency check (2 min)
- Add comprehensive test coverage across agent, engine, upgrade, usenet,
  arr, library, mediaserver, and UI packages
- Improve Makefile coverage target to exclude cmd/ glue code
- Fix stream handler resource cleanup and ffprobe error handling
2026-03-31 22:05:43 +02:00
Deivid Soto
01d62ffa13 fix(progress): always report status transitions and poll for control signals 2026-03-31 16:55:50 +02:00
Deivid Soto
aed5f0475d fix(lint): use default:none to disable errcheck, fix all gofmt and exhaustive 2026-03-31 00:29:16 +02:00
Deivid Soto
be6eef1195 fix(lint): configure linters for codebase maturity, fix gofmt and ineffassign 2026-03-31 00:17:19 +02:00
Deivid Soto
efa4562acd refactor: migrate lint config to v2, remove daemon auto-upgrade, add trust badges
Some checks failed
Release / release (push) Failing after 1s
Release / docker (push) Has been skipped
Release / virustotal (push) Failing after 0s
2026-03-30 23:24:16 +02:00
Deivid Soto
5a7449b9e6 chore: rename module from torrentclaw-cli to unarr
- Rename Go module path github.com/torrentclaw/torrentclaw-cli → github.com/torrentclaw/unarr
- Update all imports, ldflags, scripts, docs, and Docker config
- Add GitHub Actions release workflow (goreleaser on tag push)
2026-03-30 13:06:07 +02:00
Deivid Soto
61b44fe86f feat(stream): UPnP port forwarding for remote video playback
Some checks failed
Release / GoReleaser (push) Failing after 1s
- Add UPnP discovery and automatic port mapping (like Plex Remote Access)
- Stream server binds to 0.0.0.0 and reports public IP via UPnP
- Fallback chain: UPnP public IP → Tailscale IP → LAN IP
- Clean up port mapping on shutdown
- Bump version to 0.3.0-dev
2026-03-29 23:55:10 +02:00
Deivid Soto
3badde606e fix: add panic recovery to auto-scan, cap DHT nodes at 200 2026-03-29 20:32:08 +02:00
Deivid Soto
c476bd865c feat(daemon): add auto-scan, force start, and stall timeout default
- Auto-scan: daemon scans library daily (configurable via config.toml)
  [library] auto_scan = true, scan_interval = "24h"
- Force start: tasks with forceStart=true bypass concurrency semaphore
  (like Transmission's Force Start — opens temporary extra slot)
- Stall timeout default: 30m instead of unlimited, prevents dead torrents
  from permanently blocking download slots
- ForceStart field in agent.Task for CLI/server communication
2026-03-29 20:22:15 +02:00
Deivid Soto
386c97f84a fix(torrent): expand tracker list, add DHT persistence and configurable timeouts
- Expand default trackers from 5 to 31 (synced with web tracker-list.ts)
- Add DHT node persistence between sessions (~/.local/share/unarr/dht-nodes.txt)
  Saves known nodes on shutdown, restores on startup for warm DHT bootstrap
- Make metadata_timeout and stall_timeout configurable in config.toml
  Default: 0 (unlimited, like qBittorrent) — users can set custom values
- Fix CleanTitle to handle web domains and format patterns (e.g. pctfenix.com)
2026-03-29 19:09:51 +02:00
Deivid Soto
677a8fe083 feat: add migrate command, media server detection, and debrid auto-config
- Migration wizard from Sonarr/Radarr/Prowlarr (unarr migrate) [pre-beta]
  - Auto-detect instances via Docker, config files, port scan, Prowlarr
  - Import wanted list (monitored+missing movies/series)
  - Import download history and blocklist to avoid re-downloading
  - Extract debrid tokens from *arr download clients
  - Quality profile mapping to preferred_quality config
  - DISTINCT ON PostgreSQL query for optimal torrent selection
  - JSON export with --dry-run --json (text to stderr, JSON to stdout)
- Media server detection (Plex/Jellyfin/Emby) in unarr init
  - Detects library paths and offers them as download directory options
- Debrid auto-configuration in unarr init
  - Scans *arr instances for debrid tokens
  - Validates and saves via API if user confirms
- New preferred_quality setting in config (2160p/1080p/720p)
- Library scan command (unarr scan) with ffprobe metadata extraction
2026-03-29 16:54:32 +02:00
Deivid Soto
0b6c6849b1 feat: replace setup with init wizard + interactive config menu
- `unarr init` (alias: `unarr setup`): streamlined 3-step wizard
  (API key, download dir, daemon install). Removed method/name prompts
  — auto-configured from defaults.
- `unarr config [category]`: interactive menu with 7 categories
  (downloads, organization, notifications, device, region, connection,
  advanced). Direct access via `unarr config downloads`, etc.
- Extract shared helpers (openBrowser, expandHome, isTerminal) to
  helpers.go. Delete old setup.go and config.go.
- Update all "unarr setup" references to "unarr init" across daemon,
  doctor, status, README, install scripts.
2026-03-29 12:09:03 +02:00
Deivid Soto
6e07e82d51 fix: harden usenet/debrid downloaders from critico review
- Consolidate 3 maps (active, taskDirs, taskTrackers) into single
  activeDownload struct — eliminates out-of-sync state on mid-function panic
- Cancel() runs os.RemoveAll in background goroutine (non-blocking)
- Flush(): clear dirty before unlock to prevent concurrent flush race on
  same tmp file; remove fragile re-mark-on-error pattern
- Revert RWMutex → Mutex in ProgressTracker (negligible benefit under
  write-heavy workload, higher overhead)
- Remove file.Sync() from debrid and usenet downloaders (Close flushes
  kernel buffers; fsync blocks for seconds on large files)
- Pin golangci-lint to v2.1.6 in CI (was floating with `latest`)
- Fix CI matrix: Go 1.25+1.26 (was 1.24+1.25, but go.mod requires 1.25)
2026-03-28 22:11:04 +01:00
Deivid Soto
c9bcb96dab chore(deps): update all dependencies and GitHub Actions to latest
- Go deps: cobra 1.10.2, fatih/color 1.19, tablewriter 1.1.4,
  anacrolix/torrent 1.61, charmbracelet/huh 1.0, pion/webrtc 4.2.11
- GitHub Actions: checkout v6, setup-go v6, golangci-lint-action v9,
  codecov-action v5, ghaction-upx v4, goreleaser-action v7
- CI matrix: drop Go 1.22, test on 1.24 + 1.25
- Migrate tablewriter API from v0 to v1 (breaking change)
- Fix data race in WSTransport.readLoop (pass conn as parameter)
- Add file.Sync() before close in debrid and usenet downloaders
- Improve progress tracker: dedup MarkDone, re-mark dirty on flush error
2026-03-28 21:56:22 +01:00
Deivid Soto
197e33956a feat: improve daemon resilience, streaming, and usenet downloads
- Add daemon state persistence and stale resume file cleanup
- Add TriggerPoll for WebSocket resume actions
- Improve stream server with graceful shutdown and connection tracking
- Add desktop notifications for download completion
- Add media file organization with Movies/TV Shows detection
- Improve usenet downloader with progress tracking and resume support
- Add self-update package with GitHub release verification
- Downgrade tablewriter to v0.0.5 (v1.x API breaking change)
2026-03-28 21:36:12 +01:00
Deivid Soto
e332c0a6e4 feat(usenet): implement full NNTP download pipeline
Complete usenet download support for unarr CLI:
- NZB XML parser with password extraction from <head> meta
- yEnc decoder with CRC32 verification
- NNTP client with TLS, auth, and connection pool (up to 10 conns)
- Segment downloader with parallel workers and progress reporting
- Post-processing: par2 verify/repair, unrar/7z extraction with password support
- Agent client methods: SearchNzbs, DownloadNzb, GetUsenetCredentials
- UsenetDownloader implementing full Downloader interface
- Daemon wiring: UsenetDownloader passed to Manager

E2E tested: Oppenheimer 1080p (2.94 GB) downloaded via NNTP in 77.6s.
2026-03-28 21:12:12 +01:00
Deivid Soto
5f337eebd7 feat(agent): add WebSocket transport with HTTP fallback
Add Transport interface abstraction supporting WebSocket (via CF
Durable Objects) and HTTP (direct to origin) with automatic failover.

- Transport interface: Register, SendHeartbeat, SendProgress, Events()
- HTTPTransport: thin adapter over existing Client
- WSTransport: gorilla/websocket with auth handshake, readLoop, reconnect
- HybridTransport: tries WS first, falls back to HTTP, reconnects in bg
- Daemon refactored to always use Transport (no dual-path forks)
- ProgressReporter accepts StatusReporter interface
- deriveWSURL skips localhost/dev (returns "" → HTTP-only)
- API key passed in WS query param for connection auth
- Fixed: reconnectOnce race (mutex+bool), authDone double-close (sync.Once)
- Fixed: forwardWSEvents goroutine leak (select with stop signal)
- 20 transport tests + 2 E2E tests (full lifecycle, hybrid failover)
2026-03-28 18:55:29 +01:00
Deivid Soto
5e80911501 feat(debrid): add HTTPS downloader for debrid direct URLs
DebridDownloader receives directUrl from the server and downloads via
plain HTTPS with progress reporting, resume (Range), and pause/cancel.

- Add DirectURL, DirectFileName to agent Task and engine Task types
- Implement DebridDownloader: HTTPS download with progress, resume, cancel
- HTTP client with 30s ResponseHeaderTimeout
- Safe shortID helper to prevent slice panic on short IDs
- Validate 416 against Content-Range server size for resume integrity
- Register debridDl in daemon and one-shot download command
- Tests: available, download, resume, cancel, pause, fallback filename,
  expired URL (410), unauthorized (401), shutdown, task propagation
2026-03-28 18:09:34 +01:00
Deivid Soto
29cf0a0126 feat: initial commit — unarr CLI
Search, inspect, stream, and download torrents from the terminal.
Replaces the entire *arr stack with a single binary.
2026-03-28 11:29:42 +01:00