Skip to content

Commit 0373924

Browse files
feat!: add CLI interface for TsArr (#81)
* feat: add Bazarr client for subtitle management (#53) Add complete type-safe BazarrClient to the Tsarr SDK, providing access to Bazarr's subtitle management API with 50+ methods covering series, episodes, movies, providers, and system operations. Changes: - Add BazarrClient class with comprehensive subtitle management methods - Generate Bazarr API types and SDK from OpenAPI spec (v1.5.5) - Update generation scripts to include Bazarr - Export BazarrClient and Bazarr namespace from main index - Add package.json exports for bazarr and bazarr/types Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> * feat: add CLI interface for TsArr with full Servarr support Add complete CLI for managing all 6 Servarr apps (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, Bazarr) with interactive configuration, multiple output formats, shell completions, and connection diagnostics. Fixes: - Destructive commands now properly fail in non-TTY with --yes flag for automation - Config init no longer leaks secrets between env/global/local scopes - Local config read/write paths are consistent (walk up directory tree) - Config init shows clean error message instead of stack trace in non-interactive mode - Completions registry synced with actual command tree (removes stale Sonarr queue, adds Bazarr actions) Features: - Service command factory (DRY) for easy addition of new Servarr apps - Config: global (~/.config/tsarr/config.json) + local (.tsarr.json) + env vars - Output: --json (piped default), --table (TTY default), --quiet (IDs only) - Commands: doctor (connection test), config init/set/get/show, completions - All 6 services with list/get/search/delete/status/health actions - Interactive prompts for missing required args - Hey-api response unwrapping and paginated response handling Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 15ad433 commit 0373924

17 files changed

Lines changed: 1780 additions & 11 deletions

README.md

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,95 @@
77
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
88
[![CI](https://github.com/robbeverhelst/Tsarr/workflows/CI/badge.svg)](https://github.com/robbeverhelst/Tsarr/actions)
99

10-
**Type-safe TypeScript SDK for Servarr APIs (Radarr, Sonarr, etc.)**
10+
**Type-safe TypeScript SDK and CLI for Servarr APIs (Radarr, Sonarr, etc.)**
1111

12-
Tsarr provides type-safe TypeScript clients for all Servarr APIs, generated from their Swagger/OpenAPI specifications. Perfect for building automation tools, scripts, and applications to manage your media servers.
12+
Tsarr provides type-safe TypeScript clients and a CLI for all Servarr APIs, generated from their Swagger/OpenAPI specifications. Use it as an SDK in your code or as a standalone CLI tool.
1313

1414
## Features
1515

1616
- 🛡️ **Type-safe** - Generated from official Swagger/OpenAPI specs
1717
-**Bun-optimized** - Leverages native fetch API
1818
- 📦 **Modular** - Separate clients for each Servarr app
19+
- 💻 **CLI included** - Manage all Servarr apps from the terminal
1920

2021
## Supported Servarr Apps
2122

2223
- **Radarr** - Movie collection manager
23-
- **Sonarr** - TV series collection manager
24+
- **Sonarr** - TV series collection manager
2425
- **Lidarr** - Music collection manager
2526
- **Readarr** - Book collection manager
2627
- **Prowlarr** - Indexer manager
28+
- **Bazarr** - Subtitle manager
2729

2830
## Installation
2931

3032
```bash
33+
# As a dependency (SDK)
3134
bun add tsarr
35+
36+
# As a global CLI
37+
bun add -g tsarr
38+
```
39+
40+
## CLI
41+
42+
### Setup
43+
44+
```bash
45+
# Interactive setup wizard
46+
tsarr config init
47+
48+
# Or configure manually
49+
tsarr config set services.radarr.baseUrl http://localhost:7878
50+
tsarr config set services.radarr.apiKey your-api-key
51+
52+
# Or use environment variables
53+
export TSARR_RADARR_URL=http://localhost:7878
54+
export TSARR_RADARR_API_KEY=your-api-key
55+
```
56+
57+
Config is stored in `~/.config/tsarr/config.json` (global) or `.tsarr.json` (local project). Environment variables take priority over config files.
58+
59+
### Usage
60+
61+
```bash
62+
tsarr <service> <resource> <action> [options]
63+
64+
# Examples
65+
tsarr radarr movie list
66+
tsarr radarr movie search --term "Interstellar"
67+
tsarr sonarr series list
68+
tsarr prowlarr indexer list
69+
tsarr lidarr artist search --term "Radiohead"
70+
71+
# Output formats
72+
tsarr radarr movie list --table # Table (default in terminal)
73+
tsarr radarr movie list --json # JSON (default when piped)
74+
tsarr radarr movie list --quiet # IDs only
75+
76+
# Diagnostics
77+
tsarr doctor # Test all configured connections
78+
79+
# Shell completions
80+
tsarr completions bash >> ~/.bashrc
81+
tsarr completions zsh >> ~/.zshrc
82+
tsarr completions fish > ~/.config/fish/completions/tsarr.fish
3283
```
3384

34-
## Quick Start
85+
### Available Commands
86+
87+
| Service | Resources |
88+
|---------|-----------|
89+
| `radarr` | movie, profile, tag, queue, rootfolder, system, history, customformat |
90+
| `sonarr` | series, episode, profile, tag, rootfolder, system |
91+
| `lidarr` | artist, album, profile, tag, rootfolder, system |
92+
| `readarr` | author, book, profile, tag, rootfolder, system |
93+
| `prowlarr` | indexer, search, app, tag, system |
94+
| `bazarr` | series, movie, episode, provider, language, system |
95+
96+
## SDK
97+
98+
### Quick Start
3599

36100
```typescript
37101
import { RadarrClient, SonarrClient, LidarrClient } from 'tsarr';
@@ -46,6 +110,15 @@ const movies = await radarr.getMovies();
46110
const status = await radarr.getSystemStatus();
47111
```
48112

113+
### Modular Imports
114+
115+
```typescript
116+
// Import only what you need
117+
import { RadarrClient } from 'tsarr/radarr';
118+
import { SonarrClient } from 'tsarr/sonarr';
119+
import type { MovieResource } from 'tsarr/radarr/types';
120+
```
121+
49122
## Development
50123

51124
Install dependencies:
@@ -86,7 +159,7 @@ Perfect for building:
86159
- **Automation scripts** - Bulk movie imports, library maintenance, and media organization
87160
- **Management tools** - Custom dashboards, backup utilities, and monitoring scripts
88161
- **Integration scripts** - Connect Servarr apps with other services and workflows
89-
- **CLI tools** - Command-line utilities for media server administration
162+
- **CLI usage** - Manage your media servers directly from the terminal
90163

91164
## Contributing
92165

bun.lock

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"type": "git",
77
"url": "https://github.com/robbeverhelst/tsarr.git"
88
},
9+
"bin": {
10+
"tsarr": "./dist/cli/index.js"
11+
},
912
"main": "dist/index.js",
1013
"module": "dist/index.js",
1114
"devDependencies": {
@@ -86,20 +89,23 @@
8689
"typescript",
8790
"sdk",
8891
"api",
89-
"bun"
92+
"bun",
93+
"cli"
9094
],
9195
"license": "MIT",
9296
"publishConfig": {
9397
"access": "public",
9498
"registry": "https://registry.npmjs.org/"
9599
},
96100
"scripts": {
97-
"build": "bun run generate && bun run generate:types && bun run build:js && bun run build:types",
101+
"build": "bun run generate && bun run generate:types && bun run build:js && bun run build:cli && bun run build:types",
98102
"build:js": "bun build src/index.ts --outdir dist --target node --minify --splitting && bun build src/clients/radarr.ts --outdir dist/clients --target node --format esm && bun build src/clients/sonarr.ts --outdir dist/clients --target node --format esm && bun build src/clients/lidarr.ts --outdir dist/clients --target node --format esm && bun build src/clients/readarr.ts --outdir dist/clients --target node --format esm && bun build src/clients/prowlarr.ts --outdir dist/clients --target node --format esm && bun build src/clients/bazarr.ts --outdir dist/clients --target node --format esm",
103+
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && chmod +x dist/cli/index.js",
99104
"build:types": "tsc --project tsconfig.build.json",
100105
"prepublishOnly": "bun run build",
101106
"test": "bun test",
102107
"dev": "bun run src/index.ts",
108+
"cli": "bun run src/cli/index.ts",
103109
"lint": "biome check .",
104110
"lint:fix": "biome check . --write",
105111
"format": "biome format . --write",
@@ -116,5 +122,9 @@
116122
},
117123
"sideEffects": false,
118124
"type": "module",
119-
"types": "dist/index.d.ts"
125+
"types": "dist/index.d.ts",
126+
"dependencies": {
127+
"citty": "^0.2.1",
128+
"consola": "^3.4.2"
129+
}
120130
}

src/cli/commands/bazarr.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { BazarrClient } from '../../clients/bazarr.js';
2+
import type { ResourceDef } from './service.js';
3+
import { buildServiceCommand } from './service.js';
4+
5+
const resources: ResourceDef[] = [
6+
{
7+
name: 'series',
8+
description: 'Manage series subtitles',
9+
actions: [
10+
{
11+
name: 'list',
12+
description: 'List series with subtitle info',
13+
columns: ['sonarrSeriesId', 'title', 'profileId'],
14+
run: (c: BazarrClient) => c.getSeries(),
15+
},
16+
],
17+
},
18+
{
19+
name: 'movie',
20+
description: 'Manage movie subtitles',
21+
actions: [
22+
{
23+
name: 'list',
24+
description: 'List movies with subtitle info',
25+
columns: ['radarrId', 'title', 'profileId'],
26+
run: (c: BazarrClient) => c.getMovies(),
27+
},
28+
],
29+
},
30+
{
31+
name: 'episode',
32+
description: 'Manage episode subtitles',
33+
actions: [
34+
{
35+
name: 'wanted',
36+
description: 'List episodes with wanted subtitles',
37+
columns: ['sonarrEpisodeId', 'title', 'seriesTitle'],
38+
run: (c: BazarrClient) => c.getEpisodesWanted(),
39+
},
40+
],
41+
},
42+
{
43+
name: 'provider',
44+
description: 'Manage subtitle providers',
45+
actions: [
46+
{
47+
name: 'list',
48+
description: 'List subtitle providers',
49+
run: (c: BazarrClient) => c.getProviders(),
50+
},
51+
],
52+
},
53+
{
54+
name: 'language',
55+
description: 'Manage languages',
56+
actions: [
57+
{
58+
name: 'list',
59+
description: 'List available languages',
60+
columns: ['code2', 'name', 'enabled'],
61+
run: (c: BazarrClient) => c.getLanguages(),
62+
},
63+
{
64+
name: 'profiles',
65+
description: 'List language profiles',
66+
columns: ['profileId', 'name'],
67+
run: (c: BazarrClient) => c.getLanguageProfiles(),
68+
},
69+
],
70+
},
71+
{
72+
name: 'system',
73+
description: 'System information',
74+
actions: [
75+
{
76+
name: 'status',
77+
description: 'Get system status',
78+
run: (c: BazarrClient) => c.getSystemStatus(),
79+
},
80+
{
81+
name: 'health',
82+
description: 'Get system health',
83+
run: (c: BazarrClient) => c.getSystemHealth(),
84+
},
85+
{
86+
name: 'badges',
87+
description: 'Get badge counts',
88+
run: (c: BazarrClient) => c.getBadges(),
89+
},
90+
],
91+
},
92+
];
93+
94+
export const bazarr = buildServiceCommand(
95+
'bazarr',
96+
'Manage Bazarr (Subtitles)',
97+
config => new BazarrClient(config),
98+
resources
99+
);

0 commit comments

Comments
 (0)