tsarr 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -3
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts +8 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/lidarr.d.ts.map +1 -1
- package/dist/cli/commands/service.d.ts.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +334 -129
- package/dist/cli/output.d.ts +4 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/clients/bazarr.js +1 -5
- package/dist/clients/lidarr.d.ts.map +1 -1
- package/dist/clients/lidarr.js +4 -0
- package/dist/clients/prowlarr.d.ts.map +1 -1
- package/dist/clients/prowlarr.js +4 -0
- package/dist/clients/radarr.d.ts.map +1 -1
- package/dist/clients/radarr.js +4 -0
- package/dist/clients/readarr.d.ts.map +1 -1
- package/dist/clients/readarr.js +4 -0
- package/dist/clients/sonarr.d.ts.map +1 -1
- package/dist/clients/sonarr.js +4 -0
- package/dist/generated/bazarr/sdk.gen.d.ts.map +1 -1
- package/dist/index.js +7 -7
- package/dist/tsarr-2.3.0.tgz +0 -0
- package/package.json +8 -6
- package/dist/tsarr-2.2.0.tgz +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
// @bun
|
|
1
|
+
#!/usr/bin/env node
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __returnValue = (v) => v;
|
|
5
4
|
function __exportSetter(name, newValue) {
|
|
@@ -88,7 +87,7 @@ var init_scule = __esm(() => {
|
|
|
88
87
|
});
|
|
89
88
|
|
|
90
89
|
// node_modules/citty/dist/index.mjs
|
|
91
|
-
import { parseArgs as parseArgs$1 } from "util";
|
|
90
|
+
import { parseArgs as parseArgs$1 } from "node:util";
|
|
92
91
|
function toArray(val) {
|
|
93
92
|
if (Array.isArray(val))
|
|
94
93
|
return val;
|
|
@@ -714,7 +713,7 @@ var separatorArrayExplode = (style) => {
|
|
|
714
713
|
return "";
|
|
715
714
|
}
|
|
716
715
|
if (typeof value === "object") {
|
|
717
|
-
throw new Error("Deeply-nested arrays/objects aren
|
|
716
|
+
throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
718
717
|
}
|
|
719
718
|
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
720
719
|
}, serializeObjectParam = ({
|
|
@@ -2794,6 +2793,10 @@ class RadarrClient {
|
|
|
2794
2793
|
updateConfig(newConfig) {
|
|
2795
2794
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
2796
2795
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
2796
|
+
client.setConfig({
|
|
2797
|
+
baseUrl: this.clientConfig.getBaseUrl(),
|
|
2798
|
+
headers: this.clientConfig.getHeaders()
|
|
2799
|
+
});
|
|
2797
2800
|
return this.clientConfig.config;
|
|
2798
2801
|
}
|
|
2799
2802
|
}
|
|
@@ -3203,8 +3206,8 @@ var init_core = __esm(() => {
|
|
|
3203
3206
|
});
|
|
3204
3207
|
|
|
3205
3208
|
// node_modules/consola/dist/shared/consola.DRwqZj3T.mjs
|
|
3206
|
-
import { formatWithOptions } from "util";
|
|
3207
|
-
import { sep } from "path";
|
|
3209
|
+
import { formatWithOptions } from "node:util";
|
|
3210
|
+
import { sep } from "node:path";
|
|
3208
3211
|
function parseStack(stack, message) {
|
|
3209
3212
|
const cwd = process.cwd() + sep;
|
|
3210
3213
|
const lines = stack.split(`
|
|
@@ -3281,7 +3284,7 @@ var bracket = (x) => x ? `[${x}]` : "";
|
|
|
3281
3284
|
var init_consola_DRwqZj3T = () => {};
|
|
3282
3285
|
|
|
3283
3286
|
// node_modules/consola/dist/shared/consola.DXBYu-KD.mjs
|
|
3284
|
-
import * as tty from "tty";
|
|
3287
|
+
import * as tty from "node:tty";
|
|
3285
3288
|
function replaceClose(index, string, close, replace, head = string.slice(0, Math.max(0, index)) + replace, tail = string.slice(Math.max(0, index + close.length)), next = tail.indexOf(close)) {
|
|
3286
3289
|
return head + (next < 0 ? tail : replaceClose(next, tail, close, replace));
|
|
3287
3290
|
}
|
|
@@ -3421,68 +3424,68 @@ var init_consola_DXBYu_KD = __esm(() => {
|
|
|
3421
3424
|
].join("|");
|
|
3422
3425
|
boxStylePresets = {
|
|
3423
3426
|
solid: {
|
|
3424
|
-
tl: "
|
|
3425
|
-
tr: "
|
|
3426
|
-
bl: "
|
|
3427
|
-
br: "
|
|
3428
|
-
h: "
|
|
3429
|
-
v: "
|
|
3427
|
+
tl: "┌",
|
|
3428
|
+
tr: "┐",
|
|
3429
|
+
bl: "└",
|
|
3430
|
+
br: "┘",
|
|
3431
|
+
h: "─",
|
|
3432
|
+
v: "│"
|
|
3430
3433
|
},
|
|
3431
3434
|
double: {
|
|
3432
|
-
tl: "
|
|
3433
|
-
tr: "
|
|
3434
|
-
bl: "
|
|
3435
|
-
br: "
|
|
3436
|
-
h: "
|
|
3437
|
-
v: "
|
|
3435
|
+
tl: "╔",
|
|
3436
|
+
tr: "╗",
|
|
3437
|
+
bl: "╚",
|
|
3438
|
+
br: "╝",
|
|
3439
|
+
h: "═",
|
|
3440
|
+
v: "║"
|
|
3438
3441
|
},
|
|
3439
3442
|
doubleSingle: {
|
|
3440
|
-
tl: "
|
|
3441
|
-
tr: "
|
|
3442
|
-
bl: "
|
|
3443
|
-
br: "
|
|
3444
|
-
h: "
|
|
3445
|
-
v: "
|
|
3443
|
+
tl: "╓",
|
|
3444
|
+
tr: "╖",
|
|
3445
|
+
bl: "╙",
|
|
3446
|
+
br: "╜",
|
|
3447
|
+
h: "─",
|
|
3448
|
+
v: "║"
|
|
3446
3449
|
},
|
|
3447
3450
|
doubleSingleRounded: {
|
|
3448
|
-
tl: "
|
|
3449
|
-
tr: "
|
|
3450
|
-
bl: "
|
|
3451
|
-
br: "
|
|
3452
|
-
h: "
|
|
3453
|
-
v: "
|
|
3451
|
+
tl: "╭",
|
|
3452
|
+
tr: "╮",
|
|
3453
|
+
bl: "╰",
|
|
3454
|
+
br: "╯",
|
|
3455
|
+
h: "─",
|
|
3456
|
+
v: "║"
|
|
3454
3457
|
},
|
|
3455
3458
|
singleThick: {
|
|
3456
|
-
tl: "
|
|
3457
|
-
tr: "
|
|
3458
|
-
bl: "
|
|
3459
|
-
br: "
|
|
3460
|
-
h: "
|
|
3461
|
-
v: "
|
|
3459
|
+
tl: "┏",
|
|
3460
|
+
tr: "┓",
|
|
3461
|
+
bl: "┗",
|
|
3462
|
+
br: "┛",
|
|
3463
|
+
h: "━",
|
|
3464
|
+
v: "┃"
|
|
3462
3465
|
},
|
|
3463
3466
|
singleDouble: {
|
|
3464
|
-
tl: "
|
|
3465
|
-
tr: "
|
|
3466
|
-
bl: "
|
|
3467
|
-
br: "
|
|
3468
|
-
h: "
|
|
3469
|
-
v: "
|
|
3467
|
+
tl: "╒",
|
|
3468
|
+
tr: "╕",
|
|
3469
|
+
bl: "╘",
|
|
3470
|
+
br: "╛",
|
|
3471
|
+
h: "═",
|
|
3472
|
+
v: "│"
|
|
3470
3473
|
},
|
|
3471
3474
|
singleDoubleRounded: {
|
|
3472
|
-
tl: "
|
|
3473
|
-
tr: "
|
|
3474
|
-
bl: "
|
|
3475
|
-
br: "
|
|
3476
|
-
h: "
|
|
3477
|
-
v: "
|
|
3475
|
+
tl: "╭",
|
|
3476
|
+
tr: "╮",
|
|
3477
|
+
bl: "╰",
|
|
3478
|
+
br: "╯",
|
|
3479
|
+
h: "═",
|
|
3480
|
+
v: "│"
|
|
3478
3481
|
},
|
|
3479
3482
|
rounded: {
|
|
3480
|
-
tl: "
|
|
3481
|
-
tr: "
|
|
3482
|
-
bl: "
|
|
3483
|
-
br: "
|
|
3484
|
-
h: "
|
|
3485
|
-
v: "
|
|
3483
|
+
tl: "╭",
|
|
3484
|
+
tr: "╮",
|
|
3485
|
+
bl: "╰",
|
|
3486
|
+
br: "╯",
|
|
3487
|
+
h: "─",
|
|
3488
|
+
v: "│"
|
|
3486
3489
|
}
|
|
3487
3490
|
};
|
|
3488
3491
|
defaultStyle = {
|
|
@@ -3502,9 +3505,9 @@ __export(exports_prompt, {
|
|
|
3502
3505
|
prompt: () => prompt,
|
|
3503
3506
|
kCancel: () => kCancel
|
|
3504
3507
|
});
|
|
3505
|
-
import g, { stdin, stdout } from "process";
|
|
3506
|
-
import f from "readline";
|
|
3507
|
-
import { WriteStream } from "tty";
|
|
3508
|
+
import g, { stdin, stdout } from "node:process";
|
|
3509
|
+
import f from "node:readline";
|
|
3510
|
+
import { WriteStream } from "node:tty";
|
|
3508
3511
|
function getDefaultExportFromCjs(x) {
|
|
3509
3512
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
3510
3513
|
}
|
|
@@ -4137,7 +4140,7 @@ var init_prompt = __esm(() => {
|
|
|
4137
4140
|
eD = Object.keys(r.bgColor);
|
|
4138
4141
|
[...tD, ...eD];
|
|
4139
4142
|
iD = sD();
|
|
4140
|
-
v = new Set(["\x1B", "
|
|
4143
|
+
v = new Set(["\x1B", ""]);
|
|
4141
4144
|
y = `${rD}8;;`;
|
|
4142
4145
|
aD = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
4143
4146
|
c = { actions: new Set(aD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
|
|
@@ -4223,7 +4226,7 @@ var init_prompt = __esm(() => {
|
|
|
4223
4226
|
if (this.state === "submit")
|
|
4224
4227
|
return this.value;
|
|
4225
4228
|
if (this.cursor >= this.value.length)
|
|
4226
|
-
return `${this.value}
|
|
4229
|
+
return `${this.value}█`;
|
|
4227
4230
|
const u = this.value.slice(0, this.cursor), [F, ...e$1] = this.value.slice(this.cursor);
|
|
4228
4231
|
return `${u}${e.inverse(F)}${e$1.join("")}`;
|
|
4229
4232
|
}
|
|
@@ -4237,23 +4240,23 @@ var init_prompt = __esm(() => {
|
|
|
4237
4240
|
}
|
|
4238
4241
|
};
|
|
4239
4242
|
V = ce();
|
|
4240
|
-
le = u("
|
|
4241
|
-
L = u("
|
|
4242
|
-
W = u("
|
|
4243
|
-
C = u("
|
|
4243
|
+
le = u("❯", ">");
|
|
4244
|
+
L = u("■", "x");
|
|
4245
|
+
W = u("▲", "x");
|
|
4246
|
+
C = u("✔", "√");
|
|
4244
4247
|
o = u("");
|
|
4245
4248
|
d = u("");
|
|
4246
|
-
k = u("
|
|
4247
|
-
P = u("
|
|
4248
|
-
A = u("
|
|
4249
|
-
T = u("
|
|
4250
|
-
F = u("
|
|
4249
|
+
k = u("●", ">");
|
|
4250
|
+
P = u("○", " ");
|
|
4251
|
+
A = u("◻", "[•]");
|
|
4252
|
+
T = u("◼", "[+]");
|
|
4253
|
+
F = u("◻", "[ ]");
|
|
4251
4254
|
`${e.gray(o)} `;
|
|
4252
4255
|
kCancel = Symbol.for("cancel");
|
|
4253
4256
|
});
|
|
4254
4257
|
|
|
4255
4258
|
// node_modules/consola/dist/index.mjs
|
|
4256
|
-
import g$1 from "process";
|
|
4259
|
+
import g$1 from "node:process";
|
|
4257
4260
|
function b() {
|
|
4258
4261
|
if (globalThis.process?.env)
|
|
4259
4262
|
for (const e2 of f2) {
|
|
@@ -4477,16 +4480,16 @@ var init_dist2 = __esm(() => {
|
|
|
4477
4480
|
};
|
|
4478
4481
|
unicode = isUnicodeSupported();
|
|
4479
4482
|
TYPE_ICONS = {
|
|
4480
|
-
error: s("
|
|
4481
|
-
fatal: s("
|
|
4482
|
-
ready: s("
|
|
4483
|
-
warn: s("
|
|
4484
|
-
info: s("
|
|
4485
|
-
success: s("
|
|
4486
|
-
debug: s("
|
|
4487
|
-
trace: s("
|
|
4488
|
-
fail: s("
|
|
4489
|
-
start: s("
|
|
4483
|
+
error: s("✖", "×"),
|
|
4484
|
+
fatal: s("✖", "×"),
|
|
4485
|
+
ready: s("✔", "√"),
|
|
4486
|
+
warn: s("⚠", "‼"),
|
|
4487
|
+
info: s("ℹ", "i"),
|
|
4488
|
+
success: s("✔", "√"),
|
|
4489
|
+
debug: s("⚙", "D"),
|
|
4490
|
+
trace: s("→", "→"),
|
|
4491
|
+
fail: s("✖", "×"),
|
|
4492
|
+
start: s("◐", "o"),
|
|
4490
4493
|
log: ""
|
|
4491
4494
|
};
|
|
4492
4495
|
FancyReporter = class FancyReporter extends BasicReporter {
|
|
@@ -4587,9 +4590,9 @@ var init_prompt2 = __esm(() => {
|
|
|
4587
4590
|
});
|
|
4588
4591
|
|
|
4589
4592
|
// src/cli/config.ts
|
|
4590
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4591
|
-
import { homedir } from "os";
|
|
4592
|
-
import { dirname, isAbsolute, join, resolve } from "path";
|
|
4593
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4594
|
+
import { homedir } from "node:os";
|
|
4595
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4593
4596
|
function normalizeServiceConfig(service) {
|
|
4594
4597
|
if (!service)
|
|
4595
4598
|
return;
|
|
@@ -4627,12 +4630,15 @@ function getEnvConfig() {
|
|
|
4627
4630
|
const baseUrl = process.env[`TSARR_${upper}_URL`];
|
|
4628
4631
|
const apiKey = process.env[`TSARR_${upper}_API_KEY`];
|
|
4629
4632
|
const timeout = process.env[`TSARR_${upper}_TIMEOUT`];
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4633
|
+
const partial = {};
|
|
4634
|
+
if (baseUrl)
|
|
4635
|
+
partial.baseUrl = baseUrl;
|
|
4636
|
+
if (apiKey)
|
|
4637
|
+
partial.apiKey = apiKey;
|
|
4638
|
+
if (timeout)
|
|
4639
|
+
partial.timeout = Number(timeout);
|
|
4640
|
+
if (Object.keys(partial).length > 0) {
|
|
4641
|
+
services[service] = partial;
|
|
4636
4642
|
}
|
|
4637
4643
|
}
|
|
4638
4644
|
return Object.keys(services).length ? { services } : {};
|
|
@@ -4794,6 +4800,8 @@ function detectFormat(args) {
|
|
|
4794
4800
|
return "quiet";
|
|
4795
4801
|
if (args.json)
|
|
4796
4802
|
return "json";
|
|
4803
|
+
if (args.plain)
|
|
4804
|
+
return "plain";
|
|
4797
4805
|
if (args.table)
|
|
4798
4806
|
return "table";
|
|
4799
4807
|
return process.stdout.isTTY ? "table" : "json";
|
|
@@ -4803,9 +4811,11 @@ function formatOutput(data, options) {
|
|
|
4803
4811
|
return;
|
|
4804
4812
|
}
|
|
4805
4813
|
switch (options.format) {
|
|
4806
|
-
case "json":
|
|
4807
|
-
|
|
4814
|
+
case "json": {
|
|
4815
|
+
const output = options.select ? selectFields(data, options.select) : data;
|
|
4816
|
+
console.log(JSON.stringify(output, null, 2));
|
|
4808
4817
|
break;
|
|
4818
|
+
}
|
|
4809
4819
|
case "quiet": {
|
|
4810
4820
|
const items = Array.isArray(data) ? data : [data];
|
|
4811
4821
|
const field = options.idField ?? "id";
|
|
@@ -4815,12 +4825,44 @@ function formatOutput(data, options) {
|
|
|
4815
4825
|
}
|
|
4816
4826
|
break;
|
|
4817
4827
|
}
|
|
4828
|
+
case "plain":
|
|
4829
|
+
printPlain(data, options.columns);
|
|
4830
|
+
break;
|
|
4818
4831
|
case "table":
|
|
4819
|
-
printTable(data, options.columns);
|
|
4832
|
+
printTable(data, options.columns, options.noHeader);
|
|
4820
4833
|
break;
|
|
4821
4834
|
}
|
|
4822
4835
|
}
|
|
4823
|
-
function
|
|
4836
|
+
function selectFields(data, select) {
|
|
4837
|
+
const fields = select.split(",").map((f3) => f3.trim());
|
|
4838
|
+
if (Array.isArray(data)) {
|
|
4839
|
+
return data.map((item) => pickFields(item, fields));
|
|
4840
|
+
}
|
|
4841
|
+
return pickFields(data, fields);
|
|
4842
|
+
}
|
|
4843
|
+
function pickFields(item, fields) {
|
|
4844
|
+
if (item == null || typeof item !== "object")
|
|
4845
|
+
return {};
|
|
4846
|
+
const result = {};
|
|
4847
|
+
for (const field of fields) {
|
|
4848
|
+
result[field] = item[field];
|
|
4849
|
+
}
|
|
4850
|
+
return result;
|
|
4851
|
+
}
|
|
4852
|
+
function printPlain(data, columns) {
|
|
4853
|
+
const items = Array.isArray(data) ? data : [data];
|
|
4854
|
+
if (items.length === 0)
|
|
4855
|
+
return;
|
|
4856
|
+
const cols = columns ?? Object.keys(items[0] ?? {}).slice(0, 8);
|
|
4857
|
+
if (cols.length === 0)
|
|
4858
|
+
return;
|
|
4859
|
+
console.log(cols.join("\t"));
|
|
4860
|
+
for (const item of items) {
|
|
4861
|
+
const row = cols.map((col) => formatCellPlain(item?.[col])).join("\t");
|
|
4862
|
+
console.log(row);
|
|
4863
|
+
}
|
|
4864
|
+
}
|
|
4865
|
+
function printTable(data, columns, noHeader) {
|
|
4824
4866
|
const items = Array.isArray(data) ? data : [data];
|
|
4825
4867
|
if (items.length === 0) {
|
|
4826
4868
|
console.log("No results.");
|
|
@@ -4829,34 +4871,122 @@ function printTable(data, columns) {
|
|
|
4829
4871
|
const cols = columns ?? Object.keys(items[0] ?? {}).slice(0, 8);
|
|
4830
4872
|
if (cols.length === 0)
|
|
4831
4873
|
return;
|
|
4874
|
+
const formattedRows = items.map((item) => cols.map((col) => formatCell(col, item?.[col])));
|
|
4832
4875
|
const maxColWidth = 60;
|
|
4833
|
-
const
|
|
4834
|
-
|
|
4835
|
-
|
|
4876
|
+
const headers = cols.map((col) => formatHeader(col));
|
|
4877
|
+
const widths = cols.map((_3, i2) => {
|
|
4878
|
+
const values = formattedRows.map((row) => stripAnsi3(row[i2]).length);
|
|
4879
|
+
return Math.min(maxColWidth, Math.max(headers[i2].length, ...values));
|
|
4836
4880
|
});
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4881
|
+
if (!noHeader) {
|
|
4882
|
+
const header = headers.map((h2, i2) => h2.padEnd(widths[i2])).join(" ");
|
|
4883
|
+
console.log(header);
|
|
4884
|
+
console.log(cols.map((_3, i2) => "─".repeat(widths[i2])).join(" "));
|
|
4885
|
+
}
|
|
4886
|
+
for (const row of formattedRows) {
|
|
4887
|
+
const line = row.map((cell, i2) => {
|
|
4888
|
+
const visible = stripAnsi3(cell).length;
|
|
4889
|
+
const truncated = visible > widths[i2] ? truncateWithAnsi(cell, widths[i2]) : cell;
|
|
4890
|
+
const pad = widths[i2] - stripAnsi3(truncated).length;
|
|
4891
|
+
return truncated + " ".repeat(Math.max(0, pad));
|
|
4845
4892
|
}).join(" ");
|
|
4846
|
-
console.log(
|
|
4893
|
+
console.log(line);
|
|
4847
4894
|
}
|
|
4848
4895
|
console.log(`
|
|
4849
4896
|
${items.length} result${items.length === 1 ? "" : "s"}`);
|
|
4850
4897
|
}
|
|
4851
|
-
function
|
|
4898
|
+
function formatHeader(col) {
|
|
4899
|
+
return col.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").toUpperCase();
|
|
4900
|
+
}
|
|
4901
|
+
function formatCell(column, value) {
|
|
4852
4902
|
if (value == null)
|
|
4853
|
-
return "
|
|
4903
|
+
return "—";
|
|
4904
|
+
if (typeof value === "boolean") {
|
|
4905
|
+
return value ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
|
|
4906
|
+
}
|
|
4907
|
+
if (column === "status") {
|
|
4908
|
+
return formatStatus(String(value));
|
|
4909
|
+
}
|
|
4910
|
+
if (typeof value === "number" && (column.toLowerCase().includes("size") || column === "freeSpace" || column === "sizeleft")) {
|
|
4911
|
+
return formatBytes(value);
|
|
4912
|
+
}
|
|
4913
|
+
if (column.toLowerCase().includes("date") || column === "createdAt" || column === "updatedAt") {
|
|
4914
|
+
return formatDate(value);
|
|
4915
|
+
}
|
|
4916
|
+
if (typeof value === "object")
|
|
4917
|
+
return JSON.stringify(value);
|
|
4918
|
+
return String(value);
|
|
4919
|
+
}
|
|
4920
|
+
function formatCellPlain(value) {
|
|
4921
|
+
if (value == null)
|
|
4922
|
+
return "";
|
|
4854
4923
|
if (typeof value === "boolean")
|
|
4855
|
-
return value ? "
|
|
4924
|
+
return value ? "true" : "false";
|
|
4856
4925
|
if (typeof value === "object")
|
|
4857
4926
|
return JSON.stringify(value);
|
|
4858
4927
|
return String(value);
|
|
4859
4928
|
}
|
|
4929
|
+
function formatStatus(status) {
|
|
4930
|
+
const lower = status.toLowerCase();
|
|
4931
|
+
if (lower === "ok" || lower === "available" || lower === "ended" || lower === "continuing") {
|
|
4932
|
+
return `${GREEN}${status}${RESET}`;
|
|
4933
|
+
}
|
|
4934
|
+
if (lower === "fail" || lower === "missing" || lower === "not configured") {
|
|
4935
|
+
return `${RED}${status}${RESET}`;
|
|
4936
|
+
}
|
|
4937
|
+
if (lower === "warning" || lower === "downloading" || lower === "queued") {
|
|
4938
|
+
return `${YELLOW}${status}${RESET}`;
|
|
4939
|
+
}
|
|
4940
|
+
return status;
|
|
4941
|
+
}
|
|
4942
|
+
function formatBytes(bytes) {
|
|
4943
|
+
if (bytes === 0)
|
|
4944
|
+
return "0 B";
|
|
4945
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
4946
|
+
const i2 = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
4947
|
+
const val = bytes / 1024 ** i2;
|
|
4948
|
+
return `${val < 10 ? val.toFixed(1) : Math.round(val)} ${units[i2]}`;
|
|
4949
|
+
}
|
|
4950
|
+
function formatDate(value) {
|
|
4951
|
+
if (typeof value !== "string" && !(value instanceof Date))
|
|
4952
|
+
return String(value);
|
|
4953
|
+
try {
|
|
4954
|
+
const d2 = new Date(value);
|
|
4955
|
+
if (Number.isNaN(d2.getTime()))
|
|
4956
|
+
return String(value);
|
|
4957
|
+
return d2.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
|
|
4958
|
+
} catch {
|
|
4959
|
+
return String(value);
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
function stripAnsi3(str) {
|
|
4963
|
+
return str.replace(ANSI_PATTERN, "");
|
|
4964
|
+
}
|
|
4965
|
+
function truncateWithAnsi(str, maxWidth) {
|
|
4966
|
+
let visible = 0;
|
|
4967
|
+
let i2 = 0;
|
|
4968
|
+
while (i2 < str.length && visible < maxWidth - 1) {
|
|
4969
|
+
if (str[i2] === ESC) {
|
|
4970
|
+
const end = str.indexOf("m", i2);
|
|
4971
|
+
if (end !== -1) {
|
|
4972
|
+
i2 = end + 1;
|
|
4973
|
+
continue;
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
visible++;
|
|
4977
|
+
i2++;
|
|
4978
|
+
}
|
|
4979
|
+
return `${str.slice(0, i2)}…${RESET}`;
|
|
4980
|
+
}
|
|
4981
|
+
var ESC, GREEN, RED, YELLOW, RESET, ANSI_PATTERN;
|
|
4982
|
+
var init_output = __esm(() => {
|
|
4983
|
+
ESC = String.fromCharCode(27);
|
|
4984
|
+
GREEN = `${ESC}[32m`;
|
|
4985
|
+
RED = `${ESC}[31m`;
|
|
4986
|
+
YELLOW = `${ESC}[33m`;
|
|
4987
|
+
RESET = `${ESC}[0m`;
|
|
4988
|
+
ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
4989
|
+
});
|
|
4860
4990
|
|
|
4861
4991
|
// src/cli/commands/service.ts
|
|
4862
4992
|
function buildServiceCommand(serviceName, description, clientFactory, resources) {
|
|
@@ -4872,7 +5002,13 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
4872
5002
|
args: {
|
|
4873
5003
|
json: { type: "boolean", description: "Output as JSON" },
|
|
4874
5004
|
table: { type: "boolean", description: "Output as table" },
|
|
5005
|
+
plain: { type: "boolean", description: "Output as TSV (no colors, for piping)" },
|
|
4875
5006
|
quiet: { type: "boolean", alias: "q", description: "Output IDs only" },
|
|
5007
|
+
"no-header": { type: "boolean", description: "Hide table header row" },
|
|
5008
|
+
select: {
|
|
5009
|
+
type: "string",
|
|
5010
|
+
description: "Cherry-pick fields (comma-separated, JSON mode)"
|
|
5011
|
+
},
|
|
4876
5012
|
yes: { type: "boolean", alias: "y", description: "Skip confirmation prompts" },
|
|
4877
5013
|
...(action.args ?? []).reduce((acc, arg) => {
|
|
4878
5014
|
acc[arg.name] = {
|
|
@@ -4936,7 +5072,9 @@ Run \`tsarr config init\` or set TSARR_${serviceName.toUpperCase()}_API_KEY`);
|
|
|
4936
5072
|
formatOutput(result, {
|
|
4937
5073
|
format,
|
|
4938
5074
|
columns: action.columns,
|
|
4939
|
-
idField: action.idField
|
|
5075
|
+
idField: action.idField,
|
|
5076
|
+
noHeader: !!args["no-header"],
|
|
5077
|
+
select: args.select
|
|
4940
5078
|
});
|
|
4941
5079
|
} catch (error) {
|
|
4942
5080
|
handleError(error, serviceName);
|
|
@@ -4983,6 +5121,7 @@ var init_service = __esm(() => {
|
|
|
4983
5121
|
init_dist2();
|
|
4984
5122
|
init_errors();
|
|
4985
5123
|
init_config();
|
|
5124
|
+
init_output();
|
|
4986
5125
|
init_prompt2();
|
|
4987
5126
|
});
|
|
4988
5127
|
|
|
@@ -5426,7 +5565,7 @@ var separatorArrayExplode2 = (style) => {
|
|
|
5426
5565
|
return "";
|
|
5427
5566
|
}
|
|
5428
5567
|
if (typeof value === "object") {
|
|
5429
|
-
throw new Error("Deeply-nested arrays/objects aren
|
|
5568
|
+
throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
5430
5569
|
}
|
|
5431
5570
|
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
5432
5571
|
}, serializeObjectParam2 = ({
|
|
@@ -7577,6 +7716,10 @@ class SonarrClient {
|
|
|
7577
7716
|
updateConfig(newConfig) {
|
|
7578
7717
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
7579
7718
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
7719
|
+
client2.setConfig({
|
|
7720
|
+
baseUrl: this.clientConfig.getBaseUrl(),
|
|
7721
|
+
headers: this.clientConfig.getHeaders()
|
|
7722
|
+
});
|
|
7580
7723
|
return this.clientConfig.config;
|
|
7581
7724
|
}
|
|
7582
7725
|
}
|
|
@@ -7996,7 +8139,7 @@ var separatorArrayExplode3 = (style) => {
|
|
|
7996
8139
|
return "";
|
|
7997
8140
|
}
|
|
7998
8141
|
if (typeof value === "object") {
|
|
7999
|
-
throw new Error("Deeply-nested arrays/objects aren
|
|
8142
|
+
throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
8000
8143
|
}
|
|
8001
8144
|
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
8002
8145
|
}, serializeObjectParam3 = ({
|
|
@@ -10091,6 +10234,10 @@ class LidarrClient {
|
|
|
10091
10234
|
updateConfig(newConfig) {
|
|
10092
10235
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
10093
10236
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
10237
|
+
client3.setConfig({
|
|
10238
|
+
baseUrl: this.clientConfig.getBaseUrl(),
|
|
10239
|
+
headers: this.clientConfig.getHeaders()
|
|
10240
|
+
});
|
|
10094
10241
|
return this.clientConfig.config;
|
|
10095
10242
|
}
|
|
10096
10243
|
}
|
|
@@ -10132,6 +10279,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
10132
10279
|
description: "Search for artists",
|
|
10133
10280
|
args: [{ name: "term", description: "Search term", required: true }],
|
|
10134
10281
|
columns: ["foreignArtistId", "artistName", "overview"],
|
|
10282
|
+
idField: "foreignArtistId",
|
|
10135
10283
|
run: (c3, a2) => c3.searchArtists(a2.term)
|
|
10136
10284
|
},
|
|
10137
10285
|
{
|
|
@@ -10240,6 +10388,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
10240
10388
|
description: "Search for albums",
|
|
10241
10389
|
args: [{ name: "term", description: "Search term", required: true }],
|
|
10242
10390
|
columns: ["foreignAlbumId", "title", "artistId"],
|
|
10391
|
+
idField: "foreignAlbumId",
|
|
10243
10392
|
run: (c3, a2) => c3.searchAlbums(a2.term)
|
|
10244
10393
|
}
|
|
10245
10394
|
]
|
|
@@ -10520,7 +10669,7 @@ var separatorArrayExplode4 = (style) => {
|
|
|
10520
10669
|
return "";
|
|
10521
10670
|
}
|
|
10522
10671
|
if (typeof value === "object") {
|
|
10523
|
-
throw new Error("Deeply-nested arrays/objects aren
|
|
10672
|
+
throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
10524
10673
|
}
|
|
10525
10674
|
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
10526
10675
|
}, serializeObjectParam4 = ({
|
|
@@ -12561,6 +12710,10 @@ class ReadarrClient {
|
|
|
12561
12710
|
updateConfig(newConfig) {
|
|
12562
12711
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
12563
12712
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
12713
|
+
client4.setConfig({
|
|
12714
|
+
baseUrl: this.clientConfig.getBaseUrl(),
|
|
12715
|
+
headers: this.clientConfig.getHeaders()
|
|
12716
|
+
});
|
|
12564
12717
|
return this.clientConfig.config;
|
|
12565
12718
|
}
|
|
12566
12719
|
}
|
|
@@ -12987,7 +13140,7 @@ var separatorArrayExplode5 = (style) => {
|
|
|
12987
13140
|
return "";
|
|
12988
13141
|
}
|
|
12989
13142
|
if (typeof value === "object") {
|
|
12990
|
-
throw new Error("Deeply-nested arrays/objects aren
|
|
13143
|
+
throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
12991
13144
|
}
|
|
12992
13145
|
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
12993
13146
|
}, serializeObjectParam5 = ({
|
|
@@ -14359,6 +14512,10 @@ class ProwlarrClient {
|
|
|
14359
14512
|
updateConfig(newConfig) {
|
|
14360
14513
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
14361
14514
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
14515
|
+
client5.setConfig({
|
|
14516
|
+
baseUrl: this.clientConfig.getBaseUrl(),
|
|
14517
|
+
headers: this.clientConfig.getHeaders()
|
|
14518
|
+
});
|
|
14362
14519
|
return this.clientConfig.config;
|
|
14363
14520
|
}
|
|
14364
14521
|
}
|
|
@@ -14710,7 +14867,7 @@ var separatorArrayExplode6 = (style) => {
|
|
|
14710
14867
|
return "";
|
|
14711
14868
|
}
|
|
14712
14869
|
if (typeof value === "object") {
|
|
14713
|
-
throw new Error("Deeply-nested arrays/objects aren
|
|
14870
|
+
throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
14714
14871
|
}
|
|
14715
14872
|
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
14716
14873
|
}, serializeObjectParam6 = ({
|
|
@@ -15511,11 +15668,7 @@ var getBadges = (options) => (options?.client ?? client6).get({
|
|
|
15511
15668
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15512
15669
|
url: "/api/system/logs",
|
|
15513
15670
|
...options
|
|
15514
|
-
}), getSystemPing = (options) => (options?.client ?? client6).get({
|
|
15515
|
-
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15516
|
-
url: "/api/system/ping",
|
|
15517
|
-
...options
|
|
15518
|
-
}), getSystemReleases = (options) => (options?.client ?? client6).get({
|
|
15671
|
+
}), getSystemPing = (options) => (options?.client ?? client6).get({ url: "/api/system/ping", ...options }), getSystemReleases = (options) => (options?.client ?? client6).get({
|
|
15519
15672
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15520
15673
|
url: "/api/system/releases",
|
|
15521
15674
|
...options
|
|
@@ -16042,6 +16195,43 @@ var exports_doctor = {};
|
|
|
16042
16195
|
__export(exports_doctor, {
|
|
16043
16196
|
doctor: () => doctor
|
|
16044
16197
|
});
|
|
16198
|
+
function classifyError(error) {
|
|
16199
|
+
if (!(error instanceof Error))
|
|
16200
|
+
return "Unknown error";
|
|
16201
|
+
const msg = error.message;
|
|
16202
|
+
const cause = error.cause;
|
|
16203
|
+
if (cause?.code === "ECONNREFUSED" || msg.includes("ECONNREFUSED")) {
|
|
16204
|
+
return "Connection refused - is the service running?";
|
|
16205
|
+
}
|
|
16206
|
+
if (cause?.code === "ENOTFOUND" || msg.includes("ENOTFOUND")) {
|
|
16207
|
+
return "Host not found - check the URL";
|
|
16208
|
+
}
|
|
16209
|
+
if (cause?.code === "ECONNRESET" || msg.includes("ECONNRESET")) {
|
|
16210
|
+
return "Connection reset - service may have crashed";
|
|
16211
|
+
}
|
|
16212
|
+
if (cause?.code === "ETIMEDOUT" || msg.includes("ETIMEDOUT") || msg.includes("timed out")) {
|
|
16213
|
+
return "Connection timed out - service may be unreachable";
|
|
16214
|
+
}
|
|
16215
|
+
if (msg.includes("fetch failed") || msg.includes("Failed to fetch")) {
|
|
16216
|
+
return `Service unreachable - ${cause?.message ?? "check URL and network"}`;
|
|
16217
|
+
}
|
|
16218
|
+
if (msg.includes("401") || msg.includes("Unauthorized")) {
|
|
16219
|
+
return "Authentication failed (401) - check your API key";
|
|
16220
|
+
}
|
|
16221
|
+
if (msg.includes("403") || msg.includes("Forbidden")) {
|
|
16222
|
+
return "Access denied (403) - check your API key permissions";
|
|
16223
|
+
}
|
|
16224
|
+
if (msg.includes("502") || msg.includes("Bad Gateway")) {
|
|
16225
|
+
return "Bad gateway (502) - reverse proxy or service issue";
|
|
16226
|
+
}
|
|
16227
|
+
if (msg.includes("503") || msg.includes("Service Unavailable")) {
|
|
16228
|
+
return "Service unavailable (503) - service may be starting up";
|
|
16229
|
+
}
|
|
16230
|
+
if (msg.includes("CERT") || msg.includes("certificate") || msg.includes("SSL")) {
|
|
16231
|
+
return "SSL/TLS certificate error - check HTTPS configuration";
|
|
16232
|
+
}
|
|
16233
|
+
return msg;
|
|
16234
|
+
}
|
|
16045
16235
|
function extractVersion(service, status) {
|
|
16046
16236
|
const data = status?.data ?? status;
|
|
16047
16237
|
if (typeof data === "string") {
|
|
@@ -16063,6 +16253,7 @@ var init_doctor = __esm(() => {
|
|
|
16063
16253
|
init_readarr2();
|
|
16064
16254
|
init_sonarr2();
|
|
16065
16255
|
init_config();
|
|
16256
|
+
init_output();
|
|
16066
16257
|
clientFactories = {
|
|
16067
16258
|
radarr: (c3) => new RadarrClient(c3),
|
|
16068
16259
|
sonarr: (c3) => new SonarrClient(c3),
|
|
@@ -16079,7 +16270,9 @@ var init_doctor = __esm(() => {
|
|
|
16079
16270
|
args: {
|
|
16080
16271
|
json: { type: "boolean", description: "Output as JSON" },
|
|
16081
16272
|
table: { type: "boolean", description: "Output as table" },
|
|
16082
|
-
|
|
16273
|
+
plain: { type: "boolean", description: "Output as TSV (no colors, for piping)" },
|
|
16274
|
+
quiet: { type: "boolean", alias: "q", description: "Output service names only" },
|
|
16275
|
+
select: { type: "string", description: "Cherry-pick fields (comma-separated, JSON mode)" }
|
|
16083
16276
|
},
|
|
16084
16277
|
async run({ args }) {
|
|
16085
16278
|
const format = detectFormat(args);
|
|
@@ -16126,24 +16319,28 @@ var init_doctor = __esm(() => {
|
|
|
16126
16319
|
baseUrl: svcConfig.baseUrl
|
|
16127
16320
|
});
|
|
16128
16321
|
} catch (error) {
|
|
16129
|
-
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
16130
16322
|
results.push({
|
|
16131
16323
|
service,
|
|
16132
16324
|
configured: true,
|
|
16133
16325
|
status: "fail",
|
|
16134
16326
|
baseUrl: svcConfig.baseUrl,
|
|
16135
|
-
error:
|
|
16327
|
+
error: classifyError(error)
|
|
16136
16328
|
});
|
|
16137
16329
|
}
|
|
16138
16330
|
}
|
|
16331
|
+
const hadFailure = !hasAny || results.some((r3) => r3.status === "fail");
|
|
16139
16332
|
if (!hasAny && format === "table") {
|
|
16140
16333
|
consola.warn("\nNo services configured. Run `tsarr config init` to set up.");
|
|
16141
16334
|
}
|
|
16142
16335
|
formatOutput(results, {
|
|
16143
16336
|
format,
|
|
16144
16337
|
columns: ["service", "status", "version", "baseUrl", "error"],
|
|
16145
|
-
idField: "service"
|
|
16338
|
+
idField: "service",
|
|
16339
|
+
select: args.select
|
|
16146
16340
|
});
|
|
16341
|
+
if (hadFailure) {
|
|
16342
|
+
process.exitCode = 1;
|
|
16343
|
+
}
|
|
16147
16344
|
}
|
|
16148
16345
|
});
|
|
16149
16346
|
});
|
|
@@ -16216,7 +16413,7 @@ var init_config2 = __esm(() => {
|
|
|
16216
16413
|
consola.success(`Connected to ${service} v${version}`);
|
|
16217
16414
|
}
|
|
16218
16415
|
} catch {
|
|
16219
|
-
consola.warn(`Could not connect to ${service}
|
|
16416
|
+
consola.warn(`Could not connect to ${service} — config saved anyway.`);
|
|
16220
16417
|
}
|
|
16221
16418
|
}
|
|
16222
16419
|
const location = await promptSelect("Save config to:", [
|
|
@@ -16249,7 +16446,8 @@ var init_config2 = __esm(() => {
|
|
|
16249
16446
|
},
|
|
16250
16447
|
async run({ args }) {
|
|
16251
16448
|
setConfigValue(args.key, args.value, !args.local);
|
|
16252
|
-
|
|
16449
|
+
const displayValue = /\b(apiKey|apikey|token|secret|password)\b/i.test(args.key) ? "*****" : args.value;
|
|
16450
|
+
consola.success(`Set ${args.key} = ${displayValue}`);
|
|
16253
16451
|
}
|
|
16254
16452
|
});
|
|
16255
16453
|
configGet = defineCommand({
|
|
@@ -16277,7 +16475,14 @@ var init_config2 = __esm(() => {
|
|
|
16277
16475
|
},
|
|
16278
16476
|
async run() {
|
|
16279
16477
|
const config = loadConfig();
|
|
16280
|
-
|
|
16478
|
+
const redacted = JSON.parse(JSON.stringify(config));
|
|
16479
|
+
if (redacted.services) {
|
|
16480
|
+
for (const svc of Object.values(redacted.services)) {
|
|
16481
|
+
if (svc?.apiKey)
|
|
16482
|
+
svc.apiKey = "*****";
|
|
16483
|
+
}
|
|
16484
|
+
}
|
|
16485
|
+
console.log(JSON.stringify(redacted, null, 2));
|
|
16281
16486
|
}
|
|
16282
16487
|
});
|
|
16283
16488
|
config = defineCommand({
|
|
@@ -16404,7 +16609,7 @@ function generateFishCompletion() {
|
|
|
16404
16609
|
return `complete -c tsarr -n "__fish_seen_subcommand_from ${svc}; and not __fish_seen_subcommand_from ${res}" -a "${res}"`;
|
|
16405
16610
|
}).join(`
|
|
16406
16611
|
`);
|
|
16407
|
-
const actionCompletions = Object.entries(SERVICE_COMMANDS).flatMap(([
|
|
16612
|
+
const actionCompletions = Object.entries(SERVICE_COMMANDS).flatMap(([svc, resources7]) => Object.entries(resources7).map(([res, actions]) => `complete -c tsarr -n "__fish_seen_subcommand_from ${svc}; and __fish_seen_subcommand_from ${res}; and not __fish_seen_subcommand_from ${actions.join(" ")}" -a "${actions.join(" ")}"`)).join(`
|
|
16408
16613
|
`);
|
|
16409
16614
|
return `# Fish completions for tsarr
|
|
16410
16615
|
set -l services ${services}
|
|
@@ -16516,13 +16721,13 @@ var init_completions = __esm(() => {
|
|
|
16516
16721
|
|
|
16517
16722
|
// src/cli/index.ts
|
|
16518
16723
|
init_dist();
|
|
16519
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
16724
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
16520
16725
|
var { version } = JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf-8"));
|
|
16521
16726
|
var main = defineCommand({
|
|
16522
16727
|
meta: {
|
|
16523
16728
|
name: "tsarr",
|
|
16524
16729
|
version,
|
|
16525
|
-
description: "CLI for Servarr APIs (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, Bazarr)"
|
|
16730
|
+
description: "Type-safe CLI for Servarr APIs (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, Bazarr)"
|
|
16526
16731
|
},
|
|
16527
16732
|
subCommands: {
|
|
16528
16733
|
radarr: () => Promise.resolve().then(() => (init_radarr3(), exports_radarr3)).then((m2) => m2.radarr),
|