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)
This commit is contained in:
parent
9cc806d11f
commit
5a7449b9e6
58 changed files with 166 additions and 141 deletions
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
22
.github/workflows/release.yml
vendored
22
.github/workflows/release.yml
vendored
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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: |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
2
Makefile
2
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
|
||||
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -1,9 +1,9 @@
|
|||
# unarr
|
||||
|
||||
[](https://github.com/torrentclaw/torrentclaw-cli/actions/workflows/ci.yml)
|
||||
[](https://goreportcard.com/report/github.com/torrentclaw/torrentclaw-cli)
|
||||
[](https://github.com/torrentclaw/unarr/actions/workflows/ci.yml)
|
||||
[](https://goreportcard.com/report/github.com/torrentclaw/unarr)
|
||||
[](LICENSE)
|
||||
[](go.mod)
|
||||
[](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
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
6
go.mod
6
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
|
||||
|
|
|
|||
|
|
@ -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 ----
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/torrentclaw/torrentclaw-cli/internal/agent"
|
||||
"github.com/torrentclaw/unarr/internal/agent"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/torrentclaw/torrentclaw-cli/internal/library/mediainfo"
|
||||
"github.com/torrentclaw/unarr/internal/library/mediainfo"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue