tsarr 2.0.0 → 2.2.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 +4 -1
- package/dist/cli/commands/doctor.d.ts +15 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/lidarr.d.ts.map +1 -1
- package/dist/cli/commands/radarr.d.ts.map +1 -1
- package/dist/cli/commands/readarr.d.ts.map +1 -1
- package/dist/cli/commands/service.d.ts.map +1 -1
- package/dist/cli/commands/sonarr.d.ts.map +1 -1
- package/dist/cli/config.d.ts +1 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/index.js +572 -138
- package/dist/clients/bazarr.d.ts.map +1 -1
- package/dist/clients/bazarr.js +73 -64
- package/dist/clients/readarr.d.ts +3 -3
- package/dist/clients/readarr.d.ts.map +1 -1
- package/dist/generated/bazarr/client.gen.d.ts.map +1 -1
- package/dist/generated/bazarr/types.gen.d.ts +80 -80
- package/dist/generated/bazarr/types.gen.d.ts.map +1 -1
- package/dist/index.js +13 -13
- package/dist/tsarr-2.2.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/tsarr-2.0.0.tgz +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -4540,15 +4540,82 @@ ${indent}`);
|
|
|
4540
4540
|
consola = createConsola2();
|
|
4541
4541
|
});
|
|
4542
4542
|
|
|
4543
|
+
// src/cli/prompt.ts
|
|
4544
|
+
async function promptIfMissing(value, message) {
|
|
4545
|
+
if (value)
|
|
4546
|
+
return value;
|
|
4547
|
+
if (!process.stdin.isTTY) {
|
|
4548
|
+
throw new Error(`Missing required argument. Use --help for usage info.`);
|
|
4549
|
+
}
|
|
4550
|
+
const result = await consola.prompt(message, { type: "text" });
|
|
4551
|
+
if (typeof result !== "string" || !result.trim()) {
|
|
4552
|
+
throw new Error("No input provided.");
|
|
4553
|
+
}
|
|
4554
|
+
return result.trim();
|
|
4555
|
+
}
|
|
4556
|
+
async function promptConfirm(message, skipPrompt = false) {
|
|
4557
|
+
if (skipPrompt)
|
|
4558
|
+
return true;
|
|
4559
|
+
if (!process.stdin.isTTY) {
|
|
4560
|
+
throw new Error("Destructive action requires confirmation. Use --yes to skip in non-interactive mode.");
|
|
4561
|
+
}
|
|
4562
|
+
const result = await consola.prompt(message, { type: "confirm" });
|
|
4563
|
+
return result === true;
|
|
4564
|
+
}
|
|
4565
|
+
async function promptSelect(message, options) {
|
|
4566
|
+
if (!process.stdin.isTTY) {
|
|
4567
|
+
throw new Error("Interactive selection requires a TTY.");
|
|
4568
|
+
}
|
|
4569
|
+
const result = await consola.prompt(message, {
|
|
4570
|
+
type: "select",
|
|
4571
|
+
options: options.map((o3) => ({ label: o3.label, value: o3.value }))
|
|
4572
|
+
});
|
|
4573
|
+
return result;
|
|
4574
|
+
}
|
|
4575
|
+
async function promptMultiSelect(message, options) {
|
|
4576
|
+
if (!process.stdin.isTTY) {
|
|
4577
|
+
throw new Error("Interactive selection requires a TTY.");
|
|
4578
|
+
}
|
|
4579
|
+
const result = await consola.prompt(message, {
|
|
4580
|
+
type: "multiselect",
|
|
4581
|
+
options: options.map((o3) => ({ label: o3.label, value: o3.value }))
|
|
4582
|
+
});
|
|
4583
|
+
return result;
|
|
4584
|
+
}
|
|
4585
|
+
var init_prompt2 = __esm(() => {
|
|
4586
|
+
init_dist2();
|
|
4587
|
+
});
|
|
4588
|
+
|
|
4543
4589
|
// src/cli/config.ts
|
|
4544
4590
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4545
4591
|
import { homedir } from "os";
|
|
4546
|
-
import { join, resolve } from "path";
|
|
4592
|
+
import { dirname, isAbsolute, join, resolve } from "path";
|
|
4593
|
+
function normalizeServiceConfig(service) {
|
|
4594
|
+
if (!service)
|
|
4595
|
+
return;
|
|
4596
|
+
const normalized = {
|
|
4597
|
+
baseUrl: service.baseUrl ?? "",
|
|
4598
|
+
apiKey: service.apiKey ?? "",
|
|
4599
|
+
...service.apiKeyFile ? { apiKeyFile: service.apiKeyFile } : {}
|
|
4600
|
+
};
|
|
4601
|
+
const timeout = typeof service.timeout === "string" ? Number(service.timeout) : service.timeout;
|
|
4602
|
+
if (typeof timeout === "number" && Number.isFinite(timeout)) {
|
|
4603
|
+
normalized.timeout = timeout;
|
|
4604
|
+
}
|
|
4605
|
+
return normalized;
|
|
4606
|
+
}
|
|
4607
|
+
function normalizeConfig(config) {
|
|
4608
|
+
const services = Object.fromEntries(Object.entries(config.services ?? {}).map(([name, service]) => [name, normalizeServiceConfig(service)]).filter(([, service]) => service != null));
|
|
4609
|
+
return {
|
|
4610
|
+
...config,
|
|
4611
|
+
...Object.keys(services).length > 0 ? { services } : {}
|
|
4612
|
+
};
|
|
4613
|
+
}
|
|
4547
4614
|
function readJsonFile(path) {
|
|
4548
4615
|
if (!existsSync(path))
|
|
4549
4616
|
return {};
|
|
4550
4617
|
try {
|
|
4551
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
4618
|
+
return normalizeConfig(JSON.parse(readFileSync(path, "utf-8")));
|
|
4552
4619
|
} catch {
|
|
4553
4620
|
return {};
|
|
4554
4621
|
}
|
|
@@ -4583,18 +4650,25 @@ function findLocalConfigPath() {
|
|
|
4583
4650
|
}
|
|
4584
4651
|
}
|
|
4585
4652
|
function loadConfig() {
|
|
4586
|
-
const base = { services: {} };
|
|
4587
4653
|
const global = readJsonFile(GLOBAL_CONFIG_PATH);
|
|
4588
4654
|
const localPath = findLocalConfigPath();
|
|
4589
4655
|
const local = localPath ? readJsonFile(localPath) : {};
|
|
4590
4656
|
const env2 = getEnvConfig();
|
|
4657
|
+
const allServiceNames = new Set([
|
|
4658
|
+
...Object.keys(global.services ?? {}),
|
|
4659
|
+
...Object.keys(local.services ?? {}),
|
|
4660
|
+
...Object.keys(env2.services ?? {})
|
|
4661
|
+
]);
|
|
4662
|
+
const services = {};
|
|
4663
|
+
for (const name of allServiceNames) {
|
|
4664
|
+
services[name] = {
|
|
4665
|
+
...global.services?.[name],
|
|
4666
|
+
...local.services?.[name],
|
|
4667
|
+
...env2.services?.[name]
|
|
4668
|
+
};
|
|
4669
|
+
}
|
|
4591
4670
|
const merged = {
|
|
4592
|
-
services
|
|
4593
|
-
...base.services,
|
|
4594
|
-
...global.services,
|
|
4595
|
-
...local.services,
|
|
4596
|
-
...env2.services
|
|
4597
|
-
},
|
|
4671
|
+
services,
|
|
4598
4672
|
defaults: {
|
|
4599
4673
|
...global.defaults,
|
|
4600
4674
|
...local.defaults
|
|
@@ -4602,14 +4676,51 @@ function loadConfig() {
|
|
|
4602
4676
|
};
|
|
4603
4677
|
return merged;
|
|
4604
4678
|
}
|
|
4679
|
+
function resolveConfigRelativePath(filePath, configPath) {
|
|
4680
|
+
if (isAbsolute(filePath) || !configPath) {
|
|
4681
|
+
return filePath;
|
|
4682
|
+
}
|
|
4683
|
+
return resolve(dirname(configPath), filePath);
|
|
4684
|
+
}
|
|
4685
|
+
function getResolvedApiKeyFilePath(serviceName, service, localPath, local, global) {
|
|
4686
|
+
if (!service.apiKeyFile)
|
|
4687
|
+
return;
|
|
4688
|
+
if (local.services?.[serviceName]?.apiKeyFile) {
|
|
4689
|
+
return resolveConfigRelativePath(service.apiKeyFile, localPath);
|
|
4690
|
+
}
|
|
4691
|
+
if (global.services?.[serviceName]?.apiKeyFile) {
|
|
4692
|
+
return resolveConfigRelativePath(service.apiKeyFile, GLOBAL_CONFIG_PATH);
|
|
4693
|
+
}
|
|
4694
|
+
return service.apiKeyFile;
|
|
4695
|
+
}
|
|
4696
|
+
function readApiKeyFile(filePath) {
|
|
4697
|
+
if (!existsSync(filePath)) {
|
|
4698
|
+
throw new Error(`API key file not found: ${filePath}`);
|
|
4699
|
+
}
|
|
4700
|
+
try {
|
|
4701
|
+
return readFileSync(filePath, "utf-8").trimEnd();
|
|
4702
|
+
} catch (err) {
|
|
4703
|
+
throw new Error(`Failed to read API key file: ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4605
4706
|
function getServiceConfig(serviceName) {
|
|
4707
|
+
const global = readJsonFile(GLOBAL_CONFIG_PATH);
|
|
4708
|
+
const localPath = findLocalConfigPath();
|
|
4709
|
+
const local = localPath ? readJsonFile(localPath) : {};
|
|
4606
4710
|
const config = loadConfig();
|
|
4607
4711
|
const service = config.services[serviceName];
|
|
4608
|
-
if (!service?.baseUrl
|
|
4712
|
+
if (!service?.baseUrl)
|
|
4713
|
+
return null;
|
|
4714
|
+
let apiKey = service.apiKey;
|
|
4715
|
+
const apiKeyFilePath = getResolvedApiKeyFilePath(serviceName, service, localPath, local, global);
|
|
4716
|
+
if (!apiKey && apiKeyFilePath) {
|
|
4717
|
+
apiKey = readApiKeyFile(apiKeyFilePath);
|
|
4718
|
+
}
|
|
4719
|
+
if (!apiKey)
|
|
4609
4720
|
return null;
|
|
4610
4721
|
return {
|
|
4611
4722
|
baseUrl: service.baseUrl,
|
|
4612
|
-
apiKey
|
|
4723
|
+
apiKey,
|
|
4613
4724
|
...service.timeout ? { timeout: service.timeout } : {}
|
|
4614
4725
|
};
|
|
4615
4726
|
}
|
|
@@ -4646,13 +4757,23 @@ function setConfigValue(key, value, global = true) {
|
|
|
4646
4757
|
}
|
|
4647
4758
|
current = current[parts[i2]];
|
|
4648
4759
|
}
|
|
4649
|
-
current[parts[parts.length - 1]] = value;
|
|
4760
|
+
current[parts[parts.length - 1]] = parseConfigValue(key, value);
|
|
4650
4761
|
if (global) {
|
|
4651
4762
|
saveGlobalConfig(config);
|
|
4652
4763
|
} else {
|
|
4653
4764
|
saveLocalConfig(config);
|
|
4654
4765
|
}
|
|
4655
4766
|
}
|
|
4767
|
+
function parseConfigValue(key, value) {
|
|
4768
|
+
if (key.endsWith(".timeout")) {
|
|
4769
|
+
const timeout = Number(value);
|
|
4770
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
4771
|
+
throw new Error(`Invalid timeout value "${value}". Expected a non-negative number.`);
|
|
4772
|
+
}
|
|
4773
|
+
return timeout;
|
|
4774
|
+
}
|
|
4775
|
+
return value;
|
|
4776
|
+
}
|
|
4656
4777
|
function loadScopedConfig(scope) {
|
|
4657
4778
|
if (scope === "global") {
|
|
4658
4779
|
return readJsonFile(GLOBAL_CONFIG_PATH);
|
|
@@ -4737,52 +4858,6 @@ function formatCell(value) {
|
|
|
4737
4858
|
return String(value);
|
|
4738
4859
|
}
|
|
4739
4860
|
|
|
4740
|
-
// src/cli/prompt.ts
|
|
4741
|
-
async function promptIfMissing(value, message) {
|
|
4742
|
-
if (value)
|
|
4743
|
-
return value;
|
|
4744
|
-
if (!process.stdin.isTTY) {
|
|
4745
|
-
throw new Error(`Missing required argument. Use --help for usage info.`);
|
|
4746
|
-
}
|
|
4747
|
-
const result = await consola.prompt(message, { type: "text" });
|
|
4748
|
-
if (typeof result !== "string" || !result.trim()) {
|
|
4749
|
-
throw new Error("No input provided.");
|
|
4750
|
-
}
|
|
4751
|
-
return result.trim();
|
|
4752
|
-
}
|
|
4753
|
-
async function promptConfirm(message, skipPrompt = false) {
|
|
4754
|
-
if (skipPrompt)
|
|
4755
|
-
return true;
|
|
4756
|
-
if (!process.stdin.isTTY) {
|
|
4757
|
-
throw new Error("Destructive action requires confirmation. Use --yes to skip in non-interactive mode.");
|
|
4758
|
-
}
|
|
4759
|
-
const result = await consola.prompt(message, { type: "confirm" });
|
|
4760
|
-
return result === true;
|
|
4761
|
-
}
|
|
4762
|
-
async function promptSelect(message, options) {
|
|
4763
|
-
if (!process.stdin.isTTY) {
|
|
4764
|
-
throw new Error("Interactive selection requires a TTY.");
|
|
4765
|
-
}
|
|
4766
|
-
const result = await consola.prompt(message, {
|
|
4767
|
-
type: "select",
|
|
4768
|
-
options: options.map((o3) => ({ label: o3.label, value: o3.value }))
|
|
4769
|
-
});
|
|
4770
|
-
return result;
|
|
4771
|
-
}
|
|
4772
|
-
async function promptMultiSelect(message, options) {
|
|
4773
|
-
if (!process.stdin.isTTY) {
|
|
4774
|
-
throw new Error("Interactive selection requires a TTY.");
|
|
4775
|
-
}
|
|
4776
|
-
const result = await consola.prompt(message, {
|
|
4777
|
-
type: "multiselect",
|
|
4778
|
-
options: options.map((o3) => ({ label: o3.label, value: o3.value }))
|
|
4779
|
-
});
|
|
4780
|
-
return result;
|
|
4781
|
-
}
|
|
4782
|
-
var init_prompt2 = __esm(() => {
|
|
4783
|
-
init_dist2();
|
|
4784
|
-
});
|
|
4785
|
-
|
|
4786
4861
|
// src/cli/commands/service.ts
|
|
4787
4862
|
function buildServiceCommand(serviceName, description, clientFactory, resources) {
|
|
4788
4863
|
const subCommands = {};
|
|
@@ -4851,6 +4926,9 @@ Run \`tsarr config init\` or set TSARR_${serviceName.toUpperCase()}_API_KEY`);
|
|
|
4851
4926
|
process.exit(1);
|
|
4852
4927
|
}
|
|
4853
4928
|
let result = raw?.data !== undefined ? raw.data : raw;
|
|
4929
|
+
if (result != null && typeof result === "object" && "data" in result && Object.keys(result).length === 1) {
|
|
4930
|
+
result = result.data;
|
|
4931
|
+
}
|
|
4854
4932
|
if (result?.records !== undefined && Array.isArray(result.records)) {
|
|
4855
4933
|
result = result.records;
|
|
4856
4934
|
}
|
|
@@ -4916,6 +4994,7 @@ __export(exports_radarr3, {
|
|
|
4916
4994
|
var resources, radarr;
|
|
4917
4995
|
var init_radarr3 = __esm(() => {
|
|
4918
4996
|
init_radarr2();
|
|
4997
|
+
init_prompt2();
|
|
4919
4998
|
init_service();
|
|
4920
4999
|
resources = [
|
|
4921
5000
|
{
|
|
@@ -4942,6 +5021,79 @@ var init_radarr3 = __esm(() => {
|
|
|
4942
5021
|
idField: "tmdbId",
|
|
4943
5022
|
run: (c3, a2) => c3.searchMovies(a2.term)
|
|
4944
5023
|
},
|
|
5024
|
+
{
|
|
5025
|
+
name: "add",
|
|
5026
|
+
description: "Search and add a movie",
|
|
5027
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
5028
|
+
run: async (c3, a2) => {
|
|
5029
|
+
const searchResult = await c3.searchMovies(a2.term);
|
|
5030
|
+
const results = searchResult?.data ?? searchResult;
|
|
5031
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
5032
|
+
throw new Error("No movies found.");
|
|
5033
|
+
}
|
|
5034
|
+
const movieId = await promptSelect("Select a movie:", results.map((m2) => ({ label: `${m2.title} (${m2.year})`, value: String(m2.tmdbId) })));
|
|
5035
|
+
const movie = results.find((m2) => String(m2.tmdbId) === movieId);
|
|
5036
|
+
if (!movie) {
|
|
5037
|
+
throw new Error("Selected movie was not found in the search results.");
|
|
5038
|
+
}
|
|
5039
|
+
const profilesResult = await c3.getQualityProfiles();
|
|
5040
|
+
const profiles = profilesResult?.data ?? profilesResult;
|
|
5041
|
+
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
5042
|
+
throw new Error("No quality profiles found. Configure one in Radarr first.");
|
|
5043
|
+
}
|
|
5044
|
+
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
5045
|
+
const foldersResult = await c3.getRootFolders();
|
|
5046
|
+
const folders = foldersResult?.data ?? foldersResult;
|
|
5047
|
+
if (!Array.isArray(folders) || folders.length === 0) {
|
|
5048
|
+
throw new Error("No root folders found. Configure one in Radarr first.");
|
|
5049
|
+
}
|
|
5050
|
+
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
5051
|
+
const confirmed = await promptConfirm(`Add "${movie.title} (${movie.year})"?`, !!a2.yes);
|
|
5052
|
+
if (!confirmed)
|
|
5053
|
+
throw new Error("Cancelled.");
|
|
5054
|
+
return c3.addMovie({
|
|
5055
|
+
...movie,
|
|
5056
|
+
qualityProfileId: Number(profileId),
|
|
5057
|
+
rootFolderPath,
|
|
5058
|
+
monitored: true,
|
|
5059
|
+
addOptions: { searchForMovie: true }
|
|
5060
|
+
});
|
|
5061
|
+
}
|
|
5062
|
+
},
|
|
5063
|
+
{
|
|
5064
|
+
name: "edit",
|
|
5065
|
+
description: "Edit a movie",
|
|
5066
|
+
args: [
|
|
5067
|
+
{ name: "id", description: "Movie ID", required: true, type: "number" },
|
|
5068
|
+
{ name: "monitored", description: "Set monitored (true/false)" },
|
|
5069
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
5070
|
+
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
5071
|
+
],
|
|
5072
|
+
run: async (c3, a2) => {
|
|
5073
|
+
const result = await c3.getMovie(a2.id);
|
|
5074
|
+
const movie = result?.data ?? result;
|
|
5075
|
+
const updates = { ...movie };
|
|
5076
|
+
if (a2.monitored !== undefined)
|
|
5077
|
+
updates.monitored = a2.monitored === "true";
|
|
5078
|
+
if (a2["quality-profile-id"] !== undefined)
|
|
5079
|
+
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
5080
|
+
if (a2.tags !== undefined)
|
|
5081
|
+
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
5082
|
+
return c3.updateMovie(a2.id, updates);
|
|
5083
|
+
}
|
|
5084
|
+
},
|
|
5085
|
+
{
|
|
5086
|
+
name: "refresh",
|
|
5087
|
+
description: "Refresh movie metadata",
|
|
5088
|
+
args: [{ name: "id", description: "Movie ID", required: true, type: "number" }],
|
|
5089
|
+
run: (c3, a2) => c3.runCommand({ name: "RefreshMovie", movieIds: [a2.id] })
|
|
5090
|
+
},
|
|
5091
|
+
{
|
|
5092
|
+
name: "manual-search",
|
|
5093
|
+
description: "Trigger a manual search for releases",
|
|
5094
|
+
args: [{ name: "id", description: "Movie ID", required: true, type: "number" }],
|
|
5095
|
+
run: (c3, a2) => c3.runCommand({ name: "MoviesSearch", movieIds: [a2.id] })
|
|
5096
|
+
},
|
|
4945
5097
|
{
|
|
4946
5098
|
name: "delete",
|
|
4947
5099
|
description: "Delete a movie",
|
|
@@ -7442,6 +7594,7 @@ __export(exports_sonarr3, {
|
|
|
7442
7594
|
var resources2, sonarr;
|
|
7443
7595
|
var init_sonarr3 = __esm(() => {
|
|
7444
7596
|
init_sonarr2();
|
|
7597
|
+
init_prompt2();
|
|
7445
7598
|
init_service();
|
|
7446
7599
|
resources2 = [
|
|
7447
7600
|
{
|
|
@@ -7467,6 +7620,79 @@ var init_sonarr3 = __esm(() => {
|
|
|
7467
7620
|
columns: ["tvdbId", "title", "year", "overview"],
|
|
7468
7621
|
run: (c3, a2) => c3.searchSeries(a2.term)
|
|
7469
7622
|
},
|
|
7623
|
+
{
|
|
7624
|
+
name: "add",
|
|
7625
|
+
description: "Search and add a series",
|
|
7626
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
7627
|
+
run: async (c3, a2) => {
|
|
7628
|
+
const searchResult = await c3.searchSeries(a2.term);
|
|
7629
|
+
const results = searchResult?.data ?? searchResult;
|
|
7630
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
7631
|
+
throw new Error("No series found.");
|
|
7632
|
+
}
|
|
7633
|
+
const seriesId = await promptSelect("Select a series:", results.map((s2) => ({ label: `${s2.title} (${s2.year})`, value: String(s2.tvdbId) })));
|
|
7634
|
+
const series = results.find((s2) => String(s2.tvdbId) === seriesId);
|
|
7635
|
+
if (!series) {
|
|
7636
|
+
throw new Error("Selected series was not found in the search results.");
|
|
7637
|
+
}
|
|
7638
|
+
const profilesResult = await c3.getQualityProfiles();
|
|
7639
|
+
const profiles = profilesResult?.data ?? profilesResult;
|
|
7640
|
+
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
7641
|
+
throw new Error("No quality profiles found. Configure one in Sonarr first.");
|
|
7642
|
+
}
|
|
7643
|
+
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
7644
|
+
const foldersResult = await c3.getRootFolders();
|
|
7645
|
+
const folders = foldersResult?.data ?? foldersResult;
|
|
7646
|
+
if (!Array.isArray(folders) || folders.length === 0) {
|
|
7647
|
+
throw new Error("No root folders found. Configure one in Sonarr first.");
|
|
7648
|
+
}
|
|
7649
|
+
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
7650
|
+
const confirmed = await promptConfirm(`Add "${series.title} (${series.year})"?`, !!a2.yes);
|
|
7651
|
+
if (!confirmed)
|
|
7652
|
+
throw new Error("Cancelled.");
|
|
7653
|
+
return c3.addSeries({
|
|
7654
|
+
...series,
|
|
7655
|
+
qualityProfileId: Number(profileId),
|
|
7656
|
+
rootFolderPath,
|
|
7657
|
+
monitored: true,
|
|
7658
|
+
addOptions: { searchForMissingEpisodes: true }
|
|
7659
|
+
});
|
|
7660
|
+
}
|
|
7661
|
+
},
|
|
7662
|
+
{
|
|
7663
|
+
name: "edit",
|
|
7664
|
+
description: "Edit a series",
|
|
7665
|
+
args: [
|
|
7666
|
+
{ name: "id", description: "Series ID", required: true, type: "number" },
|
|
7667
|
+
{ name: "monitored", description: "Set monitored (true/false)" },
|
|
7668
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
7669
|
+
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
7670
|
+
],
|
|
7671
|
+
run: async (c3, a2) => {
|
|
7672
|
+
const result = await c3.getSeriesById(a2.id);
|
|
7673
|
+
const series = result?.data ?? result;
|
|
7674
|
+
const updates = { ...series };
|
|
7675
|
+
if (a2.monitored !== undefined)
|
|
7676
|
+
updates.monitored = a2.monitored === "true";
|
|
7677
|
+
if (a2["quality-profile-id"] !== undefined)
|
|
7678
|
+
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
7679
|
+
if (a2.tags !== undefined)
|
|
7680
|
+
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
7681
|
+
return c3.updateSeries(String(a2.id), updates);
|
|
7682
|
+
}
|
|
7683
|
+
},
|
|
7684
|
+
{
|
|
7685
|
+
name: "refresh",
|
|
7686
|
+
description: "Refresh series metadata",
|
|
7687
|
+
args: [{ name: "id", description: "Series ID", required: true, type: "number" }],
|
|
7688
|
+
run: (c3, a2) => c3.runCommand({ name: "RefreshSeries", seriesId: a2.id })
|
|
7689
|
+
},
|
|
7690
|
+
{
|
|
7691
|
+
name: "manual-search",
|
|
7692
|
+
description: "Trigger a manual search for releases",
|
|
7693
|
+
args: [{ name: "id", description: "Series ID", required: true, type: "number" }],
|
|
7694
|
+
run: (c3, a2) => c3.runCommand({ name: "SeriesSearch", seriesId: a2.id })
|
|
7695
|
+
},
|
|
7470
7696
|
{
|
|
7471
7697
|
name: "delete",
|
|
7472
7698
|
description: "Delete a series",
|
|
@@ -9882,6 +10108,7 @@ __export(exports_lidarr3, {
|
|
|
9882
10108
|
var resources3, lidarr;
|
|
9883
10109
|
var init_lidarr3 = __esm(() => {
|
|
9884
10110
|
init_lidarr2();
|
|
10111
|
+
init_prompt2();
|
|
9885
10112
|
init_service();
|
|
9886
10113
|
resources3 = [
|
|
9887
10114
|
{
|
|
@@ -9907,6 +10134,82 @@ var init_lidarr3 = __esm(() => {
|
|
|
9907
10134
|
columns: ["foreignArtistId", "artistName", "overview"],
|
|
9908
10135
|
run: (c3, a2) => c3.searchArtists(a2.term)
|
|
9909
10136
|
},
|
|
10137
|
+
{
|
|
10138
|
+
name: "add",
|
|
10139
|
+
description: "Search and add an artist",
|
|
10140
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
10141
|
+
run: async (c3, a2) => {
|
|
10142
|
+
const searchResult = await c3.searchArtists(a2.term);
|
|
10143
|
+
const results = searchResult?.data ?? searchResult;
|
|
10144
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
10145
|
+
throw new Error("No artists found.");
|
|
10146
|
+
}
|
|
10147
|
+
const artistId = await promptSelect("Select an artist:", results.map((ar) => ({
|
|
10148
|
+
label: ar.artistName,
|
|
10149
|
+
value: String(ar.foreignArtistId)
|
|
10150
|
+
})));
|
|
10151
|
+
const artist = results.find((ar) => String(ar.foreignArtistId) === artistId);
|
|
10152
|
+
if (!artist) {
|
|
10153
|
+
throw new Error("Selected artist was not found in the search results.");
|
|
10154
|
+
}
|
|
10155
|
+
const profilesResult = await c3.getQualityProfiles();
|
|
10156
|
+
const profiles = profilesResult?.data ?? profilesResult;
|
|
10157
|
+
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
10158
|
+
throw new Error("No quality profiles found. Configure one in Lidarr first.");
|
|
10159
|
+
}
|
|
10160
|
+
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
10161
|
+
const foldersResult = await c3.getRootFolders();
|
|
10162
|
+
const folders = foldersResult?.data ?? foldersResult;
|
|
10163
|
+
if (!Array.isArray(folders) || folders.length === 0) {
|
|
10164
|
+
throw new Error("No root folders found. Configure one in Lidarr first.");
|
|
10165
|
+
}
|
|
10166
|
+
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
10167
|
+
const confirmed = await promptConfirm(`Add "${artist.artistName}"?`, !!a2.yes);
|
|
10168
|
+
if (!confirmed)
|
|
10169
|
+
throw new Error("Cancelled.");
|
|
10170
|
+
return c3.addArtist({
|
|
10171
|
+
...artist,
|
|
10172
|
+
qualityProfileId: Number(profileId),
|
|
10173
|
+
rootFolderPath,
|
|
10174
|
+
monitored: true,
|
|
10175
|
+
addOptions: { searchForMissingAlbums: true }
|
|
10176
|
+
});
|
|
10177
|
+
}
|
|
10178
|
+
},
|
|
10179
|
+
{
|
|
10180
|
+
name: "edit",
|
|
10181
|
+
description: "Edit an artist",
|
|
10182
|
+
args: [
|
|
10183
|
+
{ name: "id", description: "Artist ID", required: true, type: "number" },
|
|
10184
|
+
{ name: "monitored", description: "Set monitored (true/false)" },
|
|
10185
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
10186
|
+
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
10187
|
+
],
|
|
10188
|
+
run: async (c3, a2) => {
|
|
10189
|
+
const result = await c3.getArtist(a2.id);
|
|
10190
|
+
const artist = result?.data ?? result;
|
|
10191
|
+
const updates = { ...artist };
|
|
10192
|
+
if (a2.monitored !== undefined)
|
|
10193
|
+
updates.monitored = a2.monitored === "true";
|
|
10194
|
+
if (a2["quality-profile-id"] !== undefined)
|
|
10195
|
+
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
10196
|
+
if (a2.tags !== undefined)
|
|
10197
|
+
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
10198
|
+
return c3.updateArtist(a2.id, updates);
|
|
10199
|
+
}
|
|
10200
|
+
},
|
|
10201
|
+
{
|
|
10202
|
+
name: "refresh",
|
|
10203
|
+
description: "Refresh artist metadata",
|
|
10204
|
+
args: [{ name: "id", description: "Artist ID", required: true, type: "number" }],
|
|
10205
|
+
run: (c3, a2) => c3.runCommand({ name: "RefreshArtist", artistId: a2.id })
|
|
10206
|
+
},
|
|
10207
|
+
{
|
|
10208
|
+
name: "manual-search",
|
|
10209
|
+
description: "Trigger a manual search for releases",
|
|
10210
|
+
args: [{ name: "id", description: "Artist ID", required: true, type: "number" }],
|
|
10211
|
+
run: (c3, a2) => c3.runCommand({ name: "ArtistSearch", artistId: a2.id })
|
|
10212
|
+
},
|
|
9910
10213
|
{
|
|
9911
10214
|
name: "delete",
|
|
9912
10215
|
description: "Delete an artist",
|
|
@@ -12275,6 +12578,7 @@ __export(exports_readarr3, {
|
|
|
12275
12578
|
var resources4, readarr;
|
|
12276
12579
|
var init_readarr3 = __esm(() => {
|
|
12277
12580
|
init_readarr2();
|
|
12581
|
+
init_prompt2();
|
|
12278
12582
|
init_service();
|
|
12279
12583
|
resources4 = [
|
|
12280
12584
|
{
|
|
@@ -12300,6 +12604,79 @@ var init_readarr3 = __esm(() => {
|
|
|
12300
12604
|
columns: ["foreignAuthorId", "authorName", "overview"],
|
|
12301
12605
|
run: (c3, a2) => c3.searchAuthors(a2.term)
|
|
12302
12606
|
},
|
|
12607
|
+
{
|
|
12608
|
+
name: "add",
|
|
12609
|
+
description: "Search and add an author",
|
|
12610
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
12611
|
+
run: async (c3, a2) => {
|
|
12612
|
+
const searchResult = await c3.searchAuthors(a2.term);
|
|
12613
|
+
const results = searchResult?.data ?? searchResult;
|
|
12614
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
12615
|
+
throw new Error("No authors found.");
|
|
12616
|
+
}
|
|
12617
|
+
const authorId = await promptSelect("Select an author:", results.map((au) => ({
|
|
12618
|
+
label: au.authorName,
|
|
12619
|
+
value: String(au.foreignAuthorId)
|
|
12620
|
+
})));
|
|
12621
|
+
const author = results.find((au) => String(au.foreignAuthorId) === authorId);
|
|
12622
|
+
const profilesResult = await c3.getQualityProfiles();
|
|
12623
|
+
const profiles = profilesResult?.data ?? profilesResult;
|
|
12624
|
+
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
12625
|
+
throw new Error("No quality profiles found. Configure one in Readarr first.");
|
|
12626
|
+
}
|
|
12627
|
+
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
12628
|
+
const foldersResult = await c3.getRootFolders();
|
|
12629
|
+
const folders = foldersResult?.data ?? foldersResult;
|
|
12630
|
+
if (!Array.isArray(folders) || folders.length === 0) {
|
|
12631
|
+
throw new Error("No root folders found. Configure one in Readarr first.");
|
|
12632
|
+
}
|
|
12633
|
+
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
12634
|
+
const confirmed = await promptConfirm(`Add "${author.authorName}"?`, !!a2.yes);
|
|
12635
|
+
if (!confirmed)
|
|
12636
|
+
throw new Error("Cancelled.");
|
|
12637
|
+
return c3.addAuthor({
|
|
12638
|
+
...author,
|
|
12639
|
+
qualityProfileId: Number(profileId),
|
|
12640
|
+
rootFolderPath,
|
|
12641
|
+
monitored: true,
|
|
12642
|
+
addOptions: { searchForMissingBooks: true }
|
|
12643
|
+
});
|
|
12644
|
+
}
|
|
12645
|
+
},
|
|
12646
|
+
{
|
|
12647
|
+
name: "edit",
|
|
12648
|
+
description: "Edit an author",
|
|
12649
|
+
args: [
|
|
12650
|
+
{ name: "id", description: "Author ID", required: true, type: "number" },
|
|
12651
|
+
{ name: "monitored", description: "Set monitored (true/false)" },
|
|
12652
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
12653
|
+
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
12654
|
+
],
|
|
12655
|
+
run: async (c3, a2) => {
|
|
12656
|
+
const result = await c3.getAuthor(a2.id);
|
|
12657
|
+
const author = result?.data ?? result;
|
|
12658
|
+
const updates = { ...author };
|
|
12659
|
+
if (a2.monitored !== undefined)
|
|
12660
|
+
updates.monitored = a2.monitored === "true";
|
|
12661
|
+
if (a2["quality-profile-id"] !== undefined)
|
|
12662
|
+
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
12663
|
+
if (a2.tags !== undefined)
|
|
12664
|
+
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
12665
|
+
return c3.updateAuthor(a2.id, updates);
|
|
12666
|
+
}
|
|
12667
|
+
},
|
|
12668
|
+
{
|
|
12669
|
+
name: "refresh",
|
|
12670
|
+
description: "Refresh author metadata",
|
|
12671
|
+
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
12672
|
+
run: (c3, a2) => c3.runCommand({ name: "RefreshAuthor", authorId: a2.id })
|
|
12673
|
+
},
|
|
12674
|
+
{
|
|
12675
|
+
name: "manual-search",
|
|
12676
|
+
description: "Trigger a manual search for releases",
|
|
12677
|
+
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
12678
|
+
run: (c3, a2) => c3.runCommand({ name: "AuthorSearch", authorId: a2.id })
|
|
12679
|
+
},
|
|
12303
12680
|
{
|
|
12304
12681
|
name: "delete",
|
|
12305
12682
|
description: "Delete an author",
|
|
@@ -14912,46 +15289,46 @@ var init_client7 = __esm(() => {
|
|
|
14912
15289
|
var client6;
|
|
14913
15290
|
var init_client_gen12 = __esm(() => {
|
|
14914
15291
|
init_client7();
|
|
14915
|
-
client6 = createClient6(createConfig6(
|
|
15292
|
+
client6 = createClient6(createConfig6());
|
|
14916
15293
|
});
|
|
14917
15294
|
|
|
14918
15295
|
// src/generated/bazarr/sdk.gen.ts
|
|
14919
15296
|
var getBadges = (options) => (options?.client ?? client6).get({
|
|
14920
15297
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14921
|
-
url: "/badges",
|
|
15298
|
+
url: "/api/badges",
|
|
14922
15299
|
...options
|
|
14923
15300
|
}), getEpisodes = (options) => (options?.client ?? client6).get({
|
|
14924
15301
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14925
|
-
url: "/episodes",
|
|
15302
|
+
url: "/api/episodes",
|
|
14926
15303
|
...options
|
|
14927
15304
|
}), deleteEpisodesBlacklist = (options) => (options?.client ?? client6).delete({
|
|
14928
15305
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14929
|
-
url: "/episodes/blacklist",
|
|
15306
|
+
url: "/api/episodes/blacklist",
|
|
14930
15307
|
...options
|
|
14931
15308
|
}), getEpisodesBlacklist = (options) => (options?.client ?? client6).get({
|
|
14932
15309
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14933
|
-
url: "/episodes/blacklist",
|
|
15310
|
+
url: "/api/episodes/blacklist",
|
|
14934
15311
|
...options
|
|
14935
15312
|
}), postEpisodesBlacklist = (options) => (options.client ?? client6).post({
|
|
14936
15313
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14937
|
-
url: "/episodes/blacklist",
|
|
15314
|
+
url: "/api/episodes/blacklist",
|
|
14938
15315
|
...options
|
|
14939
15316
|
}), getEpisodesHistory = (options) => (options?.client ?? client6).get({
|
|
14940
15317
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14941
|
-
url: "/episodes/history",
|
|
15318
|
+
url: "/api/episodes/history",
|
|
14942
15319
|
...options
|
|
14943
15320
|
}), deleteEpisodesSubtitles = (options) => (options.client ?? client6).delete({
|
|
14944
15321
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14945
|
-
url: "/episodes/subtitles",
|
|
15322
|
+
url: "/api/episodes/subtitles",
|
|
14946
15323
|
...options
|
|
14947
15324
|
}), patchEpisodesSubtitles = (options) => (options.client ?? client6).patch({
|
|
14948
15325
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14949
|
-
url: "/episodes/subtitles",
|
|
15326
|
+
url: "/api/episodes/subtitles",
|
|
14950
15327
|
...options
|
|
14951
15328
|
}), postEpisodesSubtitles = (options) => (options.client ?? client6).post({
|
|
14952
15329
|
...formDataBodySerializer,
|
|
14953
15330
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14954
|
-
url: "/episodes/subtitles",
|
|
15331
|
+
url: "/api/episodes/subtitles",
|
|
14955
15332
|
...options,
|
|
14956
15333
|
headers: {
|
|
14957
15334
|
"Content-Type": null,
|
|
@@ -14959,64 +15336,64 @@ var getBadges = (options) => (options?.client ?? client6).get({
|
|
|
14959
15336
|
}
|
|
14960
15337
|
}), getEpisodesWanted = (options) => (options?.client ?? client6).get({
|
|
14961
15338
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14962
|
-
url: "/episodes/wanted",
|
|
15339
|
+
url: "/api/episodes/wanted",
|
|
14963
15340
|
...options
|
|
14964
15341
|
}), getBrowseBazarrFs = (options) => (options?.client ?? client6).get({
|
|
14965
15342
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14966
|
-
url: "/files",
|
|
15343
|
+
url: "/api/files",
|
|
14967
15344
|
...options
|
|
14968
15345
|
}), getBrowseRadarrFs = (options) => (options?.client ?? client6).get({
|
|
14969
15346
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14970
|
-
url: "/files/radarr",
|
|
15347
|
+
url: "/api/files/radarr",
|
|
14971
15348
|
...options
|
|
14972
15349
|
}), getBrowseSonarrFs = (options) => (options?.client ?? client6).get({
|
|
14973
15350
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14974
|
-
url: "/files/sonarr",
|
|
15351
|
+
url: "/api/files/sonarr",
|
|
14975
15352
|
...options
|
|
14976
15353
|
}), getHistoryStats = (options) => (options?.client ?? client6).get({
|
|
14977
15354
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14978
|
-
url: "/history/stats",
|
|
15355
|
+
url: "/api/history/stats",
|
|
14979
15356
|
...options
|
|
14980
15357
|
}), getMovies = (options) => (options?.client ?? client6).get({
|
|
14981
15358
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14982
|
-
url: "/movies",
|
|
15359
|
+
url: "/api/movies",
|
|
14983
15360
|
...options
|
|
14984
15361
|
}), patchMovies = (options) => (options?.client ?? client6).patch({
|
|
14985
15362
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14986
|
-
url: "/movies",
|
|
15363
|
+
url: "/api/movies",
|
|
14987
15364
|
...options
|
|
14988
15365
|
}), postMovies = (options) => (options?.client ?? client6).post({
|
|
14989
15366
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14990
|
-
url: "/movies",
|
|
15367
|
+
url: "/api/movies",
|
|
14991
15368
|
...options
|
|
14992
15369
|
}), deleteMoviesBlacklist = (options) => (options?.client ?? client6).delete({
|
|
14993
15370
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14994
|
-
url: "/movies/blacklist",
|
|
15371
|
+
url: "/api/movies/blacklist",
|
|
14995
15372
|
...options
|
|
14996
15373
|
}), getMoviesBlacklist = (options) => (options?.client ?? client6).get({
|
|
14997
15374
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
14998
|
-
url: "/movies/blacklist",
|
|
15375
|
+
url: "/api/movies/blacklist",
|
|
14999
15376
|
...options
|
|
15000
15377
|
}), postMoviesBlacklist = (options) => (options.client ?? client6).post({
|
|
15001
15378
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15002
|
-
url: "/movies/blacklist",
|
|
15379
|
+
url: "/api/movies/blacklist",
|
|
15003
15380
|
...options
|
|
15004
15381
|
}), getMoviesHistory = (options) => (options?.client ?? client6).get({
|
|
15005
15382
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15006
|
-
url: "/movies/history",
|
|
15383
|
+
url: "/api/movies/history",
|
|
15007
15384
|
...options
|
|
15008
15385
|
}), deleteMoviesSubtitles = (options) => (options.client ?? client6).delete({
|
|
15009
15386
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15010
|
-
url: "/movies/subtitles",
|
|
15387
|
+
url: "/api/movies/subtitles",
|
|
15011
15388
|
...options
|
|
15012
15389
|
}), patchMoviesSubtitles = (options) => (options.client ?? client6).patch({
|
|
15013
15390
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15014
|
-
url: "/movies/subtitles",
|
|
15391
|
+
url: "/api/movies/subtitles",
|
|
15015
15392
|
...options
|
|
15016
15393
|
}), postMoviesSubtitles = (options) => (options.client ?? client6).post({
|
|
15017
15394
|
...formDataBodySerializer,
|
|
15018
15395
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15019
|
-
url: "/movies/subtitles",
|
|
15396
|
+
url: "/api/movies/subtitles",
|
|
15020
15397
|
...options,
|
|
15021
15398
|
headers: {
|
|
15022
15399
|
"Content-Type": null,
|
|
@@ -15024,151 +15401,151 @@ var getBadges = (options) => (options?.client ?? client6).get({
|
|
|
15024
15401
|
}
|
|
15025
15402
|
}), getMoviesWanted = (options) => (options?.client ?? client6).get({
|
|
15026
15403
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15027
|
-
url: "/movies/wanted",
|
|
15404
|
+
url: "/api/movies/wanted",
|
|
15028
15405
|
...options
|
|
15029
15406
|
}), getProviders = (options) => (options?.client ?? client6).get({
|
|
15030
15407
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15031
|
-
url: "/providers",
|
|
15408
|
+
url: "/api/providers",
|
|
15032
15409
|
...options
|
|
15033
15410
|
}), postProviders = (options) => (options.client ?? client6).post({
|
|
15034
15411
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15035
|
-
url: "/providers",
|
|
15412
|
+
url: "/api/providers",
|
|
15036
15413
|
...options
|
|
15037
15414
|
}), getProviderEpisodes = (options) => (options.client ?? client6).get({
|
|
15038
15415
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15039
|
-
url: "/providers/episodes",
|
|
15416
|
+
url: "/api/providers/episodes",
|
|
15040
15417
|
...options
|
|
15041
15418
|
}), postProviderEpisodes = (options) => (options.client ?? client6).post({
|
|
15042
15419
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15043
|
-
url: "/providers/episodes",
|
|
15420
|
+
url: "/api/providers/episodes",
|
|
15044
15421
|
...options
|
|
15045
15422
|
}), getProviderMovies = (options) => (options.client ?? client6).get({
|
|
15046
15423
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15047
|
-
url: "/providers/movies",
|
|
15424
|
+
url: "/api/providers/movies",
|
|
15048
15425
|
...options
|
|
15049
15426
|
}), postProviderMovies = (options) => (options.client ?? client6).post({
|
|
15050
15427
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15051
|
-
url: "/providers/movies",
|
|
15428
|
+
url: "/api/providers/movies",
|
|
15052
15429
|
...options
|
|
15053
15430
|
}), getSeries = (options) => (options?.client ?? client6).get({
|
|
15054
15431
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15055
|
-
url: "/series",
|
|
15432
|
+
url: "/api/series",
|
|
15056
15433
|
...options
|
|
15057
15434
|
}), patchSeries = (options) => (options?.client ?? client6).patch({
|
|
15058
15435
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15059
|
-
url: "/series",
|
|
15436
|
+
url: "/api/series",
|
|
15060
15437
|
...options
|
|
15061
15438
|
}), postSeries = (options) => (options?.client ?? client6).post({
|
|
15062
15439
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15063
|
-
url: "/series",
|
|
15440
|
+
url: "/api/series",
|
|
15064
15441
|
...options
|
|
15065
15442
|
}), getSubtitles = (options) => (options.client ?? client6).get({
|
|
15066
15443
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15067
|
-
url: "/subtitles",
|
|
15444
|
+
url: "/api/subtitles",
|
|
15068
15445
|
...options
|
|
15069
15446
|
}), patchSubtitles = (options) => (options.client ?? client6).patch({
|
|
15070
15447
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15071
|
-
url: "/subtitles",
|
|
15448
|
+
url: "/api/subtitles",
|
|
15072
15449
|
...options
|
|
15073
15450
|
}), getSubtitleNameInfo = (options) => (options.client ?? client6).get({
|
|
15074
15451
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15075
|
-
url: "/subtitles/info",
|
|
15452
|
+
url: "/api/subtitles/info",
|
|
15076
15453
|
...options
|
|
15077
15454
|
}), getSystemAnnouncements = (options) => (options?.client ?? client6).get({
|
|
15078
15455
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15079
|
-
url: "/system/announcements",
|
|
15456
|
+
url: "/api/system/announcements",
|
|
15080
15457
|
...options
|
|
15081
15458
|
}), postSystemAnnouncements = (options) => (options.client ?? client6).post({
|
|
15082
15459
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15083
|
-
url: "/system/announcements",
|
|
15460
|
+
url: "/api/system/announcements",
|
|
15084
15461
|
...options
|
|
15085
15462
|
}), deleteSystemBackups = (options) => (options.client ?? client6).delete({
|
|
15086
15463
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15087
|
-
url: "/system/backups",
|
|
15464
|
+
url: "/api/system/backups",
|
|
15088
15465
|
...options
|
|
15089
15466
|
}), getSystemBackups = (options) => (options?.client ?? client6).get({
|
|
15090
15467
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15091
|
-
url: "/system/backups",
|
|
15468
|
+
url: "/api/system/backups",
|
|
15092
15469
|
...options
|
|
15093
15470
|
}), patchSystemBackups = (options) => (options.client ?? client6).patch({
|
|
15094
15471
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15095
|
-
url: "/system/backups",
|
|
15472
|
+
url: "/api/system/backups",
|
|
15096
15473
|
...options
|
|
15097
15474
|
}), postSystemBackups = (options) => (options?.client ?? client6).post({
|
|
15098
15475
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15099
|
-
url: "/system/backups",
|
|
15476
|
+
url: "/api/system/backups",
|
|
15100
15477
|
...options
|
|
15101
15478
|
}), getSystemHealth = (options) => (options?.client ?? client6).get({
|
|
15102
15479
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15103
|
-
url: "/system/health",
|
|
15480
|
+
url: "/api/system/health",
|
|
15104
15481
|
...options
|
|
15105
15482
|
}), deleteSystemJobs = (options) => (options.client ?? client6).delete({
|
|
15106
15483
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15107
|
-
url: "/system/jobs",
|
|
15484
|
+
url: "/api/system/jobs",
|
|
15108
15485
|
...options
|
|
15109
15486
|
}), getSystemJobs = (options) => (options?.client ?? client6).get({
|
|
15110
15487
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15111
|
-
url: "/system/jobs",
|
|
15488
|
+
url: "/api/system/jobs",
|
|
15112
15489
|
...options
|
|
15113
15490
|
}), patchSystemJobs = (options) => (options.client ?? client6).patch({
|
|
15114
15491
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15115
|
-
url: "/system/jobs",
|
|
15492
|
+
url: "/api/system/jobs",
|
|
15116
15493
|
...options
|
|
15117
15494
|
}), postSystemJobs = (options) => (options.client ?? client6).post({
|
|
15118
15495
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15119
|
-
url: "/system/jobs",
|
|
15496
|
+
url: "/api/system/jobs",
|
|
15120
15497
|
...options
|
|
15121
15498
|
}), getLanguages = (options) => (options?.client ?? client6).get({
|
|
15122
15499
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15123
|
-
url: "/system/languages",
|
|
15500
|
+
url: "/api/system/languages",
|
|
15124
15501
|
...options
|
|
15125
15502
|
}), getLanguagesProfiles = (options) => (options?.client ?? client6).get({
|
|
15126
15503
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15127
|
-
url: "/system/languages/profiles",
|
|
15504
|
+
url: "/api/system/languages/profiles",
|
|
15128
15505
|
...options
|
|
15129
15506
|
}), deleteSystemLogs = (options) => (options?.client ?? client6).delete({
|
|
15130
15507
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15131
|
-
url: "/system/logs",
|
|
15508
|
+
url: "/api/system/logs",
|
|
15132
15509
|
...options
|
|
15133
15510
|
}), getSystemLogs = (options) => (options?.client ?? client6).get({
|
|
15134
15511
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15135
|
-
url: "/system/logs",
|
|
15512
|
+
url: "/api/system/logs",
|
|
15136
15513
|
...options
|
|
15137
15514
|
}), getSystemPing = (options) => (options?.client ?? client6).get({
|
|
15138
15515
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15139
|
-
url: "/system/ping",
|
|
15516
|
+
url: "/api/system/ping",
|
|
15140
15517
|
...options
|
|
15141
15518
|
}), getSystemReleases = (options) => (options?.client ?? client6).get({
|
|
15142
15519
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15143
|
-
url: "/system/releases",
|
|
15520
|
+
url: "/api/system/releases",
|
|
15144
15521
|
...options
|
|
15145
15522
|
}), getSearches = (options) => (options.client ?? client6).get({
|
|
15146
15523
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15147
|
-
url: "/system/searches",
|
|
15524
|
+
url: "/api/system/searches",
|
|
15148
15525
|
...options
|
|
15149
15526
|
}), getSystemStatus = (options) => (options?.client ?? client6).get({
|
|
15150
15527
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15151
|
-
url: "/system/status",
|
|
15528
|
+
url: "/api/system/status",
|
|
15152
15529
|
...options
|
|
15153
15530
|
}), getSystemTasks = (options) => (options?.client ?? client6).get({
|
|
15154
15531
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15155
|
-
url: "/system/tasks",
|
|
15532
|
+
url: "/api/system/tasks",
|
|
15156
15533
|
...options
|
|
15157
15534
|
}), postSystemTasks = (options) => (options.client ?? client6).post({
|
|
15158
15535
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15159
|
-
url: "/system/tasks",
|
|
15536
|
+
url: "/api/system/tasks",
|
|
15160
15537
|
...options
|
|
15161
15538
|
}), postSystemWebhookTest = (options) => (options?.client ?? client6).post({
|
|
15162
15539
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15163
|
-
url: "/system/webhooks/test",
|
|
15540
|
+
url: "/api/system/webhooks/test",
|
|
15164
15541
|
...options
|
|
15165
15542
|
}), postWebHooksPlex = (options) => (options.client ?? client6).post({
|
|
15166
15543
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15167
|
-
url: "/webhooks/plex",
|
|
15544
|
+
url: "/api/webhooks/plex",
|
|
15168
15545
|
...options
|
|
15169
15546
|
}), postWebHooksRadarr = (options) => (options.client ?? client6).post({
|
|
15170
15547
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15171
|
-
url: "/webhooks/radarr",
|
|
15548
|
+
url: "/api/webhooks/radarr",
|
|
15172
15549
|
...options,
|
|
15173
15550
|
headers: {
|
|
15174
15551
|
"Content-Type": "application/json",
|
|
@@ -15176,7 +15553,7 @@ var getBadges = (options) => (options?.client ?? client6).get({
|
|
|
15176
15553
|
}
|
|
15177
15554
|
}), postWebHooksSonarr = (options) => (options.client ?? client6).post({
|
|
15178
15555
|
security: [{ name: "X-API-KEY", type: "apiKey" }],
|
|
15179
|
-
url: "/webhooks/sonarr",
|
|
15556
|
+
url: "/api/webhooks/sonarr",
|
|
15180
15557
|
...options,
|
|
15181
15558
|
headers: {
|
|
15182
15559
|
"Content-Type": "application/json",
|
|
@@ -15198,13 +15575,17 @@ var exports_bazarr = {};
|
|
|
15198
15575
|
__export(exports_bazarr, {
|
|
15199
15576
|
BazarrClient: () => BazarrClient
|
|
15200
15577
|
});
|
|
15578
|
+
function getBazarrApiBaseUrl(baseUrl) {
|
|
15579
|
+
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
15580
|
+
return normalizedBaseUrl.endsWith("/api") ? normalizedBaseUrl : `${normalizedBaseUrl}/api`;
|
|
15581
|
+
}
|
|
15201
15582
|
|
|
15202
15583
|
class BazarrClient {
|
|
15203
15584
|
clientConfig;
|
|
15204
15585
|
constructor(config) {
|
|
15205
15586
|
this.clientConfig = createServarrClient(config);
|
|
15206
15587
|
client6.setConfig({
|
|
15207
|
-
baseUrl: this.clientConfig.getBaseUrl(),
|
|
15588
|
+
baseUrl: getBazarrApiBaseUrl(this.clientConfig.getBaseUrl()),
|
|
15208
15589
|
headers: this.clientConfig.getHeaders()
|
|
15209
15590
|
});
|
|
15210
15591
|
}
|
|
@@ -15543,6 +15924,10 @@ class BazarrClient {
|
|
|
15543
15924
|
updateConfig(newConfig) {
|
|
15544
15925
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
15545
15926
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
15927
|
+
client6.setConfig({
|
|
15928
|
+
baseUrl: getBazarrApiBaseUrl(this.clientConfig.getBaseUrl()),
|
|
15929
|
+
headers: this.clientConfig.getHeaders()
|
|
15930
|
+
});
|
|
15546
15931
|
return this.clientConfig.config;
|
|
15547
15932
|
}
|
|
15548
15933
|
}
|
|
@@ -15657,6 +16042,16 @@ var exports_doctor = {};
|
|
|
15657
16042
|
__export(exports_doctor, {
|
|
15658
16043
|
doctor: () => doctor
|
|
15659
16044
|
});
|
|
16045
|
+
function extractVersion(service, status) {
|
|
16046
|
+
const data = status?.data ?? status;
|
|
16047
|
+
if (typeof data === "string") {
|
|
16048
|
+
return null;
|
|
16049
|
+
}
|
|
16050
|
+
if (service === "bazarr") {
|
|
16051
|
+
return data?.data?.bazarr_version ?? data?.bazarr_version ?? null;
|
|
16052
|
+
}
|
|
16053
|
+
return data?.version ?? status?.version ?? null;
|
|
16054
|
+
}
|
|
15660
16055
|
var clientFactories, doctor;
|
|
15661
16056
|
var init_doctor = __esm(() => {
|
|
15662
16057
|
init_dist();
|
|
@@ -15681,37 +16076,74 @@ var init_doctor = __esm(() => {
|
|
|
15681
16076
|
name: "doctor",
|
|
15682
16077
|
description: "Test all configured service connections"
|
|
15683
16078
|
},
|
|
15684
|
-
|
|
15685
|
-
|
|
15686
|
-
|
|
15687
|
-
|
|
16079
|
+
args: {
|
|
16080
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
16081
|
+
table: { type: "boolean", description: "Output as table" },
|
|
16082
|
+
quiet: { type: "boolean", alias: "q", description: "Output service names only" }
|
|
16083
|
+
},
|
|
16084
|
+
async run({ args }) {
|
|
16085
|
+
const format = detectFormat(args);
|
|
15688
16086
|
let hasAny = false;
|
|
16087
|
+
const results = [];
|
|
16088
|
+
if (format === "table") {
|
|
16089
|
+
consola.info(`Checking connections...
|
|
16090
|
+
`);
|
|
16091
|
+
}
|
|
15689
16092
|
for (const service of SERVICES) {
|
|
15690
16093
|
const svcConfig = getServiceConfig(service);
|
|
15691
16094
|
if (!svcConfig) {
|
|
15692
|
-
|
|
16095
|
+
results.push({
|
|
16096
|
+
service,
|
|
16097
|
+
configured: false,
|
|
16098
|
+
status: "not configured"
|
|
16099
|
+
});
|
|
15693
16100
|
continue;
|
|
15694
16101
|
}
|
|
15695
16102
|
hasAny = true;
|
|
15696
16103
|
try {
|
|
15697
16104
|
const factory = clientFactories[service];
|
|
15698
16105
|
if (!factory) {
|
|
15699
|
-
|
|
16106
|
+
results.push({
|
|
16107
|
+
service,
|
|
16108
|
+
configured: true,
|
|
16109
|
+
status: "fail",
|
|
16110
|
+
baseUrl: svcConfig.baseUrl,
|
|
16111
|
+
error: "No client factory available"
|
|
16112
|
+
});
|
|
15700
16113
|
continue;
|
|
15701
16114
|
}
|
|
15702
16115
|
const client7 = factory(svcConfig);
|
|
15703
16116
|
const status = await client7.getSystemStatus();
|
|
15704
|
-
const version =
|
|
15705
|
-
|
|
16117
|
+
const version = extractVersion(service, status) ?? "?";
|
|
16118
|
+
if (version === "?") {
|
|
16119
|
+
throw new Error("Unexpected response payload");
|
|
16120
|
+
}
|
|
16121
|
+
results.push({
|
|
16122
|
+
service,
|
|
16123
|
+
configured: true,
|
|
16124
|
+
status: "ok",
|
|
16125
|
+
version: String(version),
|
|
16126
|
+
baseUrl: svcConfig.baseUrl
|
|
16127
|
+
});
|
|
15706
16128
|
} catch (error) {
|
|
15707
16129
|
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
15708
|
-
|
|
16130
|
+
results.push({
|
|
16131
|
+
service,
|
|
16132
|
+
configured: true,
|
|
16133
|
+
status: "fail",
|
|
16134
|
+
baseUrl: svcConfig.baseUrl,
|
|
16135
|
+
error: msg
|
|
16136
|
+
});
|
|
15709
16137
|
}
|
|
15710
16138
|
}
|
|
15711
|
-
if (!hasAny) {
|
|
16139
|
+
if (!hasAny && format === "table") {
|
|
15712
16140
|
consola.warn("\nNo services configured. Run `tsarr config init` to set up.");
|
|
15713
16141
|
}
|
|
15714
|
-
|
|
16142
|
+
formatOutput(results, {
|
|
16143
|
+
format,
|
|
16144
|
+
columns: ["service", "status", "version", "baseUrl", "error"],
|
|
16145
|
+
idField: "service"
|
|
16146
|
+
});
|
|
15715
16147
|
}
|
|
15716
16148
|
});
|
|
15717
16149
|
});
|
|
@@ -16002,7 +16434,7 @@ var init_completions = __esm(() => {
|
|
|
16002
16434
|
init_dist2();
|
|
16003
16435
|
SERVICE_COMMANDS = {
|
|
16004
16436
|
radarr: {
|
|
16005
|
-
movie: ["list", "get", "search", "delete"],
|
|
16437
|
+
movie: ["list", "get", "search", "add", "edit", "refresh", "manual-search", "delete"],
|
|
16006
16438
|
profile: ["list", "get"],
|
|
16007
16439
|
tag: ["list"],
|
|
16008
16440
|
queue: ["list", "status"],
|
|
@@ -16012,7 +16444,7 @@ var init_completions = __esm(() => {
|
|
|
16012
16444
|
customformat: ["list"]
|
|
16013
16445
|
},
|
|
16014
16446
|
sonarr: {
|
|
16015
|
-
series: ["list", "get", "search", "delete"],
|
|
16447
|
+
series: ["list", "get", "search", "add", "edit", "refresh", "manual-search", "delete"],
|
|
16016
16448
|
episode: ["list", "get"],
|
|
16017
16449
|
profile: ["list"],
|
|
16018
16450
|
tag: ["list"],
|
|
@@ -16020,7 +16452,7 @@ var init_completions = __esm(() => {
|
|
|
16020
16452
|
system: ["status", "health"]
|
|
16021
16453
|
},
|
|
16022
16454
|
lidarr: {
|
|
16023
|
-
artist: ["list", "get", "search", "delete"],
|
|
16455
|
+
artist: ["list", "get", "search", "add", "edit", "refresh", "manual-search", "delete"],
|
|
16024
16456
|
album: ["list", "get", "search"],
|
|
16025
16457
|
profile: ["list"],
|
|
16026
16458
|
tag: ["list"],
|
|
@@ -16028,7 +16460,7 @@ var init_completions = __esm(() => {
|
|
|
16028
16460
|
system: ["status", "health"]
|
|
16029
16461
|
},
|
|
16030
16462
|
readarr: {
|
|
16031
|
-
author: ["list", "get", "search", "delete"],
|
|
16463
|
+
author: ["list", "get", "search", "add", "edit", "refresh", "manual-search", "delete"],
|
|
16032
16464
|
book: ["list", "get", "search"],
|
|
16033
16465
|
profile: ["list"],
|
|
16034
16466
|
tag: ["list"],
|
|
@@ -16084,10 +16516,12 @@ var init_completions = __esm(() => {
|
|
|
16084
16516
|
|
|
16085
16517
|
// src/cli/index.ts
|
|
16086
16518
|
init_dist();
|
|
16519
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
16520
|
+
var { version } = JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf-8"));
|
|
16087
16521
|
var main = defineCommand({
|
|
16088
16522
|
meta: {
|
|
16089
16523
|
name: "tsarr",
|
|
16090
|
-
version
|
|
16524
|
+
version,
|
|
16091
16525
|
description: "CLI for Servarr APIs (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, Bazarr)"
|
|
16092
16526
|
},
|
|
16093
16527
|
subCommands: {
|