diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 5928222..225bbc7 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - name: Questions & Discussion - url: https://github.com/torrentclaw/torrentclaw-cli/discussions + url: https://github.com/torrentclaw/unarr/discussions about: Ask questions or start a discussion diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 197da9d..bd4c0e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,30 +10,20 @@ permissions: jobs: release: - name: GoReleaser runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Checkout go-client (local replace dependency) - run: git clone --depth 1 https://github.com/torrentclaw/go-client "$GITHUB_WORKSPACE/../go-client" - - - name: Set up Go - uses: actions/setup-go@v6 + - uses: actions/setup-go@v5 with: - go-version: "1.25" + go-version-file: go.mod - - name: Install UPX - uses: crazy-max/ghaction-upx@v4 + - uses: goreleaser/goreleaser-action@v6 with: - install-only: true - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v7 - with: - version: latest + version: "~> v2" args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index f4e8102..d9f41fa 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -16,8 +16,8 @@ builds: - arm64 ldflags: - -s -w - - -X github.com/torrentclaw/torrentclaw-cli/internal/cmd.Version={{.Version}} - - -X github.com/torrentclaw/torrentclaw-cli/internal/sentry.dsn={{ .Env.SENTRY_DSN }} + - -X github.com/torrentclaw/unarr/internal/cmd.Version={{.Version}} + - -X github.com/torrentclaw/unarr/internal/sentry.dsn={{ .Env.SENTRY_DSN }} archives: - format: tar.gz @@ -42,7 +42,7 @@ brews: owner: torrentclaw name: homebrew-tap name: unarr - homepage: https://github.com/torrentclaw/torrentclaw-cli + homepage: https://github.com/torrentclaw/unarr description: "unarr — replaces the entire *arr stack" license: MIT install: | diff --git a/CHANGELOG.md b/CHANGELOG.md index c7a8710..0f49ea9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,5 +53,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - CI pipeline (test, build, lint, vet) - Lefthook git hooks (gofmt, go vet, conventional commits) -[Unreleased]: https://github.com/torrentclaw/torrentclaw-cli/compare/v0.1.0...HEAD -[0.1.0]: https://github.com/torrentclaw/torrentclaw-cli/releases/tag/v0.1.0 +[Unreleased]: https://github.com/torrentclaw/unarr/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/torrentclaw/unarr/releases/tag/v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca4f1a0..92a655d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,15 +7,15 @@ Thank you for your interest in contributing! This guide will help you get starte 1. **Fork** the repository on GitHub 2. **Clone** your fork locally: ```bash - git clone https://github.com/YOUR-USERNAME/torrentclaw-cli.git - cd torrentclaw-cli + git clone https://github.com/YOUR-USERNAME/unarr.git + cd unarr ``` 3. **Set up the Go client** (local dependency): ```bash # Clone the go-client next to the CLI cd .. git clone https://github.com/torrentclaw/go-client.git - cd torrentclaw-cli + cd unarr ``` 4. **Create a branch** for your change: ```bash @@ -23,7 +23,7 @@ Thank you for your interest in contributing! This guide will help you get starte ``` 5. **Make your changes**, write tests, and ensure everything passes 6. **Commit** with a clear message (see [Commit Messages](#commit-messages)) -7. **Push** to your fork and [open a Pull Request](https://github.com/torrentclaw/torrentclaw-cli/compare) +7. **Push** to your fork and [open a Pull Request](https://github.com/torrentclaw/unarr/compare) ## Development Setup @@ -76,7 +76,7 @@ make install-hooks # Install lefthook git hooks ## Project Structure ``` -torrentclaw-cli/ +unarr/ ├── cmd/unarr/ # Entry point │ └── main.go ├── internal/ @@ -176,7 +176,7 @@ chore: update CI matrix to Go 1.24 ## Reporting Bugs -[Open an issue](https://github.com/torrentclaw/torrentclaw-cli/issues/new?labels=bug) with: +[Open an issue](https://github.com/torrentclaw/unarr/issues/new?labels=bug) with: - **Description** — what went wrong - **Steps to reproduce** — minimal commands to trigger the bug diff --git a/Dockerfile b/Dockerfile index 0a7a9d4..38c70c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # ---- Build stage ---- -# Build context must be the parent directory containing both torrentclaw-cli/ -# and go-client/. Use: docker build -f torrentclaw-cli/Dockerfile . +# Build context must be the parent directory containing both unarr/ +# and go-client/. Use: docker build -f unarr/Dockerfile . # Or use the provided docker-build.sh script. FROM golang:1.24-alpine AS builder @@ -12,12 +12,12 @@ COPY go-client/ /deps/go-client/ # Copy go.mod/go.sum first for layer caching WORKDIR /src -COPY torrentclaw-cli/go.mod torrentclaw-cli/go.sum ./ +COPY unarr/go.mod unarr/go.sum ./ RUN go mod edit -replace github.com/torrentclaw/go-client=/deps/go-client RUN go mod download # Copy source (changes here won't invalidate mod cache) -COPY torrentclaw-cli/ . +COPY unarr/ . RUN go mod edit -replace github.com/torrentclaw/go-client=/deps/go-client RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /unarr ./cmd/unarr/ diff --git a/Makefile b/Makefile index c17b5e4..4a8245e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ BINARY = unarr SENTRY_DSN ?= -LDFLAGS = -s -w -X github.com/torrentclaw/torrentclaw-cli/internal/sentry.dsn=$(SENTRY_DSN) +LDFLAGS = -s -w -X github.com/torrentclaw/unarr/internal/sentry.dsn=$(SENTRY_DSN) all: fmt vet lint test build diff --git a/README.md b/README.md index 2b57702..d763d99 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # unarr -[![CI](https://github.com/torrentclaw/torrentclaw-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/torrentclaw/torrentclaw-cli/actions/workflows/ci.yml) -[![Go Report Card](https://goreportcard.com/badge/github.com/torrentclaw/torrentclaw-cli)](https://goreportcard.com/report/github.com/torrentclaw/torrentclaw-cli) +[![CI](https://github.com/torrentclaw/unarr/actions/workflows/ci.yml/badge.svg)](https://github.com/torrentclaw/unarr/actions/workflows/ci.yml) +[![Go Report Card](https://goreportcard.com/badge/github.com/torrentclaw/unarr)](https://goreportcard.com/report/github.com/torrentclaw/unarr) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -[![Go Version](https://img.shields.io/github/go-mod/go-version/torrentclaw/torrentclaw-cli)](go.mod) +[![Go Version](https://img.shields.io/github/go-mod/go-version/torrentclaw/unarr)](go.mod) Powerful terminal tool for torrent search and management. @@ -35,18 +35,18 @@ brew install torrentclaw/tap/unarr ### Go install ```bash -go install github.com/torrentclaw/torrentclaw-cli/cmd/unarr@latest +go install github.com/torrentclaw/unarr/cmd/unarr@latest ``` ### GitHub Releases -Download prebuilt binaries for Linux, macOS, and Windows from [GitHub Releases](https://github.com/torrentclaw/torrentclaw-cli/releases). +Download prebuilt binaries for Linux, macOS, and Windows from [GitHub Releases](https://github.com/torrentclaw/unarr/releases). ### Build from source ```bash -git clone https://github.com/torrentclaw/torrentclaw-cli.git -cd torrentclaw-cli +git clone https://github.com/torrentclaw/unarr.git +cd unarr make build ``` diff --git a/SECURITY.md b/SECURITY.md index 747b083..a7a3399 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,7 +15,7 @@ Only the latest release receives security updates. Instead, report them via **GitHub Security Advisories**: -1. Go to [Security Advisories](https://github.com/torrentclaw/torrentclaw-cli/security/advisories) +1. Go to [Security Advisories](https://github.com/torrentclaw/unarr/security/advisories) 2. Click **"Report a vulnerability"** 3. Fill in the details diff --git a/cmd/unarr/main.go b/cmd/unarr/main.go index ae89c25..9489ff7 100644 --- a/cmd/unarr/main.go +++ b/cmd/unarr/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/torrentclaw/torrentclaw-cli/internal/cmd" - "github.com/torrentclaw/torrentclaw-cli/internal/sentry" + "github.com/torrentclaw/unarr/internal/cmd" + "github.com/torrentclaw/unarr/internal/sentry" ) func main() { diff --git a/docker-build.sh b/docker-build.sh index 8475922..9417987 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -1,12 +1,12 @@ #!/bin/sh # Build the unarr Docker image. -# Must be run from the torrentclaw-cli directory (or its parent). +# Must be run from the unarr directory (or its parent). set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PARENT_DIR="$(dirname "$SCRIPT_DIR")" -# Build from parent dir so both torrentclaw-cli/ and go-client/ are in context +# Build from parent dir so both unarr/ and go-client/ are in context docker build \ -f "$SCRIPT_DIR/Dockerfile" \ -t torrentclaw/unarr:latest \ diff --git a/docker-compose.yml b/docker-compose.yml index b2e8247..5f49fcf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ services: unarr: build: context: .. - dockerfile: torrentclaw-cli/Dockerfile + dockerfile: unarr/Dockerfile image: torrentclaw/unarr:latest container_name: unarr restart: unless-stopped diff --git a/go.mod b/go.mod index 0832f76..ac2f72b 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,13 @@ -module github.com/torrentclaw/torrentclaw-cli +module github.com/torrentclaw/unarr go 1.25.0 require ( github.com/BurntSushi/toml v1.6.0 + github.com/anacrolix/dht/v2 v2.23.0 github.com/anacrolix/log v0.17.1-0.20251118025802-918f1157b7bb github.com/anacrolix/torrent v1.61.0 + github.com/anacrolix/upnp v0.1.4 github.com/charmbracelet/huh v1.0.0 github.com/fatih/color v1.19.0 github.com/getsentry/sentry-go v0.44.1 @@ -22,7 +24,6 @@ require ( github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/anacrolix/btree v0.1.1 // indirect github.com/anacrolix/chansync v0.7.0 // indirect - github.com/anacrolix/dht/v2 v2.23.0 // indirect github.com/anacrolix/envpprof v1.5.0 // indirect github.com/anacrolix/generics v0.2.0 // indirect github.com/anacrolix/go-libutp v1.4.0 // indirect @@ -33,7 +34,6 @@ require ( github.com/anacrolix/multiless v0.4.0 // indirect github.com/anacrolix/stm v0.5.0 // indirect github.com/anacrolix/sync v0.6.0 // indirect - github.com/anacrolix/upnp v0.1.4 // indirect github.com/anacrolix/utp v0.2.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect diff --git a/install.ps1 b/install.ps1 index cd0754f..56ffb08 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,6 +1,6 @@ # unarr — Windows installer (PowerShell 5.1+) # Usage: irm https://get.unarr.com/install.ps1 | iex -# or: irm https://raw.githubusercontent.com/torrentclaw/torrentclaw-cli/main/install.ps1 | iex +# or: irm https://raw.githubusercontent.com/torrentclaw/unarr/main/install.ps1 | iex # # Options (env vars): # $env:INSTALL_DIR = "C:\path" — where to place the binary @@ -15,7 +15,7 @@ param( $ErrorActionPreference = "Stop" -$Repo = "torrentclaw/torrentclaw-cli" +$Repo = "torrentclaw/unarr" $Binary = "unarr.exe" # ---- Helpers ---- diff --git a/install.sh b/install.sh index 7be4e81..5b89ab1 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/bin/sh # unarr — cross-platform installer (Linux / macOS) # Usage: curl -fsSL https://get.unarr.com/install.sh | sh -# or: curl -fsSL https://raw.githubusercontent.com/torrentclaw/torrentclaw-cli/main/install.sh | sh +# or: curl -fsSL https://raw.githubusercontent.com/torrentclaw/unarr/main/install.sh | sh # # Options (env vars): # INSTALL_DIR=/usr/local/bin — where to place the binary (default: /usr/local/bin or ~/.local/bin) @@ -9,7 +9,7 @@ # METHOD=binary|docker — force install method (default: auto-detect) set -e -REPO="torrentclaw/torrentclaw-cli" +REPO="torrentclaw/unarr" BINARY="unarr" # ---- Colors (only if terminal) ---- @@ -217,7 +217,7 @@ install_docker() { torrentclaw/unarr # Or use the provided docker-compose.yml: - # curl -fsSL https://raw.githubusercontent.com/torrentclaw/torrentclaw-cli/main/docker-compose.yml > docker-compose.yml + # curl -fsSL https://raw.githubusercontent.com/torrentclaw/unarr/main/docker-compose.yml > docker-compose.yml # docker compose up -d DOCKER_USAGE diff --git a/internal/agent/state.go b/internal/agent/state.go index 7316116..5812709 100644 --- a/internal/agent/state.go +++ b/internal/agent/state.go @@ -6,7 +6,7 @@ import ( "path/filepath" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/config" + "github.com/torrentclaw/unarr/internal/config" ) // DaemonState is written to disk every heartbeat for external tools to read. diff --git a/internal/cmd/clean.go b/internal/cmd/clean.go index bfac761..18e7af0 100644 --- a/internal/cmd/clean.go +++ b/internal/cmd/clean.go @@ -10,9 +10,9 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/ui" ) func newCleanCmd() *cobra.Command { diff --git a/internal/cmd/config_menu.go b/internal/cmd/config_menu.go index 82e2090..a338066 100644 --- a/internal/cmd/config_menu.go +++ b/internal/cmd/config_menu.go @@ -11,7 +11,7 @@ import ( "github.com/charmbracelet/huh" "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/config" + "github.com/torrentclaw/unarr/internal/config" ) var configCategories = []string{"downloads", "organization", "notifications", "device", "region", "connection", "advanced"} diff --git a/internal/cmd/daemon.go b/internal/cmd/daemon.go index 8a7881b..5b5ddb6 100644 --- a/internal/cmd/daemon.go +++ b/internal/cmd/daemon.go @@ -13,12 +13,12 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/engine" - "github.com/torrentclaw/torrentclaw-cli/internal/library" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/download" - "github.com/torrentclaw/torrentclaw-cli/internal/upgrade" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/engine" + "github.com/torrentclaw/unarr/internal/library" + "github.com/torrentclaw/unarr/internal/usenet/download" + "github.com/torrentclaw/unarr/internal/upgrade" ) // newStartCmd creates the top-level `unarr start` command. diff --git a/internal/cmd/doctor.go b/internal/cmd/doctor.go index c8b06c9..3ee4cf6 100644 --- a/internal/cmd/doctor.go +++ b/internal/cmd/doctor.go @@ -9,8 +9,8 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" ) func newDoctorCmd() *cobra.Command { diff --git a/internal/cmd/download.go b/internal/cmd/download.go index cd91508..98e77d5 100644 --- a/internal/cmd/download.go +++ b/internal/cmd/download.go @@ -12,9 +12,9 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/engine" - "github.com/torrentclaw/torrentclaw-cli/internal/parser" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/engine" + "github.com/torrentclaw/unarr/internal/parser" ) func newDownloadCmd() *cobra.Command { diff --git a/internal/cmd/init.go b/internal/cmd/init.go index 845d81f..2bbb521 100644 --- a/internal/cmd/init.go +++ b/internal/cmd/init.go @@ -13,10 +13,10 @@ import ( "github.com/fatih/color" "github.com/google/uuid" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/arr" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/mediaserver" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/arr" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/mediaserver" ) func newInitCmd() *cobra.Command { diff --git a/internal/cmd/inspect.go b/internal/cmd/inspect.go index 9aaa837..d5682a6 100644 --- a/internal/cmd/inspect.go +++ b/internal/cmd/inspect.go @@ -9,8 +9,8 @@ import ( "github.com/spf13/cobra" tc "github.com/torrentclaw/go-client" - "github.com/torrentclaw/torrentclaw-cli/internal/parser" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/parser" + "github.com/torrentclaw/unarr/internal/ui" ) func newInspectCmd() *cobra.Command { diff --git a/internal/cmd/migrate.go b/internal/cmd/migrate.go index bcdde3a..c32d09d 100644 --- a/internal/cmd/migrate.go +++ b/internal/cmd/migrate.go @@ -11,10 +11,10 @@ import ( "github.com/charmbracelet/huh" "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/arr" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/mediaserver" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/arr" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/mediaserver" ) func newMigrateCmd() *cobra.Command { diff --git a/internal/cmd/popular.go b/internal/cmd/popular.go index b3a7a4d..66de977 100644 --- a/internal/cmd/popular.go +++ b/internal/cmd/popular.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" tc "github.com/torrentclaw/go-client" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/ui" ) func newPopularCmd() *cobra.Command { diff --git a/internal/cmd/recent.go b/internal/cmd/recent.go index d4c39bb..32bf37d 100644 --- a/internal/cmd/recent.go +++ b/internal/cmd/recent.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" tc "github.com/torrentclaw/go-client" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/ui" ) func newRecentCmd() *cobra.Command { diff --git a/internal/cmd/reload_unix.go b/internal/cmd/reload_unix.go index 4407043..5577a76 100644 --- a/internal/cmd/reload_unix.go +++ b/internal/cmd/reload_unix.go @@ -9,8 +9,8 @@ import ( "syscall" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" ) // ReloadableConfig holds a reference to the daemon for hot-reload. diff --git a/internal/cmd/reload_windows.go b/internal/cmd/reload_windows.go index cfc262a..d9e042e 100644 --- a/internal/cmd/reload_windows.go +++ b/internal/cmd/reload_windows.go @@ -2,7 +2,7 @@ package cmd -import "github.com/torrentclaw/torrentclaw-cli/internal/agent" +import "github.com/torrentclaw/unarr/internal/agent" // ReloadableConfig holds a reference to the daemon for hot-reload. type ReloadableConfig struct { diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 87c8f40..712038e 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -6,8 +6,8 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/sentry" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/sentry" tc "github.com/torrentclaw/go-client" ) @@ -37,7 +37,7 @@ Get started: unarr start Start the download daemon Documentation: https://torrentclaw.com/cli -Source: https://github.com/torrentclaw/torrentclaw-cli`, +Source: https://github.com/torrentclaw/unarr`, PersistentPreRun: func(cmd *cobra.Command, args []string) { if noColor || os.Getenv("NO_COLOR") != "" { color.NoColor = true diff --git a/internal/cmd/scan.go b/internal/cmd/scan.go index 791e636..2d9e591 100644 --- a/internal/cmd/scan.go +++ b/internal/cmd/scan.go @@ -12,9 +12,9 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/library" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/library" ) func newScanCmd() *cobra.Command { diff --git a/internal/cmd/search.go b/internal/cmd/search.go index 7134a8c..5b8377d 100644 --- a/internal/cmd/search.go +++ b/internal/cmd/search.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" tc "github.com/torrentclaw/go-client" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/ui" ) func newSearchCmd() *cobra.Command { diff --git a/internal/cmd/self_update.go b/internal/cmd/self_update.go index cc711e2..b936eb0 100644 --- a/internal/cmd/self_update.go +++ b/internal/cmd/self_update.go @@ -11,7 +11,7 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/upgrade" + "github.com/torrentclaw/unarr/internal/upgrade" ) func newSelfUpdateCmd() *cobra.Command { diff --git a/internal/cmd/stats.go b/internal/cmd/stats.go index 47905d3..bcc95f5 100644 --- a/internal/cmd/stats.go +++ b/internal/cmd/stats.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/ui" ) func newStatsCmd() *cobra.Command { diff --git a/internal/cmd/stream.go b/internal/cmd/stream.go index f28240b..91d2fea 100644 --- a/internal/cmd/stream.go +++ b/internal/cmd/stream.go @@ -12,9 +12,9 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/torrentclaw/torrentclaw-cli/internal/engine" - "github.com/torrentclaw/torrentclaw-cli/internal/parser" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/engine" + "github.com/torrentclaw/unarr/internal/parser" + "github.com/torrentclaw/unarr/internal/ui" ) func newStreamCmd() *cobra.Command { diff --git a/internal/cmd/stream_handler.go b/internal/cmd/stream_handler.go index 4c75331..bd2081f 100644 --- a/internal/cmd/stream_handler.go +++ b/internal/cmd/stream_handler.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/engine" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/engine" + "github.com/torrentclaw/unarr/internal/ui" ) // streamRegistry tracks active stream tasks and servers for cancellation. diff --git a/internal/cmd/stubs.go b/internal/cmd/stubs.go index d9f239d..bcd0d90 100644 --- a/internal/cmd/stubs.go +++ b/internal/cmd/stubs.go @@ -15,7 +15,7 @@ func newStubCmd(name, short string) *cobra.Command { fmt.Println() color.New(color.FgYellow).Printf(" ⚠️ '%s' is coming in a future release.\n", name) fmt.Println() - fmt.Println(" Follow progress at: https://github.com/torrentclaw/torrentclaw-cli") + fmt.Println(" Follow progress at: https://github.com/torrentclaw/unarr") fmt.Println() }, } diff --git a/internal/cmd/watch.go b/internal/cmd/watch.go index 3c237c7..28b07df 100644 --- a/internal/cmd/watch.go +++ b/internal/cmd/watch.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" tc "github.com/torrentclaw/go-client" - "github.com/torrentclaw/torrentclaw-cli/internal/ui" + "github.com/torrentclaw/unarr/internal/ui" ) func newWatchCmd() *cobra.Command { diff --git a/internal/engine/debrid_test.go b/internal/engine/debrid_test.go index 5a20222..b7fc019 100644 --- a/internal/engine/debrid_test.go +++ b/internal/engine/debrid_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) func TestDebridAvailable(t *testing.T) { diff --git a/internal/engine/manager.go b/internal/engine/manager.go index 0367a8f..12cfc06 100644 --- a/internal/engine/manager.go +++ b/internal/engine/manager.go @@ -5,7 +5,7 @@ import ( "log" "sync" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) // ManagerConfig holds download manager settings. @@ -24,6 +24,7 @@ type Manager struct { activeMu sync.RWMutex active map[string]*Task + cancels map[string]context.CancelFunc // per-task cancel functions sem chan struct{} wg sync.WaitGroup @@ -45,6 +46,7 @@ func NewManager(cfg ManagerConfig, reporter *ProgressReporter, downloaders ...Do reporter: reporter, downloaders: dlMap, active: make(map[string]*Task), + cancels: make(map[string]context.CancelFunc), sem: make(chan struct{}, cfg.MaxConcurrent), } } @@ -53,8 +55,12 @@ func NewManager(cfg ManagerConfig, reporter *ProgressReporter, downloaders ...Do func (m *Manager) Submit(ctx context.Context, at agent.Task) { task := NewTaskFromAgent(at) + // Per-task cancellable context so CancelTask can unblock the goroutine + taskCtx, taskCancel := context.WithCancel(ctx) + m.activeMu.Lock() m.active[task.ID] = task + m.cancels[task.ID] = taskCancel m.activeMu.Unlock() m.reporter.Track(task) @@ -65,7 +71,8 @@ func (m *Manager) Submit(ctx context.Context, at agent.Task) { m.wg.Add(1) go func() { defer m.wg.Done() - m.processTask(ctx, task) + defer taskCancel() + m.processTask(taskCtx, task) }() return } @@ -74,6 +81,7 @@ func (m *Manager) Submit(ctx context.Context, at agent.Task) { select { case m.sem <- struct{}{}: case <-ctx.Done(): + taskCancel() return } @@ -81,7 +89,8 @@ func (m *Manager) Submit(ctx context.Context, at agent.Task) { go func() { defer m.wg.Done() defer func() { <-m.sem }() - m.processTask(ctx, task) + defer taskCancel() + m.processTask(taskCtx, task) }() } @@ -119,12 +128,19 @@ func (m *Manager) ActiveTasks() []*Task { func (m *Manager) CancelTask(taskID string) { m.activeMu.RLock() task, ok := m.active[taskID] + cancel := m.cancels[taskID] m.activeMu.RUnlock() if !ok { return } + // Cancel the task's context first — this unblocks the goroutine + // (e.g. stuck waiting for metadata) so it exits and releases the semaphore slot. + if cancel != nil { + cancel() + } + if dl, exists := m.downloaders[task.ResolvedMethod]; exists { dl.Pause(taskID) // stop download, keep files } @@ -141,12 +157,17 @@ func (m *Manager) CancelTask(taskID string) { func (m *Manager) PauseTask(taskID string) { m.activeMu.RLock() task, ok := m.active[taskID] + cancel := m.cancels[taskID] m.activeMu.RUnlock() if !ok { return } + if cancel != nil { + cancel() + } + if dl, exists := m.downloaders[task.ResolvedMethod]; exists { dl.Pause(taskID) // stop download, keep files for resume } @@ -159,12 +180,17 @@ func (m *Manager) PauseTask(taskID string) { func (m *Manager) CancelAndDeleteFiles(taskID string) { m.activeMu.RLock() task, ok := m.active[taskID] + cancel := m.cancels[taskID] m.activeMu.RUnlock() if !ok { return } + if cancel != nil { + cancel() + } + if dl, exists := m.downloaders[task.ResolvedMethod]; exists { dl.Cancel(taskID) // stop download + delete files } @@ -204,8 +230,12 @@ func (m *Manager) Shutdown(ctx context.Context) { } } - // Clean active map + // Clean active map and cancel functions m.activeMu.Lock() + for id, cancel := range m.cancels { + cancel() + delete(m.cancels, id) + } m.active = make(map[string]*Task) m.activeMu.Unlock() } @@ -214,6 +244,7 @@ func (m *Manager) processTask(ctx context.Context, task *Task) { defer func() { m.activeMu.Lock() delete(m.active, task.ID) + delete(m.cancels, task.ID) m.activeMu.Unlock() }() diff --git a/internal/engine/manager_test.go b/internal/engine/manager_test.go index 396e7ef..7c9893f 100644 --- a/internal/engine/manager_test.go +++ b/internal/engine/manager_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) func TestManagerSubmitAndWait(t *testing.T) { diff --git a/internal/engine/progress.go b/internal/engine/progress.go index e3c15fb..f91af8a 100644 --- a/internal/engine/progress.go +++ b/internal/engine/progress.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) // ActionFunc is called when the server signals an action on a task. diff --git a/internal/engine/stream_test.go b/internal/engine/stream_test.go index d66bd63..eb8a541 100644 --- a/internal/engine/stream_test.go +++ b/internal/engine/stream_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) // --------------------------------------------------------------------------- diff --git a/internal/engine/task.go b/internal/engine/task.go index 3202187..78513bc 100644 --- a/internal/engine/task.go +++ b/internal/engine/task.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) // TaskStatus represents the current state of a download task. diff --git a/internal/engine/task_test.go b/internal/engine/task_test.go index 13848d4..00d2b1a 100644 --- a/internal/engine/task_test.go +++ b/internal/engine/task_test.go @@ -3,7 +3,7 @@ package engine import ( "testing" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" + "github.com/torrentclaw/unarr/internal/agent" ) func TestNewTaskFromAgent(t *testing.T) { diff --git a/internal/engine/torrent.go b/internal/engine/torrent.go index 56bf08a..3318255 100644 --- a/internal/engine/torrent.go +++ b/internal/engine/torrent.go @@ -16,7 +16,7 @@ import ( "github.com/anacrolix/dht/v2/krpc" "github.com/anacrolix/torrent" "github.com/anacrolix/torrent/storage" - "github.com/torrentclaw/torrentclaw-cli/internal/config" + "github.com/torrentclaw/unarr/internal/config" "golang.org/x/time/rate" ) diff --git a/internal/engine/upnp.go b/internal/engine/upnp.go index c321338..1171cf8 100644 --- a/internal/engine/upnp.go +++ b/internal/engine/upnp.go @@ -20,11 +20,13 @@ type UPnPMapping struct { // setupUPnP discovers the gateway, maps the port, and gets the public IP. // Returns nil if UPnP is not available or fails. func setupUPnP(internalPort int) (*UPnPMapping, error) { - devices := upnp.Discover(0, 5*time.Second, alog.Logger{}) + log.Println("stream: discovering UPnP gateway (10s timeout)...") + devices := upnp.Discover(0, 10*time.Second, alog.Logger{}) if len(devices) == 0 { - return nil, fmt.Errorf("no UPnP devices found") + return nil, fmt.Errorf("no UPnP devices found (is UPnP enabled on your router?)") } + log.Printf("stream: found %d UPnP device(s), using %s", len(devices), devices[0].ID()) device := devices[0] // Get public IP @@ -32,13 +34,15 @@ func setupUPnP(internalPort int) (*UPnPMapping, error) { if err != nil { return nil, fmt.Errorf("get external IP: %w", err) } + log.Printf("stream: public IP via UPnP: %s", externalIP) - // Map port (0 = let router choose external port, 2h lease) + // Map port (same internal/external, 2h lease) mappedPort, err := device.AddPortMapping(upnp.TCP, internalPort, internalPort, "unarr stream", 2*time.Hour) if err != nil { - return nil, fmt.Errorf("add port mapping: %w", err) + return nil, fmt.Errorf("add port mapping %d: %w", internalPort, err) } + log.Printf("stream: UPnP port mapped %s:%d -> local:%d (2h lease)", externalIP, mappedPort, internalPort) return &UPnPMapping{ ExternalIP: externalIP.String(), ExternalPort: mappedPort, diff --git a/internal/engine/usenet.go b/internal/engine/usenet.go index a7698db..bc85a68 100644 --- a/internal/engine/usenet.go +++ b/internal/engine/usenet.go @@ -10,12 +10,12 @@ import ( "sync" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/agent" - "github.com/torrentclaw/torrentclaw-cli/internal/config" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/download" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nntp" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nzb" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/postprocess" + "github.com/torrentclaw/unarr/internal/agent" + "github.com/torrentclaw/unarr/internal/config" + "github.com/torrentclaw/unarr/internal/usenet/download" + "github.com/torrentclaw/unarr/internal/usenet/nntp" + "github.com/torrentclaw/unarr/internal/usenet/nzb" + "github.com/torrentclaw/unarr/internal/usenet/postprocess" ) // activeDownload holds the state for a single in-progress usenet download. diff --git a/internal/library/cache.go b/internal/library/cache.go index f2cdc35..e86c7c7 100644 --- a/internal/library/cache.go +++ b/internal/library/cache.go @@ -6,7 +6,7 @@ import ( "os" "path/filepath" - "github.com/torrentclaw/torrentclaw-cli/internal/config" + "github.com/torrentclaw/unarr/internal/config" ) // CachePath returns the default library cache file path. diff --git a/internal/library/resolve.go b/internal/library/resolve.go index 621c25d..ca4a9dd 100644 --- a/internal/library/resolve.go +++ b/internal/library/resolve.go @@ -4,7 +4,7 @@ import ( "regexp" "strings" - "github.com/torrentclaw/torrentclaw-cli/internal/library/mediainfo" + "github.com/torrentclaw/unarr/internal/library/mediainfo" ) var ( diff --git a/internal/library/resolve_test.go b/internal/library/resolve_test.go index 015c26d..c226e06 100644 --- a/internal/library/resolve_test.go +++ b/internal/library/resolve_test.go @@ -3,7 +3,7 @@ package library import ( "testing" - "github.com/torrentclaw/torrentclaw-cli/internal/library/mediainfo" + "github.com/torrentclaw/unarr/internal/library/mediainfo" ) func TestResolveResolution(t *testing.T) { diff --git a/internal/library/scanner.go b/internal/library/scanner.go index b6e4742..9b9692e 100644 --- a/internal/library/scanner.go +++ b/internal/library/scanner.go @@ -11,8 +11,8 @@ import ( "sync/atomic" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/library/mediainfo" - "github.com/torrentclaw/torrentclaw-cli/internal/parser" + "github.com/torrentclaw/unarr/internal/library/mediainfo" + "github.com/torrentclaw/unarr/internal/parser" ) // videoExts are file extensions considered as video files. diff --git a/internal/library/sync.go b/internal/library/sync.go index bfa75ec..bafd054 100644 --- a/internal/library/sync.go +++ b/internal/library/sync.go @@ -1,6 +1,6 @@ package library -import "github.com/torrentclaw/torrentclaw-cli/internal/agent" +import "github.com/torrentclaw/unarr/internal/agent" // BuildSyncItems converts cached library items to sync request items. // Shared between unarr scan (cmd/scan.go) and auto-scan (cmd/daemon.go). diff --git a/internal/library/types.go b/internal/library/types.go index c6e5370..e11fde4 100644 --- a/internal/library/types.go +++ b/internal/library/types.go @@ -1,6 +1,6 @@ package library -import "github.com/torrentclaw/torrentclaw-cli/internal/library/mediainfo" +import "github.com/torrentclaw/unarr/internal/library/mediainfo" // LibraryItem represents a single scanned media file. type LibraryItem struct { diff --git a/internal/sentry/sentry.go b/internal/sentry/sentry.go index ee6423a..633fc0d 100644 --- a/internal/sentry/sentry.go +++ b/internal/sentry/sentry.go @@ -10,7 +10,7 @@ import ( ) // dsn is injected at build time via ldflags. If empty, Sentry is disabled. -// Set via: -ldflags "-X github.com/torrentclaw/torrentclaw-cli/internal/sentry.dsn=..." +// Set via: -ldflags "-X github.com/torrentclaw/unarr/internal/sentry.dsn=..." var dsn string const flushTimeout = 2 * time.Second diff --git a/internal/usenet/download/downloader.go b/internal/usenet/download/downloader.go index e49321f..6b9d31e 100644 --- a/internal/usenet/download/downloader.go +++ b/internal/usenet/download/downloader.go @@ -12,9 +12,9 @@ import ( "sync/atomic" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nntp" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nzb" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/yenc" + "github.com/torrentclaw/unarr/internal/usenet/nntp" + "github.com/torrentclaw/unarr/internal/usenet/nzb" + "github.com/torrentclaw/unarr/internal/usenet/yenc" ) // Progress is emitted during download. diff --git a/internal/usenet/download/e2e_test.go b/internal/usenet/download/e2e_test.go index a6ac531..83ec687 100644 --- a/internal/usenet/download/e2e_test.go +++ b/internal/usenet/download/e2e_test.go @@ -8,10 +8,10 @@ import ( "testing" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/download" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nntp" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nzb" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/postprocess" + "github.com/torrentclaw/unarr/internal/usenet/download" + "github.com/torrentclaw/unarr/internal/usenet/nntp" + "github.com/torrentclaw/unarr/internal/usenet/nzb" + "github.com/torrentclaw/unarr/internal/usenet/postprocess" ) // TestE2EDownload is a real end-to-end test that downloads from Usenet. diff --git a/internal/usenet/download/progress.go b/internal/usenet/download/progress.go index 8e7a547..41d83df 100644 --- a/internal/usenet/download/progress.go +++ b/internal/usenet/download/progress.go @@ -11,7 +11,7 @@ import ( "sync/atomic" "time" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nzb" + "github.com/torrentclaw/unarr/internal/usenet/nzb" ) // Binary progress file format: diff --git a/internal/usenet/download/progress_test.go b/internal/usenet/download/progress_test.go index 831eeb4..9c37de2 100644 --- a/internal/usenet/download/progress_test.go +++ b/internal/usenet/download/progress_test.go @@ -8,7 +8,7 @@ import ( "time" - "github.com/torrentclaw/torrentclaw-cli/internal/usenet/nzb" + "github.com/torrentclaw/unarr/internal/usenet/nzb" ) var fixedPast = time.Now().Add(-30 * 24 * time.Hour)