tsarr 2.7.5 → 2.8.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/config.d.ts.map +1 -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/prowlarr.d.ts.map +1 -1
- package/dist/cli/commands/qbit.d.ts +1 -1
- package/dist/cli/commands/qbit.d.ts.map +1 -1
- package/dist/cli/commands/radarr.d.ts +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/seerr.d.ts +1 -1
- package/dist/cli/commands/seerr.d.ts.map +1 -1
- package/dist/cli/commands/service.d.ts +6 -0
- package/dist/cli/commands/service.d.ts.map +1 -1
- package/dist/cli/commands/sonarr.d.ts +1 -1
- package/dist/cli/commands/sonarr.d.ts.map +1 -1
- package/dist/cli/completions.d.ts.map +1 -1
- package/dist/cli/config.d.ts +9 -3
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/index.js +461 -408
- package/dist/clients/bazarr.d.ts +3 -2
- package/dist/clients/bazarr.d.ts.map +1 -1
- package/dist/clients/lidarr.d.ts +4 -3
- package/dist/clients/lidarr.d.ts.map +1 -1
- package/dist/clients/prowlarr.d.ts +4 -3
- package/dist/clients/prowlarr.d.ts.map +1 -1
- package/dist/clients/qbittorrent.d.ts +3 -2
- package/dist/clients/qbittorrent.d.ts.map +1 -1
- package/dist/clients/radarr.d.ts +4 -3
- package/dist/clients/radarr.d.ts.map +1 -1
- package/dist/clients/readarr.d.ts +4 -3
- package/dist/clients/readarr.d.ts.map +1 -1
- package/dist/clients/seerr.d.ts +4 -3
- package/dist/clients/seerr.d.ts.map +1 -1
- package/dist/clients/sonarr.d.ts +4 -3
- package/dist/clients/sonarr.d.ts.map +1 -1
- package/dist/core/client.d.ts +1 -1
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -4
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/types.d.ts +0 -5
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +17 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -41
- package/dist/tsarr-2.8.0.tgz +0 -0
- package/package.json +2 -2
- package/dist/core/response.d.ts +0 -13
- package/dist/core/response.d.ts.map +0 -1
- package/dist/tsarr-2.7.5.tgz +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -564,7 +564,7 @@ var init_dist = __esm(() => {
|
|
|
564
564
|
});
|
|
565
565
|
|
|
566
566
|
// src/core/errors.ts
|
|
567
|
-
var TsarrError, ApiKeyError, ConnectionError
|
|
567
|
+
var TsarrError, ApiKeyError, ConnectionError;
|
|
568
568
|
var init_errors = __esm(() => {
|
|
569
569
|
TsarrError = class TsarrError extends Error {
|
|
570
570
|
code;
|
|
@@ -590,12 +590,6 @@ var init_errors = __esm(() => {
|
|
|
590
590
|
this.name = "ConnectionError";
|
|
591
591
|
}
|
|
592
592
|
};
|
|
593
|
-
NotFoundError = class NotFoundError extends TsarrError {
|
|
594
|
-
constructor(resource) {
|
|
595
|
-
super(`Resource not found: ${resource}`, "NOT_FOUND", 404);
|
|
596
|
-
this.name = "NotFoundError";
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
593
|
});
|
|
600
594
|
|
|
601
595
|
// src/core/client.ts
|
|
@@ -4862,6 +4856,7 @@ function normalizeServiceConfig(service) {
|
|
|
4862
4856
|
const normalized = {
|
|
4863
4857
|
baseUrl: service.baseUrl ?? "",
|
|
4864
4858
|
apiKey: service.apiKey ?? "",
|
|
4859
|
+
...service.name ? { name: service.name } : {},
|
|
4865
4860
|
...service.apiKeyFile ? { apiKeyFile: service.apiKeyFile } : {},
|
|
4866
4861
|
...service.username ? { username: service.username } : {},
|
|
4867
4862
|
...service.password ? { password: service.password } : {}
|
|
@@ -4872,21 +4867,29 @@ function normalizeServiceConfig(service) {
|
|
|
4872
4867
|
}
|
|
4873
4868
|
return normalized;
|
|
4874
4869
|
}
|
|
4870
|
+
function normalizeServiceEntry(entry) {
|
|
4871
|
+
if (Array.isArray(entry)) {
|
|
4872
|
+
return entry.map((item) => normalizeServiceConfig(item)).filter((item) => item != null);
|
|
4873
|
+
}
|
|
4874
|
+
const normalized = normalizeServiceConfig(entry);
|
|
4875
|
+
return normalized ? [normalized] : [];
|
|
4876
|
+
}
|
|
4875
4877
|
function normalizeConfig(config) {
|
|
4876
|
-
const services = Object.fromEntries(Object.entries(config.services ?? {}).map(([name,
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
};
|
|
4878
|
+
const services = Object.fromEntries(Object.entries(config.services ?? {}).map(([name, entry]) => [
|
|
4879
|
+
name,
|
|
4880
|
+
normalizeServiceEntry(entry)
|
|
4881
|
+
]).filter(([, instances]) => instances.length > 0));
|
|
4882
|
+
const result = {};
|
|
4883
|
+
if (Object.keys(services).length > 0)
|
|
4884
|
+
result.services = services;
|
|
4885
|
+
if (config.defaults)
|
|
4886
|
+
result.defaults = config.defaults;
|
|
4887
|
+
return result;
|
|
4881
4888
|
}
|
|
4882
4889
|
function readJsonFile(path) {
|
|
4883
4890
|
if (!existsSync(path))
|
|
4884
4891
|
return {};
|
|
4885
|
-
|
|
4886
|
-
return normalizeConfig(JSON.parse(readFileSync(path, "utf-8")));
|
|
4887
|
-
} catch {
|
|
4888
|
-
return {};
|
|
4889
|
-
}
|
|
4892
|
+
return normalizeConfig(JSON.parse(readFileSync(path, "utf-8")));
|
|
4890
4893
|
}
|
|
4891
4894
|
function getEnvConfig() {
|
|
4892
4895
|
const services = {};
|
|
@@ -4912,7 +4915,7 @@ function getEnvConfig() {
|
|
|
4912
4915
|
if (timeout)
|
|
4913
4916
|
partial.timeout = Number(timeout);
|
|
4914
4917
|
if (Object.keys(partial).length > 0) {
|
|
4915
|
-
services[service] = partial;
|
|
4918
|
+
services[service] = [partial];
|
|
4916
4919
|
}
|
|
4917
4920
|
}
|
|
4918
4921
|
return Object.keys(services).length ? { services } : {};
|
|
@@ -4929,29 +4932,64 @@ function findLocalConfigPath() {
|
|
|
4929
4932
|
dir = parent;
|
|
4930
4933
|
}
|
|
4931
4934
|
}
|
|
4935
|
+
function isArrayEntry(raw) {
|
|
4936
|
+
return Array.isArray(raw);
|
|
4937
|
+
}
|
|
4932
4938
|
function loadConfig() {
|
|
4933
|
-
const
|
|
4939
|
+
const globalRaw = readJsonFile(GLOBAL_CONFIG_PATH);
|
|
4934
4940
|
const localPath = findLocalConfigPath();
|
|
4935
|
-
const
|
|
4941
|
+
const localRaw = localPath ? readJsonFile(localPath) : {};
|
|
4936
4942
|
const env2 = getEnvConfig();
|
|
4943
|
+
let globalDiskRaw = {};
|
|
4944
|
+
let localDiskRaw = {};
|
|
4945
|
+
try {
|
|
4946
|
+
if (existsSync(GLOBAL_CONFIG_PATH)) {
|
|
4947
|
+
globalDiskRaw = JSON.parse(readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
4948
|
+
}
|
|
4949
|
+
} catch {}
|
|
4950
|
+
try {
|
|
4951
|
+
if (localPath && existsSync(localPath)) {
|
|
4952
|
+
localDiskRaw = JSON.parse(readFileSync(localPath, "utf-8"));
|
|
4953
|
+
}
|
|
4954
|
+
} catch {}
|
|
4937
4955
|
const allServiceNames = new Set([
|
|
4938
|
-
...Object.keys(
|
|
4939
|
-
...Object.keys(
|
|
4956
|
+
...Object.keys(globalRaw.services ?? {}),
|
|
4957
|
+
...Object.keys(localRaw.services ?? {}),
|
|
4940
4958
|
...Object.keys(env2.services ?? {})
|
|
4941
4959
|
]);
|
|
4942
4960
|
const services = {};
|
|
4943
4961
|
for (const name of allServiceNames) {
|
|
4944
|
-
services[name]
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4962
|
+
const globalInstances = globalRaw.services?.[name] ?? [];
|
|
4963
|
+
const localInstances = localRaw.services?.[name] ?? [];
|
|
4964
|
+
const envInstances = env2.services?.[name] ?? [];
|
|
4965
|
+
const globalIsArray = isArrayEntry(globalDiskRaw.services?.[name]);
|
|
4966
|
+
const localIsArray = isArrayEntry(localDiskRaw.services?.[name]);
|
|
4967
|
+
if (globalIsArray || localIsArray) {
|
|
4968
|
+
const base = localInstances.length > 0 ? localInstances : globalInstances;
|
|
4969
|
+
if (envInstances.length > 0 && base.length > 0) {
|
|
4970
|
+
base[0] = { ...base[0], ...envInstances[0] };
|
|
4971
|
+
} else if (envInstances.length > 0) {
|
|
4972
|
+
services[name] = envInstances;
|
|
4973
|
+
continue;
|
|
4974
|
+
}
|
|
4975
|
+
services[name] = base;
|
|
4976
|
+
} else {
|
|
4977
|
+
const globalObj = globalInstances[0];
|
|
4978
|
+
const localObj = localInstances[0];
|
|
4979
|
+
const envObj = envInstances[0];
|
|
4980
|
+
const merged2 = {
|
|
4981
|
+
...globalObj,
|
|
4982
|
+
...localObj,
|
|
4983
|
+
...envObj
|
|
4984
|
+
};
|
|
4985
|
+
services[name] = [merged2];
|
|
4986
|
+
}
|
|
4949
4987
|
}
|
|
4950
4988
|
const merged = {
|
|
4951
4989
|
services,
|
|
4952
4990
|
defaults: {
|
|
4953
|
-
...
|
|
4954
|
-
...
|
|
4991
|
+
...globalRaw.defaults,
|
|
4992
|
+
...localRaw.defaults
|
|
4955
4993
|
}
|
|
4956
4994
|
};
|
|
4957
4995
|
return merged;
|
|
@@ -4962,16 +5000,20 @@ function resolveConfigRelativePath(filePath, configPath) {
|
|
|
4962
5000
|
}
|
|
4963
5001
|
return resolve(dirname(configPath), filePath);
|
|
4964
5002
|
}
|
|
4965
|
-
function getResolvedApiKeyFilePath(serviceName,
|
|
4966
|
-
if (!
|
|
5003
|
+
function getResolvedApiKeyFilePath(serviceName, instance, localPath, local, global) {
|
|
5004
|
+
if (!instance.apiKeyFile)
|
|
4967
5005
|
return;
|
|
4968
|
-
|
|
4969
|
-
|
|
5006
|
+
const localInstances = local.services?.[serviceName] ?? [];
|
|
5007
|
+
const localMatch = localInstances.find((i2) => i2.apiKeyFile && (instance.name ? i2.name === instance.name : true));
|
|
5008
|
+
if (localMatch) {
|
|
5009
|
+
return resolveConfigRelativePath(instance.apiKeyFile, localPath);
|
|
4970
5010
|
}
|
|
4971
|
-
|
|
4972
|
-
|
|
5011
|
+
const globalInstances = global.services?.[serviceName] ?? [];
|
|
5012
|
+
const globalMatch = globalInstances.find((i2) => i2.apiKeyFile && (instance.name ? i2.name === instance.name : true));
|
|
5013
|
+
if (globalMatch) {
|
|
5014
|
+
return resolveConfigRelativePath(instance.apiKeyFile, GLOBAL_CONFIG_PATH);
|
|
4973
5015
|
}
|
|
4974
|
-
return
|
|
5016
|
+
return instance.apiKeyFile;
|
|
4975
5017
|
}
|
|
4976
5018
|
function readApiKeyFile(filePath) {
|
|
4977
5019
|
if (!existsSync(filePath)) {
|
|
@@ -4983,75 +5025,132 @@ function readApiKeyFile(filePath) {
|
|
|
4983
5025
|
throw new Error(`Failed to read API key file: ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4984
5026
|
}
|
|
4985
5027
|
}
|
|
4986
|
-
function
|
|
5028
|
+
function getServiceInstances(serviceName) {
|
|
5029
|
+
const config = loadConfig();
|
|
5030
|
+
return config.services[serviceName] ?? [];
|
|
5031
|
+
}
|
|
5032
|
+
function resolveInstance(instances, instanceName) {
|
|
5033
|
+
if (!instances.length)
|
|
5034
|
+
return;
|
|
5035
|
+
if (!instanceName)
|
|
5036
|
+
return instances[0];
|
|
5037
|
+
return instances.find((i2) => i2.name?.toLowerCase() === instanceName.toLowerCase());
|
|
5038
|
+
}
|
|
5039
|
+
function getServiceConfig(serviceName, instanceName) {
|
|
4987
5040
|
const global = readJsonFile(GLOBAL_CONFIG_PATH);
|
|
4988
5041
|
const localPath = findLocalConfigPath();
|
|
4989
5042
|
const local = localPath ? readJsonFile(localPath) : {};
|
|
4990
5043
|
const config = loadConfig();
|
|
4991
|
-
const
|
|
4992
|
-
|
|
5044
|
+
const instances = config.services[serviceName] ?? [];
|
|
5045
|
+
const instance = resolveInstance(instances, instanceName);
|
|
5046
|
+
if (!instance?.baseUrl)
|
|
4993
5047
|
return null;
|
|
4994
5048
|
if (serviceName === "qbittorrent") {
|
|
4995
|
-
if (!
|
|
5049
|
+
if (!instance.username || !instance.password)
|
|
4996
5050
|
return null;
|
|
4997
5051
|
return {
|
|
4998
|
-
baseUrl:
|
|
4999
|
-
username:
|
|
5000
|
-
password:
|
|
5001
|
-
...
|
|
5052
|
+
baseUrl: instance.baseUrl,
|
|
5053
|
+
username: instance.username,
|
|
5054
|
+
password: instance.password,
|
|
5055
|
+
...instance.timeout ? { timeout: instance.timeout } : {}
|
|
5002
5056
|
};
|
|
5003
5057
|
}
|
|
5004
|
-
let apiKey =
|
|
5005
|
-
const apiKeyFilePath = getResolvedApiKeyFilePath(serviceName,
|
|
5058
|
+
let apiKey = instance.apiKey;
|
|
5059
|
+
const apiKeyFilePath = getResolvedApiKeyFilePath(serviceName, instance, localPath, local, global);
|
|
5006
5060
|
if (!apiKey && apiKeyFilePath) {
|
|
5007
5061
|
apiKey = readApiKeyFile(apiKeyFilePath);
|
|
5008
5062
|
}
|
|
5009
5063
|
if (!apiKey)
|
|
5010
5064
|
return null;
|
|
5011
5065
|
return {
|
|
5012
|
-
baseUrl:
|
|
5066
|
+
baseUrl: instance.baseUrl,
|
|
5013
5067
|
apiKey,
|
|
5014
|
-
...
|
|
5068
|
+
...instance.timeout ? { timeout: instance.timeout } : {}
|
|
5015
5069
|
};
|
|
5016
5070
|
}
|
|
5071
|
+
function serializeForDisk(config) {
|
|
5072
|
+
const services = {};
|
|
5073
|
+
for (const [name, instances] of Object.entries(config.services)) {
|
|
5074
|
+
if (instances.length === 1 && !instances[0].name) {
|
|
5075
|
+
const { name: _name, ...rest } = instances[0];
|
|
5076
|
+
services[name] = rest;
|
|
5077
|
+
} else {
|
|
5078
|
+
services[name] = instances;
|
|
5079
|
+
}
|
|
5080
|
+
}
|
|
5081
|
+
return { services, defaults: config.defaults };
|
|
5082
|
+
}
|
|
5017
5083
|
function saveGlobalConfig(config) {
|
|
5018
5084
|
mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
5019
|
-
writeFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(config, null, 2)}
|
|
5085
|
+
writeFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(serializeForDisk(config), null, 2)}
|
|
5020
5086
|
`);
|
|
5021
5087
|
}
|
|
5022
5088
|
function saveLocalConfig(config) {
|
|
5023
5089
|
const existingPath = findLocalConfigPath();
|
|
5024
5090
|
const targetPath = existingPath ?? join(process.cwd(), LOCAL_CONFIG_NAME);
|
|
5025
|
-
writeFileSync(targetPath, `${JSON.stringify(config, null, 2)}
|
|
5091
|
+
writeFileSync(targetPath, `${JSON.stringify(serializeForDisk(config), null, 2)}
|
|
5026
5092
|
`);
|
|
5027
5093
|
}
|
|
5094
|
+
function resolveArrayPath(instances, segment) {
|
|
5095
|
+
const byName = instances.find((i2) => i2.name === segment);
|
|
5096
|
+
if (byName)
|
|
5097
|
+
return byName;
|
|
5098
|
+
const idx = Number(segment);
|
|
5099
|
+
if (Number.isInteger(idx) && idx >= 0 && idx < instances.length)
|
|
5100
|
+
return instances[idx];
|
|
5101
|
+
return;
|
|
5102
|
+
}
|
|
5028
5103
|
function getConfigValue(key) {
|
|
5029
5104
|
const config = loadConfig();
|
|
5030
5105
|
const parts = key.split(".");
|
|
5031
5106
|
let current = config;
|
|
5032
|
-
for (
|
|
5107
|
+
for (let i2 = 0;i2 < parts.length; i2++) {
|
|
5033
5108
|
if (current == null || typeof current !== "object")
|
|
5034
5109
|
return;
|
|
5035
|
-
current
|
|
5110
|
+
if (Array.isArray(current)) {
|
|
5111
|
+
const resolved = resolveArrayPath(current, parts[i2]);
|
|
5112
|
+
if (resolved) {
|
|
5113
|
+
current = resolved;
|
|
5114
|
+
continue;
|
|
5115
|
+
}
|
|
5116
|
+
current = current[0]?.[parts[i2]];
|
|
5117
|
+
} else {
|
|
5118
|
+
current = current[parts[i2]];
|
|
5119
|
+
}
|
|
5036
5120
|
}
|
|
5037
5121
|
return current != null ? String(current) : undefined;
|
|
5038
5122
|
}
|
|
5039
5123
|
function setConfigValue(key, value, global = true) {
|
|
5040
5124
|
const configPath = global ? GLOBAL_CONFIG_PATH : findLocalConfigPath() ?? join(process.cwd(), LOCAL_CONFIG_NAME);
|
|
5041
|
-
const
|
|
5125
|
+
const raw = existsSync(configPath) ? JSON.parse(readFileSync(configPath, "utf-8")) : {};
|
|
5042
5126
|
const parts = key.split(".");
|
|
5043
|
-
let current =
|
|
5127
|
+
let current = raw;
|
|
5044
5128
|
for (let i2 = 0;i2 < parts.length - 1; i2++) {
|
|
5045
|
-
|
|
5046
|
-
|
|
5129
|
+
const part = parts[i2];
|
|
5130
|
+
if (Array.isArray(current[part])) {
|
|
5131
|
+
const nextPart = parts[i2 + 1];
|
|
5132
|
+
const resolved = resolveArrayPath(current[part], nextPart);
|
|
5133
|
+
if (resolved) {
|
|
5134
|
+
current = resolved;
|
|
5135
|
+
i2++;
|
|
5136
|
+
continue;
|
|
5137
|
+
}
|
|
5138
|
+
current = current[part][0];
|
|
5139
|
+
continue;
|
|
5047
5140
|
}
|
|
5048
|
-
current
|
|
5141
|
+
if (current[part] == null || typeof current[part] !== "object") {
|
|
5142
|
+
current[part] = {};
|
|
5143
|
+
}
|
|
5144
|
+
current = current[part];
|
|
5049
5145
|
}
|
|
5050
5146
|
current[parts[parts.length - 1]] = parseConfigValue(key, value);
|
|
5051
5147
|
if (global) {
|
|
5052
|
-
|
|
5148
|
+
mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
5149
|
+
writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}
|
|
5150
|
+
`);
|
|
5053
5151
|
} else {
|
|
5054
|
-
|
|
5152
|
+
writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}
|
|
5153
|
+
`);
|
|
5055
5154
|
}
|
|
5056
5155
|
}
|
|
5057
5156
|
function parseConfigValue(key, value) {
|
|
@@ -5293,14 +5392,10 @@ function formatBytes(bytes) {
|
|
|
5293
5392
|
function formatDate(value) {
|
|
5294
5393
|
if (typeof value !== "string" && !(value instanceof Date))
|
|
5295
5394
|
return String(value);
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
if (Number.isNaN(d2.getTime()))
|
|
5299
|
-
return String(value);
|
|
5300
|
-
return d2.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
|
|
5301
|
-
} catch {
|
|
5395
|
+
const d2 = new Date(value);
|
|
5396
|
+
if (Number.isNaN(d2.getTime()))
|
|
5302
5397
|
return String(value);
|
|
5303
|
-
}
|
|
5398
|
+
return d2.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
|
|
5304
5399
|
}
|
|
5305
5400
|
function stripAnsi3(str) {
|
|
5306
5401
|
return str.replace(ANSI_PATTERN, "");
|
|
@@ -5322,6 +5417,7 @@ var init_output = __esm(() => {
|
|
|
5322
5417
|
});
|
|
5323
5418
|
|
|
5324
5419
|
// src/cli/commands/service.ts
|
|
5420
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
5325
5421
|
function limitResults(results, limit) {
|
|
5326
5422
|
if (limit === undefined)
|
|
5327
5423
|
return results;
|
|
@@ -5352,6 +5448,11 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
5352
5448
|
description: "Cherry-pick fields (comma-separated, JSON mode)"
|
|
5353
5449
|
},
|
|
5354
5450
|
yes: { type: "boolean", alias: "y", description: "Skip confirmation prompts" },
|
|
5451
|
+
instance: {
|
|
5452
|
+
type: "string",
|
|
5453
|
+
alias: "i",
|
|
5454
|
+
description: "Instance name (for multi-instance services)"
|
|
5455
|
+
},
|
|
5355
5456
|
...(action.args ?? []).reduce((acc, arg) => {
|
|
5356
5457
|
acc[arg.name] = {
|
|
5357
5458
|
type: arg.type === "boolean" ? "boolean" : arg.type === "number" ? "string" : "string",
|
|
@@ -5362,10 +5463,17 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
5362
5463
|
}, {})
|
|
5363
5464
|
},
|
|
5364
5465
|
async run({ args }) {
|
|
5365
|
-
const
|
|
5466
|
+
const instanceName = args.instance;
|
|
5467
|
+
const config = getServiceConfig(serviceName, instanceName);
|
|
5366
5468
|
if (!config) {
|
|
5367
|
-
|
|
5368
|
-
|
|
5469
|
+
if (instanceName) {
|
|
5470
|
+
const available = getServiceInstances(serviceName).map((i2) => i2.name).filter(Boolean);
|
|
5471
|
+
const hint = available.length ? ` Available: ${available.join(", ")}` : "";
|
|
5472
|
+
consola.error(`${serviceName} instance '${instanceName}' is not configured.${hint}`);
|
|
5473
|
+
} else {
|
|
5474
|
+
const envHint = serviceName === "qbittorrent" ? `TSARR_QBITTORRENT_URL, TSARR_QBITTORRENT_USERNAME, and TSARR_QBITTORRENT_PASSWORD` : `TSARR_${serviceName.toUpperCase()}_URL and TSARR_${serviceName.toUpperCase()}_API_KEY`;
|
|
5475
|
+
consola.error(`${serviceName} is not configured. Run \`tsarr config init\` or set ${envHint} environment variables.`);
|
|
5476
|
+
}
|
|
5369
5477
|
process.exit(1);
|
|
5370
5478
|
}
|
|
5371
5479
|
try {
|
|
@@ -5393,7 +5501,7 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
5393
5501
|
const noHeader = process.argv.includes("--no-header") || !!args.noHeader;
|
|
5394
5502
|
const dryRun = !!(args["dry-run"] ?? args.dryRun ?? process.argv.includes("--dry-run"));
|
|
5395
5503
|
if (dryRun) {
|
|
5396
|
-
formatOutput(buildDryRunPreview(format, serviceName, resource.name, action.name, resolvedArgs), {
|
|
5504
|
+
formatOutput(buildDryRunPreview(format, serviceName, resource.name, action.name, resolvedArgs, instanceName), {
|
|
5397
5505
|
format,
|
|
5398
5506
|
noHeader
|
|
5399
5507
|
});
|
|
@@ -5474,6 +5582,44 @@ Run \`tsarr config init\` or set TSARR_${serviceName.toUpperCase()}_API_KEY`;
|
|
|
5474
5582
|
subCommands
|
|
5475
5583
|
});
|
|
5476
5584
|
}
|
|
5585
|
+
function unwrapData(result) {
|
|
5586
|
+
return result?.data ?? result;
|
|
5587
|
+
}
|
|
5588
|
+
function readJsonInput(filePath) {
|
|
5589
|
+
const raw = filePath === "-" ? readFileSync2(0, "utf-8") : readFileSync2(filePath, "utf-8");
|
|
5590
|
+
return JSON.parse(raw);
|
|
5591
|
+
}
|
|
5592
|
+
function parseBooleanArg(value, fallback) {
|
|
5593
|
+
if (value === undefined)
|
|
5594
|
+
return fallback;
|
|
5595
|
+
if (typeof value === "boolean")
|
|
5596
|
+
return value;
|
|
5597
|
+
if (typeof value === "string") {
|
|
5598
|
+
const normalized = value.trim().toLowerCase();
|
|
5599
|
+
if (normalized === "true")
|
|
5600
|
+
return true;
|
|
5601
|
+
if (normalized === "false")
|
|
5602
|
+
return false;
|
|
5603
|
+
}
|
|
5604
|
+
return Boolean(value);
|
|
5605
|
+
}
|
|
5606
|
+
function resolveQualityProfileId(profiles, profileId) {
|
|
5607
|
+
const profile = profiles.find((item) => item?.id === profileId);
|
|
5608
|
+
if (!profile) {
|
|
5609
|
+
throw new Error(`Quality profile ${profileId} was not found.`);
|
|
5610
|
+
}
|
|
5611
|
+
return profileId;
|
|
5612
|
+
}
|
|
5613
|
+
function resolveRootFolderPath(folders, rootFolderPath) {
|
|
5614
|
+
const folder = folders.find((item) => item?.path === rootFolderPath);
|
|
5615
|
+
if (!folder) {
|
|
5616
|
+
throw new Error(`Root folder "${rootFolderPath}" was not found.`);
|
|
5617
|
+
}
|
|
5618
|
+
return rootFolderPath;
|
|
5619
|
+
}
|
|
5620
|
+
function getApiStatus(result) {
|
|
5621
|
+
return result?.error?.status ?? result?.response?.status;
|
|
5622
|
+
}
|
|
5477
5623
|
function coerceBooleanArg(value) {
|
|
5478
5624
|
if (typeof value === "boolean")
|
|
5479
5625
|
return value;
|
|
@@ -5486,19 +5632,21 @@ function coerceBooleanArg(value) {
|
|
|
5486
5632
|
}
|
|
5487
5633
|
return Boolean(value);
|
|
5488
5634
|
}
|
|
5489
|
-
function buildDryRunPreview(format, serviceName, resourceName, actionName, args) {
|
|
5490
|
-
const filteredArgs = Object.fromEntries(Object.entries(args).filter(([key, value]) => value !== undefined && key !== "_" && key !== "json" && key !== "table" && key !== "plain" && key !== "quiet" && key !== "select" && key !== "no-header" && key !== "noHeader" && key !== "dry-run" && key !== "dryRun"));
|
|
5635
|
+
function buildDryRunPreview(format, serviceName, resourceName, actionName, args, instanceName) {
|
|
5636
|
+
const filteredArgs = Object.fromEntries(Object.entries(args).filter(([key, value]) => value !== undefined && key !== "_" && key !== "json" && key !== "table" && key !== "plain" && key !== "quiet" && key !== "select" && key !== "no-header" && key !== "noHeader" && key !== "dry-run" && key !== "dryRun" && key !== "instance"));
|
|
5637
|
+
const serviceLabel = instanceName ? `${serviceName}[${instanceName}]` : serviceName;
|
|
5491
5638
|
if (format === "json") {
|
|
5492
5639
|
return {
|
|
5493
5640
|
dryRun: true,
|
|
5494
5641
|
service: serviceName,
|
|
5642
|
+
...instanceName ? { instance: instanceName } : {},
|
|
5495
5643
|
resource: resourceName,
|
|
5496
5644
|
action: actionName,
|
|
5497
5645
|
args: filteredArgs
|
|
5498
5646
|
};
|
|
5499
5647
|
}
|
|
5500
5648
|
return {
|
|
5501
|
-
message: `Dry run: would execute ${
|
|
5649
|
+
message: `Dry run: would execute ${serviceLabel} ${resourceName} ${actionName}${formatDryRunArgs(filteredArgs)}`
|
|
5502
5650
|
};
|
|
5503
5651
|
}
|
|
5504
5652
|
function formatDryRunArgs(args) {
|
|
@@ -5514,8 +5662,6 @@ Run \`tsarr config init\` or set TSARR_${serviceName.toUpperCase()}_API_KEY`);
|
|
|
5514
5662
|
} else if (error instanceof ConnectionError) {
|
|
5515
5663
|
consola.error(`Connection error: ${error.message}
|
|
5516
5664
|
Run \`tsarr doctor\` to diagnose.`);
|
|
5517
|
-
} else if (error instanceof NotFoundError) {
|
|
5518
|
-
consola.error(error.message);
|
|
5519
5665
|
} else if (error instanceof TsarrError) {
|
|
5520
5666
|
consola.error(`Error: ${error.message}`);
|
|
5521
5667
|
} else if (error instanceof Error) {
|
|
@@ -5572,51 +5718,12 @@ __export(exports_radarr3, {
|
|
|
5572
5718
|
resources: () => resources,
|
|
5573
5719
|
radarr: () => radarr
|
|
5574
5720
|
});
|
|
5575
|
-
import { readFileSync as readFileSync2 } from "node:fs";
|
|
5576
|
-
function unwrapData(result) {
|
|
5577
|
-
return result?.data ?? result;
|
|
5578
|
-
}
|
|
5579
|
-
function parseBooleanArg(value, fallback) {
|
|
5580
|
-
if (value === undefined)
|
|
5581
|
-
return fallback;
|
|
5582
|
-
if (typeof value === "boolean")
|
|
5583
|
-
return value;
|
|
5584
|
-
if (typeof value === "string") {
|
|
5585
|
-
const normalized = value.trim().toLowerCase();
|
|
5586
|
-
if (normalized === "true")
|
|
5587
|
-
return true;
|
|
5588
|
-
if (normalized === "false")
|
|
5589
|
-
return false;
|
|
5590
|
-
}
|
|
5591
|
-
return Boolean(value);
|
|
5592
|
-
}
|
|
5593
|
-
function resolveQualityProfileId(profiles, profileId) {
|
|
5594
|
-
const profile = profiles.find((item) => item?.id === profileId);
|
|
5595
|
-
if (!profile) {
|
|
5596
|
-
throw new Error(`Quality profile ${profileId} was not found.`);
|
|
5597
|
-
}
|
|
5598
|
-
return profileId;
|
|
5599
|
-
}
|
|
5600
|
-
function resolveRootFolderPath(folders, rootFolderPath) {
|
|
5601
|
-
const folder = folders.find((item) => item?.path === rootFolderPath);
|
|
5602
|
-
if (!folder) {
|
|
5603
|
-
throw new Error(`Root folder "${rootFolderPath}" was not found.`);
|
|
5604
|
-
}
|
|
5605
|
-
return rootFolderPath;
|
|
5606
|
-
}
|
|
5607
5721
|
async function findMovieByTmdbId(client2, tmdbId) {
|
|
5608
5722
|
if (tmdbId === undefined)
|
|
5609
5723
|
return;
|
|
5610
5724
|
const movies = unwrapData(await client2.getMovies());
|
|
5611
5725
|
return movies.find((movie) => movie?.tmdbId === tmdbId);
|
|
5612
5726
|
}
|
|
5613
|
-
function getApiStatus(result) {
|
|
5614
|
-
return result?.error?.status ?? result?.response?.status;
|
|
5615
|
-
}
|
|
5616
|
-
function readJsonInput(filePath) {
|
|
5617
|
-
const raw = filePath === "-" ? readFileSync2(0, "utf-8") : readFileSync2(filePath, "utf-8");
|
|
5618
|
-
return JSON.parse(raw);
|
|
5619
|
-
}
|
|
5620
5727
|
var resources, radarr;
|
|
5621
5728
|
var init_radarr3 = __esm(() => {
|
|
5622
5729
|
init_radarr2();
|
|
@@ -8684,38 +8791,6 @@ __export(exports_sonarr3, {
|
|
|
8684
8791
|
sonarr: () => sonarr,
|
|
8685
8792
|
resources: () => resources2
|
|
8686
8793
|
});
|
|
8687
|
-
import { readFileSync as readFileSync3 } from "node:fs";
|
|
8688
|
-
function unwrapData2(result) {
|
|
8689
|
-
return result?.data ?? result;
|
|
8690
|
-
}
|
|
8691
|
-
function parseBooleanArg2(value, fallback) {
|
|
8692
|
-
if (value === undefined)
|
|
8693
|
-
return fallback;
|
|
8694
|
-
if (typeof value === "boolean")
|
|
8695
|
-
return value;
|
|
8696
|
-
if (typeof value === "string") {
|
|
8697
|
-
const normalized = value.trim().toLowerCase();
|
|
8698
|
-
if (normalized === "true")
|
|
8699
|
-
return true;
|
|
8700
|
-
if (normalized === "false")
|
|
8701
|
-
return false;
|
|
8702
|
-
}
|
|
8703
|
-
return Boolean(value);
|
|
8704
|
-
}
|
|
8705
|
-
function resolveQualityProfileId2(profiles, profileId) {
|
|
8706
|
-
const profile = profiles.find((item) => item?.id === profileId);
|
|
8707
|
-
if (!profile) {
|
|
8708
|
-
throw new Error(`Quality profile ${profileId} was not found.`);
|
|
8709
|
-
}
|
|
8710
|
-
return profileId;
|
|
8711
|
-
}
|
|
8712
|
-
function resolveRootFolderPath2(folders, rootFolderPath) {
|
|
8713
|
-
const folder = folders.find((item) => item?.path === rootFolderPath);
|
|
8714
|
-
if (!folder) {
|
|
8715
|
-
throw new Error(`Root folder "${rootFolderPath}" was not found.`);
|
|
8716
|
-
}
|
|
8717
|
-
return rootFolderPath;
|
|
8718
|
-
}
|
|
8719
8794
|
function formatSeriesListItem(series) {
|
|
8720
8795
|
const seasons = Array.isArray(series?.seasons) ? series.seasons.filter((season) => season?.seasonNumber !== 0) : [];
|
|
8721
8796
|
const statistics = series?.statistics ?? {};
|
|
@@ -8728,26 +8803,19 @@ function formatSeriesListItem(series) {
|
|
|
8728
8803
|
};
|
|
8729
8804
|
}
|
|
8730
8805
|
async function lookupSeriesByTvdbId(client3, tvdbId) {
|
|
8731
|
-
const tvdbSearch =
|
|
8806
|
+
const tvdbSearch = unwrapData(await client3.searchSeries(`tvdb:${tvdbId}`));
|
|
8732
8807
|
const exactTvdbMatch = tvdbSearch.find((series) => series?.tvdbId === tvdbId);
|
|
8733
8808
|
if (exactTvdbMatch)
|
|
8734
8809
|
return exactTvdbMatch;
|
|
8735
|
-
const fallbackSearch =
|
|
8810
|
+
const fallbackSearch = unwrapData(await client3.searchSeries(String(tvdbId)));
|
|
8736
8811
|
return fallbackSearch.find((series) => series?.tvdbId === tvdbId);
|
|
8737
8812
|
}
|
|
8738
8813
|
async function findSeriesByTvdbId(client3, tvdbId) {
|
|
8739
8814
|
if (tvdbId === undefined)
|
|
8740
8815
|
return;
|
|
8741
|
-
const series =
|
|
8816
|
+
const series = unwrapData(await client3.getSeries());
|
|
8742
8817
|
return series.find((item) => item?.tvdbId === tvdbId);
|
|
8743
8818
|
}
|
|
8744
|
-
function getApiStatus2(result) {
|
|
8745
|
-
return result?.error?.status ?? result?.response?.status;
|
|
8746
|
-
}
|
|
8747
|
-
function readJsonInput2(filePath) {
|
|
8748
|
-
const raw = filePath === "-" ? readFileSync3(0, "utf-8") : readFileSync3(filePath, "utf-8");
|
|
8749
|
-
return JSON.parse(raw);
|
|
8750
|
-
}
|
|
8751
8819
|
var resources2, sonarr;
|
|
8752
8820
|
var init_sonarr3 = __esm(() => {
|
|
8753
8821
|
init_sonarr2();
|
|
@@ -8772,7 +8840,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
8772
8840
|
"status"
|
|
8773
8841
|
],
|
|
8774
8842
|
run: async (c3) => {
|
|
8775
|
-
const series =
|
|
8843
|
+
const series = unwrapData(await c3.getSeries());
|
|
8776
8844
|
return series.map(formatSeriesListItem);
|
|
8777
8845
|
}
|
|
8778
8846
|
},
|
|
@@ -8792,7 +8860,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
8792
8860
|
],
|
|
8793
8861
|
run: async (c3, a2) => {
|
|
8794
8862
|
const result = await c3.getSeriesById(a2.id);
|
|
8795
|
-
const series =
|
|
8863
|
+
const series = unwrapData(result);
|
|
8796
8864
|
return formatSeriesListItem(series);
|
|
8797
8865
|
}
|
|
8798
8866
|
},
|
|
@@ -8805,7 +8873,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
8805
8873
|
],
|
|
8806
8874
|
columns: ["tvdbId", "title", "year", "overview"],
|
|
8807
8875
|
run: async (c3, a2) => {
|
|
8808
|
-
const results =
|
|
8876
|
+
const results = unwrapData(await c3.searchSeries(a2.term));
|
|
8809
8877
|
return limitResults(results, a2.limit);
|
|
8810
8878
|
}
|
|
8811
8879
|
},
|
|
@@ -8829,7 +8897,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
8829
8897
|
} else {
|
|
8830
8898
|
const term = await promptIfMissing(a2.term, "Search term:");
|
|
8831
8899
|
const searchResult = await c3.searchSeries(term);
|
|
8832
|
-
const results =
|
|
8900
|
+
const results = unwrapData(searchResult);
|
|
8833
8901
|
if (!Array.isArray(results) || results.length === 0) {
|
|
8834
8902
|
throw new Error("No series found.");
|
|
8835
8903
|
}
|
|
@@ -8843,17 +8911,17 @@ var init_sonarr3 = __esm(() => {
|
|
|
8843
8911
|
}
|
|
8844
8912
|
}
|
|
8845
8913
|
const profilesResult = await c3.getQualityProfiles();
|
|
8846
|
-
const profiles =
|
|
8914
|
+
const profiles = unwrapData(profilesResult);
|
|
8847
8915
|
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
8848
8916
|
throw new Error("No quality profiles found. Configure one in Sonarr first.");
|
|
8849
8917
|
}
|
|
8850
|
-
const profileId = a2["quality-profile-id"] !== undefined ?
|
|
8918
|
+
const profileId = a2["quality-profile-id"] !== undefined ? resolveQualityProfileId(profiles, a2["quality-profile-id"]) : Number(await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) }))));
|
|
8851
8919
|
const foldersResult = await c3.getRootFolders();
|
|
8852
|
-
const folders =
|
|
8920
|
+
const folders = unwrapData(foldersResult);
|
|
8853
8921
|
if (!Array.isArray(folders) || folders.length === 0) {
|
|
8854
8922
|
throw new Error("No root folders found. Configure one in Sonarr first.");
|
|
8855
8923
|
}
|
|
8856
|
-
const rootFolderPath = a2["root-folder"] !== undefined ?
|
|
8924
|
+
const rootFolderPath = a2["root-folder"] !== undefined ? resolveRootFolderPath(folders, a2["root-folder"]) : await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
8857
8925
|
const confirmed = await promptConfirm(`Add "${series.title} (${series.year})"?`, !!a2.yes);
|
|
8858
8926
|
if (!confirmed)
|
|
8859
8927
|
throw new Error("Cancelled.");
|
|
@@ -8861,10 +8929,10 @@ var init_sonarr3 = __esm(() => {
|
|
|
8861
8929
|
...series,
|
|
8862
8930
|
qualityProfileId: profileId,
|
|
8863
8931
|
rootFolderPath,
|
|
8864
|
-
monitored:
|
|
8932
|
+
monitored: parseBooleanArg(a2.monitored, true),
|
|
8865
8933
|
addOptions: { searchForMissingEpisodes: true }
|
|
8866
8934
|
});
|
|
8867
|
-
if (addResult?.error &&
|
|
8935
|
+
if (addResult?.error && getApiStatus(addResult) === 400) {
|
|
8868
8936
|
const existingSeries = await findSeriesByTvdbId(c3, series.tvdbId);
|
|
8869
8937
|
if (existingSeries) {
|
|
8870
8938
|
throw new Error(`${existingSeries.title} is already in your library (ID: ${existingSeries.id})`);
|
|
@@ -8926,7 +8994,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
8926
8994
|
const seriesResult = await c3.getSeriesById(a2.id);
|
|
8927
8995
|
if (seriesResult?.error)
|
|
8928
8996
|
return seriesResult;
|
|
8929
|
-
const series =
|
|
8997
|
+
const series = unwrapData(seriesResult);
|
|
8930
8998
|
const deleteResult = await c3.deleteSeries(a2.id, {
|
|
8931
8999
|
deleteFiles: a2["delete-files"],
|
|
8932
9000
|
addImportListExclusion: a2["add-import-list-exclusion"]
|
|
@@ -9027,7 +9095,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9027
9095
|
const tagResult = await c3.getTag(a2.id);
|
|
9028
9096
|
if (tagResult?.error)
|
|
9029
9097
|
return tagResult;
|
|
9030
|
-
const tag =
|
|
9098
|
+
const tag = unwrapData(tagResult);
|
|
9031
9099
|
const deleteResult = await c3.deleteTag(a2.id);
|
|
9032
9100
|
if (deleteResult?.error)
|
|
9033
9101
|
return deleteResult;
|
|
@@ -9097,7 +9165,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9097
9165
|
run: async (c3, a2) => {
|
|
9098
9166
|
if (a2.since) {
|
|
9099
9167
|
const result2 = await c3.getHistorySince(a2.since, a2["series-id"]);
|
|
9100
|
-
const items2 =
|
|
9168
|
+
const items2 = unwrapData(result2);
|
|
9101
9169
|
if (a2.until) {
|
|
9102
9170
|
const untilDate = new Date(a2.until);
|
|
9103
9171
|
return items2.filter((item) => new Date(item.date) <= untilDate);
|
|
@@ -9105,7 +9173,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9105
9173
|
return items2;
|
|
9106
9174
|
}
|
|
9107
9175
|
const result = await c3.getHistory(undefined, undefined, undefined, undefined, a2["series-id"]);
|
|
9108
|
-
const items =
|
|
9176
|
+
const items = unwrapData(result);
|
|
9109
9177
|
if (a2.until) {
|
|
9110
9178
|
const untilDate = new Date(a2.until);
|
|
9111
9179
|
return items.filter((item) => new Date(item.date) <= untilDate);
|
|
@@ -9155,7 +9223,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9155
9223
|
columns: ["id", "seriesTitle", "title", "seasonNumber", "episodeNumber", "airDateUtc"],
|
|
9156
9224
|
run: async (c3, a2) => {
|
|
9157
9225
|
const result = await c3.getCalendar(a2.start, a2.end, a2.unmonitored);
|
|
9158
|
-
const episodes =
|
|
9226
|
+
const episodes = unwrapData(result);
|
|
9159
9227
|
return episodes.map((ep) => ({
|
|
9160
9228
|
...ep,
|
|
9161
9229
|
seriesTitle: ep.seriesTitle || ep.series?.title || "—"
|
|
@@ -9184,7 +9252,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9184
9252
|
name: "add",
|
|
9185
9253
|
description: "Add a notification from JSON file or stdin",
|
|
9186
9254
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
9187
|
-
run: async (c3, a2) => c3.addNotification(
|
|
9255
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput(a2.file))
|
|
9188
9256
|
},
|
|
9189
9257
|
{
|
|
9190
9258
|
name: "edit",
|
|
@@ -9194,8 +9262,8 @@ var init_sonarr3 = __esm(() => {
|
|
|
9194
9262
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
9195
9263
|
],
|
|
9196
9264
|
run: async (c3, a2) => {
|
|
9197
|
-
const existing =
|
|
9198
|
-
return c3.updateNotification(a2.id, { ...existing, ...
|
|
9265
|
+
const existing = unwrapData(await c3.getNotification(a2.id));
|
|
9266
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
9199
9267
|
}
|
|
9200
9268
|
},
|
|
9201
9269
|
{
|
|
@@ -9232,7 +9300,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9232
9300
|
name: "add",
|
|
9233
9301
|
description: "Add a download client from JSON file or stdin",
|
|
9234
9302
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
9235
|
-
run: async (c3, a2) => c3.addDownloadClient(
|
|
9303
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput(a2.file))
|
|
9236
9304
|
},
|
|
9237
9305
|
{
|
|
9238
9306
|
name: "edit",
|
|
@@ -9242,8 +9310,8 @@ var init_sonarr3 = __esm(() => {
|
|
|
9242
9310
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
9243
9311
|
],
|
|
9244
9312
|
run: async (c3, a2) => {
|
|
9245
|
-
const existing =
|
|
9246
|
-
return c3.updateDownloadClient(a2.id, { ...existing, ...
|
|
9313
|
+
const existing = unwrapData(await c3.getDownloadClient(a2.id));
|
|
9314
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
9247
9315
|
}
|
|
9248
9316
|
},
|
|
9249
9317
|
{
|
|
@@ -9317,7 +9385,7 @@ var init_sonarr3 = __esm(() => {
|
|
|
9317
9385
|
name: "add",
|
|
9318
9386
|
description: "Add an import list from JSON file or stdin",
|
|
9319
9387
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
9320
|
-
run: async (c3, a2) => c3.addImportList(
|
|
9388
|
+
run: async (c3, a2) => c3.addImportList(readJsonInput(a2.file))
|
|
9321
9389
|
},
|
|
9322
9390
|
{
|
|
9323
9391
|
name: "edit",
|
|
@@ -9327,8 +9395,8 @@ var init_sonarr3 = __esm(() => {
|
|
|
9327
9395
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
9328
9396
|
],
|
|
9329
9397
|
run: async (c3, a2) => {
|
|
9330
|
-
const existing =
|
|
9331
|
-
return c3.updateImportList(a2.id, { ...existing, ...
|
|
9398
|
+
const existing = unwrapData(await c3.getImportList(a2.id));
|
|
9399
|
+
return c3.updateImportList(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
9332
9400
|
}
|
|
9333
9401
|
},
|
|
9334
9402
|
{
|
|
@@ -11836,38 +11904,12 @@ var exports_lidarr3 = {};
|
|
|
11836
11904
|
__export(exports_lidarr3, {
|
|
11837
11905
|
lidarr: () => lidarr
|
|
11838
11906
|
});
|
|
11839
|
-
|
|
11840
|
-
function unwrapData3(result) {
|
|
11841
|
-
return result?.data ?? result;
|
|
11842
|
-
}
|
|
11843
|
-
function formatAlbumListItem(album) {
|
|
11844
|
-
return {
|
|
11845
|
-
...album,
|
|
11846
|
-
artistName: album?.artistName ?? album?.artist?.artistName ?? "—"
|
|
11847
|
-
};
|
|
11848
|
-
}
|
|
11849
|
-
function formatQueueListItem(item) {
|
|
11850
|
-
return {
|
|
11851
|
-
...item,
|
|
11852
|
-
artistName: item?.artistName ?? item?.artist?.artistName ?? "—"
|
|
11853
|
-
};
|
|
11854
|
-
}
|
|
11855
|
-
function formatHistoryListItem(item) {
|
|
11856
|
-
return {
|
|
11857
|
-
...item,
|
|
11858
|
-
artistName: item?.artistName ?? item?.artist?.artistName ?? "—"
|
|
11859
|
-
};
|
|
11860
|
-
}
|
|
11861
|
-
function formatBlocklistItem(item) {
|
|
11907
|
+
function withArtistName(item) {
|
|
11862
11908
|
return {
|
|
11863
11909
|
...item,
|
|
11864
11910
|
artistName: item?.artistName ?? item?.artist?.artistName ?? "—"
|
|
11865
11911
|
};
|
|
11866
11912
|
}
|
|
11867
|
-
function readJsonInput3(filePath) {
|
|
11868
|
-
const raw = filePath === "-" ? readFileSync4(0, "utf-8") : readFileSync4(filePath, "utf-8");
|
|
11869
|
-
return JSON.parse(raw);
|
|
11870
|
-
}
|
|
11871
11913
|
var resources3, lidarr;
|
|
11872
11914
|
var init_lidarr3 = __esm(() => {
|
|
11873
11915
|
init_lidarr2();
|
|
@@ -11903,7 +11945,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
11903
11945
|
description: "Search and add an artist",
|
|
11904
11946
|
args: [{ name: "term", description: "Search term", required: true }],
|
|
11905
11947
|
run: async (c3, a2) => {
|
|
11906
|
-
const results =
|
|
11948
|
+
const results = unwrapData(await c3.searchArtists(a2.term));
|
|
11907
11949
|
if (!Array.isArray(results) || results.length === 0) {
|
|
11908
11950
|
throw new Error("No artists found.");
|
|
11909
11951
|
}
|
|
@@ -11915,12 +11957,12 @@ var init_lidarr3 = __esm(() => {
|
|
|
11915
11957
|
if (!artist) {
|
|
11916
11958
|
throw new Error("Selected artist was not found in the search results.");
|
|
11917
11959
|
}
|
|
11918
|
-
const profiles =
|
|
11960
|
+
const profiles = unwrapData(await c3.getQualityProfiles());
|
|
11919
11961
|
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
11920
11962
|
throw new Error("No quality profiles found. Configure one in Lidarr first.");
|
|
11921
11963
|
}
|
|
11922
11964
|
const profileId = await promptSelect("Select quality profile:", profiles.map((profile) => ({ label: profile.name, value: String(profile.id) })));
|
|
11923
|
-
const folders =
|
|
11965
|
+
const folders = unwrapData(await c3.getRootFolders());
|
|
11924
11966
|
if (!Array.isArray(folders) || folders.length === 0) {
|
|
11925
11967
|
throw new Error("No root folders found. Configure one in Lidarr first.");
|
|
11926
11968
|
}
|
|
@@ -11947,7 +11989,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
11947
11989
|
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
11948
11990
|
],
|
|
11949
11991
|
run: async (c3, a2) => {
|
|
11950
|
-
const artist =
|
|
11992
|
+
const artist = unwrapData(await c3.getArtist(a2.id));
|
|
11951
11993
|
const updates = { ...artist };
|
|
11952
11994
|
if (a2.monitored !== undefined)
|
|
11953
11995
|
updates.monitored = a2.monitored === "true";
|
|
@@ -11992,8 +12034,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
11992
12034
|
description: "List all albums",
|
|
11993
12035
|
columns: ["id", "artistName", "title", "monitored"],
|
|
11994
12036
|
run: async (c3) => {
|
|
11995
|
-
const albums =
|
|
11996
|
-
return albums.map(
|
|
12037
|
+
const albums = unwrapData(await c3.getAlbums());
|
|
12038
|
+
return albums.map(withArtistName);
|
|
11997
12039
|
}
|
|
11998
12040
|
},
|
|
11999
12041
|
{
|
|
@@ -12001,8 +12043,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12001
12043
|
description: "Get an album by ID",
|
|
12002
12044
|
args: [{ name: "id", description: "Album ID", required: true, type: "number" }],
|
|
12003
12045
|
run: async (c3, a2) => {
|
|
12004
|
-
const album =
|
|
12005
|
-
return
|
|
12046
|
+
const album = unwrapData(await c3.getAlbum(a2.id));
|
|
12047
|
+
return withArtistName(album);
|
|
12006
12048
|
}
|
|
12007
12049
|
},
|
|
12008
12050
|
{
|
|
@@ -12012,15 +12054,15 @@ var init_lidarr3 = __esm(() => {
|
|
|
12012
12054
|
columns: ["foreignAlbumId", "artistName", "title", "monitored"],
|
|
12013
12055
|
idField: "foreignAlbumId",
|
|
12014
12056
|
run: async (c3, a2) => {
|
|
12015
|
-
const albums =
|
|
12016
|
-
return albums.map(
|
|
12057
|
+
const albums = unwrapData(await c3.searchAlbums(a2.term));
|
|
12058
|
+
return albums.map(withArtistName);
|
|
12017
12059
|
}
|
|
12018
12060
|
},
|
|
12019
12061
|
{
|
|
12020
12062
|
name: "add",
|
|
12021
12063
|
description: "Add an album from JSON file or stdin",
|
|
12022
12064
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
12023
|
-
run: async (c3, a2) => c3.addAlbum(
|
|
12065
|
+
run: async (c3, a2) => c3.addAlbum(readJsonInput(a2.file))
|
|
12024
12066
|
},
|
|
12025
12067
|
{
|
|
12026
12068
|
name: "edit",
|
|
@@ -12030,8 +12072,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12030
12072
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
12031
12073
|
],
|
|
12032
12074
|
run: async (c3, a2) => {
|
|
12033
|
-
const existing =
|
|
12034
|
-
return c3.updateAlbum(a2.id, { ...existing, ...
|
|
12075
|
+
const existing = unwrapData(await c3.getAlbum(a2.id));
|
|
12076
|
+
return c3.updateAlbum(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
12035
12077
|
}
|
|
12036
12078
|
},
|
|
12037
12079
|
{
|
|
@@ -12106,7 +12148,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
12106
12148
|
const tagResult = await c3.getTag(a2.id);
|
|
12107
12149
|
if (tagResult?.error)
|
|
12108
12150
|
return tagResult;
|
|
12109
|
-
const tag =
|
|
12151
|
+
const tag = unwrapData(tagResult);
|
|
12110
12152
|
const deleteResult = await c3.deleteTag(a2.id);
|
|
12111
12153
|
if (deleteResult?.error)
|
|
12112
12154
|
return deleteResult;
|
|
@@ -12130,8 +12172,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12130
12172
|
description: "List queue items",
|
|
12131
12173
|
columns: ["id", "artistName", "title", "status", "sizeleft", "timeleft"],
|
|
12132
12174
|
run: async (c3) => {
|
|
12133
|
-
const items =
|
|
12134
|
-
return items.map(
|
|
12175
|
+
const items = unwrapData(await c3.getQueue());
|
|
12176
|
+
return items.map(withArtistName);
|
|
12135
12177
|
}
|
|
12136
12178
|
},
|
|
12137
12179
|
{
|
|
@@ -12175,9 +12217,9 @@ var init_lidarr3 = __esm(() => {
|
|
|
12175
12217
|
],
|
|
12176
12218
|
columns: ["id", "artistName", "sourceTitle", "eventType", "date"],
|
|
12177
12219
|
run: async (c3, a2) => {
|
|
12178
|
-
const items = a2.since ?
|
|
12220
|
+
const items = a2.since ? unwrapData(await c3.getHistorySince(a2.since)) : unwrapData(await c3.getHistory());
|
|
12179
12221
|
const filtered = a2.until ? items.filter((item) => new Date(item.date) <= new Date(a2.until)) : items;
|
|
12180
|
-
return filtered.map(
|
|
12222
|
+
return filtered.map(withArtistName);
|
|
12181
12223
|
}
|
|
12182
12224
|
}
|
|
12183
12225
|
]
|
|
@@ -12196,8 +12238,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12196
12238
|
],
|
|
12197
12239
|
columns: ["id", "artistName", "title", "releaseDate"],
|
|
12198
12240
|
run: async (c3, a2) => {
|
|
12199
|
-
const albums =
|
|
12200
|
-
return albums.map(
|
|
12241
|
+
const albums = unwrapData(await c3.getCalendar(a2.start, a2.end, a2.unmonitored));
|
|
12242
|
+
return albums.map(withArtistName);
|
|
12201
12243
|
}
|
|
12202
12244
|
}
|
|
12203
12245
|
]
|
|
@@ -12222,7 +12264,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
12222
12264
|
name: "add",
|
|
12223
12265
|
description: "Add a notification from JSON file or stdin",
|
|
12224
12266
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
12225
|
-
run: async (c3, a2) => c3.addNotification(
|
|
12267
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput(a2.file))
|
|
12226
12268
|
},
|
|
12227
12269
|
{
|
|
12228
12270
|
name: "edit",
|
|
@@ -12232,8 +12274,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12232
12274
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
12233
12275
|
],
|
|
12234
12276
|
run: async (c3, a2) => {
|
|
12235
|
-
const existing =
|
|
12236
|
-
return c3.updateNotification(a2.id, { ...existing, ...
|
|
12277
|
+
const existing = unwrapData(await c3.getNotification(a2.id));
|
|
12278
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
12237
12279
|
}
|
|
12238
12280
|
},
|
|
12239
12281
|
{
|
|
@@ -12270,7 +12312,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
12270
12312
|
name: "add",
|
|
12271
12313
|
description: "Add a download client from JSON file or stdin",
|
|
12272
12314
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
12273
|
-
run: async (c3, a2) => c3.addDownloadClient(
|
|
12315
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput(a2.file))
|
|
12274
12316
|
},
|
|
12275
12317
|
{
|
|
12276
12318
|
name: "edit",
|
|
@@ -12280,8 +12322,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12280
12322
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
12281
12323
|
],
|
|
12282
12324
|
run: async (c3, a2) => {
|
|
12283
|
-
const existing =
|
|
12284
|
-
return c3.updateDownloadClient(a2.id, { ...existing, ...
|
|
12325
|
+
const existing = unwrapData(await c3.getDownloadClient(a2.id));
|
|
12326
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
12285
12327
|
}
|
|
12286
12328
|
},
|
|
12287
12329
|
{
|
|
@@ -12307,8 +12349,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12307
12349
|
description: "List blocked releases",
|
|
12308
12350
|
columns: ["id", "artistName", "sourceTitle", "date"],
|
|
12309
12351
|
run: async (c3) => {
|
|
12310
|
-
const items =
|
|
12311
|
-
return items.map(
|
|
12352
|
+
const items = unwrapData(await c3.getBlocklist());
|
|
12353
|
+
return items.map(withArtistName);
|
|
12312
12354
|
}
|
|
12313
12355
|
},
|
|
12314
12356
|
{
|
|
@@ -12329,8 +12371,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12329
12371
|
description: "List albums with missing tracks",
|
|
12330
12372
|
columns: ["id", "artistName", "title", "releaseDate"],
|
|
12331
12373
|
run: async (c3) => {
|
|
12332
|
-
const albums =
|
|
12333
|
-
return albums.map(
|
|
12374
|
+
const albums = unwrapData(await c3.getWantedMissing());
|
|
12375
|
+
return albums.map(withArtistName);
|
|
12334
12376
|
}
|
|
12335
12377
|
},
|
|
12336
12378
|
{
|
|
@@ -12338,8 +12380,8 @@ var init_lidarr3 = __esm(() => {
|
|
|
12338
12380
|
description: "List albums below quality cutoff",
|
|
12339
12381
|
columns: ["id", "artistName", "title", "releaseDate"],
|
|
12340
12382
|
run: async (c3) => {
|
|
12341
|
-
const albums =
|
|
12342
|
-
return albums.map(
|
|
12383
|
+
const albums = unwrapData(await c3.getWantedCutoff());
|
|
12384
|
+
return albums.map(withArtistName);
|
|
12343
12385
|
}
|
|
12344
12386
|
}
|
|
12345
12387
|
]
|
|
@@ -14871,38 +14913,12 @@ var exports_readarr3 = {};
|
|
|
14871
14913
|
__export(exports_readarr3, {
|
|
14872
14914
|
readarr: () => readarr
|
|
14873
14915
|
});
|
|
14874
|
-
|
|
14875
|
-
function unwrapData4(result) {
|
|
14876
|
-
return result?.data ?? result;
|
|
14877
|
-
}
|
|
14878
|
-
function formatBookListItem(book) {
|
|
14879
|
-
return {
|
|
14880
|
-
...book,
|
|
14881
|
-
authorName: book?.authorName ?? book?.authorTitle ?? book?.author?.authorName ?? "—"
|
|
14882
|
-
};
|
|
14883
|
-
}
|
|
14884
|
-
function formatQueueListItem2(item) {
|
|
14885
|
-
return {
|
|
14886
|
-
...item,
|
|
14887
|
-
authorName: item?.authorName ?? item?.authorTitle ?? item?.author?.authorName ?? "—"
|
|
14888
|
-
};
|
|
14889
|
-
}
|
|
14890
|
-
function formatHistoryListItem2(item) {
|
|
14916
|
+
function withAuthorName(item) {
|
|
14891
14917
|
return {
|
|
14892
14918
|
...item,
|
|
14893
14919
|
authorName: item?.authorName ?? item?.authorTitle ?? item?.author?.authorName ?? "—"
|
|
14894
14920
|
};
|
|
14895
14921
|
}
|
|
14896
|
-
function formatBlocklistItem2(item) {
|
|
14897
|
-
return {
|
|
14898
|
-
...item,
|
|
14899
|
-
authorName: item?.authorName ?? item?.authorTitle ?? item?.author?.authorName ?? "—"
|
|
14900
|
-
};
|
|
14901
|
-
}
|
|
14902
|
-
function readJsonInput4(filePath) {
|
|
14903
|
-
const raw = filePath === "-" ? readFileSync5(0, "utf-8") : readFileSync5(filePath, "utf-8");
|
|
14904
|
-
return JSON.parse(raw);
|
|
14905
|
-
}
|
|
14906
14922
|
var resources4, readarr;
|
|
14907
14923
|
var init_readarr3 = __esm(() => {
|
|
14908
14924
|
init_readarr2();
|
|
@@ -14938,7 +14954,7 @@ var init_readarr3 = __esm(() => {
|
|
|
14938
14954
|
description: "Search and add an author",
|
|
14939
14955
|
args: [{ name: "term", description: "Search term", required: true }],
|
|
14940
14956
|
run: async (c3, a2) => {
|
|
14941
|
-
const results =
|
|
14957
|
+
const results = unwrapData(await c3.searchAuthors(a2.term));
|
|
14942
14958
|
if (!Array.isArray(results) || results.length === 0) {
|
|
14943
14959
|
throw new Error("No authors found.");
|
|
14944
14960
|
}
|
|
@@ -14950,12 +14966,12 @@ var init_readarr3 = __esm(() => {
|
|
|
14950
14966
|
if (!author) {
|
|
14951
14967
|
throw new Error("Selected author was not found in the search results.");
|
|
14952
14968
|
}
|
|
14953
|
-
const profiles =
|
|
14969
|
+
const profiles = unwrapData(await c3.getQualityProfiles());
|
|
14954
14970
|
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
14955
14971
|
throw new Error("No quality profiles found. Configure one in Readarr first.");
|
|
14956
14972
|
}
|
|
14957
14973
|
const profileId = await promptSelect("Select quality profile:", profiles.map((profile) => ({ label: profile.name, value: String(profile.id) })));
|
|
14958
|
-
const folders =
|
|
14974
|
+
const folders = unwrapData(await c3.getRootFolders());
|
|
14959
14975
|
if (!Array.isArray(folders) || folders.length === 0) {
|
|
14960
14976
|
throw new Error("No root folders found. Configure one in Readarr first.");
|
|
14961
14977
|
}
|
|
@@ -14982,7 +14998,7 @@ var init_readarr3 = __esm(() => {
|
|
|
14982
14998
|
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
14983
14999
|
],
|
|
14984
15000
|
run: async (c3, a2) => {
|
|
14985
|
-
const author =
|
|
15001
|
+
const author = unwrapData(await c3.getAuthor(a2.id));
|
|
14986
15002
|
const updates = { ...author };
|
|
14987
15003
|
if (a2.monitored !== undefined)
|
|
14988
15004
|
updates.monitored = a2.monitored === "true";
|
|
@@ -15027,8 +15043,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15027
15043
|
description: "List all books",
|
|
15028
15044
|
columns: ["id", "authorName", "title", "monitored"],
|
|
15029
15045
|
run: async (c3) => {
|
|
15030
|
-
const books =
|
|
15031
|
-
return books.map(
|
|
15046
|
+
const books = unwrapData(await c3.getBooks());
|
|
15047
|
+
return books.map(withAuthorName);
|
|
15032
15048
|
}
|
|
15033
15049
|
},
|
|
15034
15050
|
{
|
|
@@ -15036,8 +15052,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15036
15052
|
description: "Get a book by ID",
|
|
15037
15053
|
args: [{ name: "id", description: "Book ID", required: true, type: "number" }],
|
|
15038
15054
|
run: async (c3, a2) => {
|
|
15039
|
-
const book =
|
|
15040
|
-
return
|
|
15055
|
+
const book = unwrapData(await c3.getBook(a2.id));
|
|
15056
|
+
return withAuthorName(book);
|
|
15041
15057
|
}
|
|
15042
15058
|
},
|
|
15043
15059
|
{
|
|
@@ -15047,15 +15063,15 @@ var init_readarr3 = __esm(() => {
|
|
|
15047
15063
|
columns: ["foreignBookId", "authorName", "title", "monitored"],
|
|
15048
15064
|
idField: "foreignBookId",
|
|
15049
15065
|
run: async (c3, a2) => {
|
|
15050
|
-
const books =
|
|
15051
|
-
return books.map(
|
|
15066
|
+
const books = unwrapData(await c3.searchBooks(a2.term));
|
|
15067
|
+
return books.map(withAuthorName);
|
|
15052
15068
|
}
|
|
15053
15069
|
},
|
|
15054
15070
|
{
|
|
15055
15071
|
name: "add",
|
|
15056
15072
|
description: "Add a book from JSON file or stdin",
|
|
15057
15073
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15058
|
-
run: async (c3, a2) => c3.addBook(
|
|
15074
|
+
run: async (c3, a2) => c3.addBook(readJsonInput(a2.file))
|
|
15059
15075
|
},
|
|
15060
15076
|
{
|
|
15061
15077
|
name: "edit",
|
|
@@ -15065,8 +15081,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15065
15081
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15066
15082
|
],
|
|
15067
15083
|
run: async (c3, a2) => {
|
|
15068
|
-
const existing =
|
|
15069
|
-
return c3.updateBook(a2.id, { ...existing, ...
|
|
15084
|
+
const existing = unwrapData(await c3.getBook(a2.id));
|
|
15085
|
+
return c3.updateBook(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
15070
15086
|
}
|
|
15071
15087
|
},
|
|
15072
15088
|
{
|
|
@@ -15141,7 +15157,7 @@ var init_readarr3 = __esm(() => {
|
|
|
15141
15157
|
const tagResult = await c3.getTag(a2.id);
|
|
15142
15158
|
if (tagResult?.error)
|
|
15143
15159
|
return tagResult;
|
|
15144
|
-
const tag =
|
|
15160
|
+
const tag = unwrapData(tagResult);
|
|
15145
15161
|
const deleteResult = await c3.deleteTag(a2.id);
|
|
15146
15162
|
if (deleteResult?.error)
|
|
15147
15163
|
return deleteResult;
|
|
@@ -15165,8 +15181,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15165
15181
|
description: "List queue items",
|
|
15166
15182
|
columns: ["id", "authorName", "title", "status", "sizeleft", "timeleft"],
|
|
15167
15183
|
run: async (c3) => {
|
|
15168
|
-
const items =
|
|
15169
|
-
return items.map(
|
|
15184
|
+
const items = unwrapData(await c3.getQueue());
|
|
15185
|
+
return items.map(withAuthorName);
|
|
15170
15186
|
}
|
|
15171
15187
|
},
|
|
15172
15188
|
{
|
|
@@ -15210,9 +15226,9 @@ var init_readarr3 = __esm(() => {
|
|
|
15210
15226
|
],
|
|
15211
15227
|
columns: ["id", "authorName", "sourceTitle", "eventType", "date"],
|
|
15212
15228
|
run: async (c3, a2) => {
|
|
15213
|
-
const items = a2.since ?
|
|
15229
|
+
const items = a2.since ? unwrapData(await c3.getHistorySince(a2.since)) : unwrapData(await c3.getHistory());
|
|
15214
15230
|
const filtered = a2.until ? items.filter((item) => new Date(item.date) <= new Date(a2.until)) : items;
|
|
15215
|
-
return filtered.map(
|
|
15231
|
+
return filtered.map(withAuthorName);
|
|
15216
15232
|
}
|
|
15217
15233
|
}
|
|
15218
15234
|
]
|
|
@@ -15231,8 +15247,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15231
15247
|
],
|
|
15232
15248
|
columns: ["id", "authorName", "title", "releaseDate"],
|
|
15233
15249
|
run: async (c3, a2) => {
|
|
15234
|
-
const books =
|
|
15235
|
-
return books.map(
|
|
15250
|
+
const books = unwrapData(await c3.getCalendar(a2.start, a2.end, a2.unmonitored));
|
|
15251
|
+
return books.map(withAuthorName);
|
|
15236
15252
|
}
|
|
15237
15253
|
}
|
|
15238
15254
|
]
|
|
@@ -15257,7 +15273,7 @@ var init_readarr3 = __esm(() => {
|
|
|
15257
15273
|
name: "add",
|
|
15258
15274
|
description: "Add a notification from JSON file or stdin",
|
|
15259
15275
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15260
|
-
run: async (c3, a2) => c3.addNotification(
|
|
15276
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput(a2.file))
|
|
15261
15277
|
},
|
|
15262
15278
|
{
|
|
15263
15279
|
name: "edit",
|
|
@@ -15267,8 +15283,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15267
15283
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15268
15284
|
],
|
|
15269
15285
|
run: async (c3, a2) => {
|
|
15270
|
-
const existing =
|
|
15271
|
-
return c3.updateNotification(a2.id, { ...existing, ...
|
|
15286
|
+
const existing = unwrapData(await c3.getNotification(a2.id));
|
|
15287
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
15272
15288
|
}
|
|
15273
15289
|
},
|
|
15274
15290
|
{
|
|
@@ -15305,7 +15321,7 @@ var init_readarr3 = __esm(() => {
|
|
|
15305
15321
|
name: "add",
|
|
15306
15322
|
description: "Add a download client from JSON file or stdin",
|
|
15307
15323
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15308
|
-
run: async (c3, a2) => c3.addDownloadClient(
|
|
15324
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput(a2.file))
|
|
15309
15325
|
},
|
|
15310
15326
|
{
|
|
15311
15327
|
name: "edit",
|
|
@@ -15315,8 +15331,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15315
15331
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15316
15332
|
],
|
|
15317
15333
|
run: async (c3, a2) => {
|
|
15318
|
-
const existing =
|
|
15319
|
-
return c3.updateDownloadClient(a2.id, { ...existing, ...
|
|
15334
|
+
const existing = unwrapData(await c3.getDownloadClient(a2.id));
|
|
15335
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
15320
15336
|
}
|
|
15321
15337
|
},
|
|
15322
15338
|
{
|
|
@@ -15342,8 +15358,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15342
15358
|
description: "List blocked releases",
|
|
15343
15359
|
columns: ["id", "authorName", "sourceTitle", "date"],
|
|
15344
15360
|
run: async (c3) => {
|
|
15345
|
-
const items =
|
|
15346
|
-
return items.map(
|
|
15361
|
+
const items = unwrapData(await c3.getBlocklist());
|
|
15362
|
+
return items.map(withAuthorName);
|
|
15347
15363
|
}
|
|
15348
15364
|
},
|
|
15349
15365
|
{
|
|
@@ -15364,8 +15380,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15364
15380
|
description: "List books with missing files",
|
|
15365
15381
|
columns: ["id", "authorName", "title", "releaseDate"],
|
|
15366
15382
|
run: async (c3) => {
|
|
15367
|
-
const books =
|
|
15368
|
-
return books.map(
|
|
15383
|
+
const books = unwrapData(await c3.getWantedMissing());
|
|
15384
|
+
return books.map(withAuthorName);
|
|
15369
15385
|
}
|
|
15370
15386
|
},
|
|
15371
15387
|
{
|
|
@@ -15373,8 +15389,8 @@ var init_readarr3 = __esm(() => {
|
|
|
15373
15389
|
description: "List books below quality cutoff",
|
|
15374
15390
|
columns: ["id", "authorName", "title", "releaseDate"],
|
|
15375
15391
|
run: async (c3) => {
|
|
15376
|
-
const books =
|
|
15377
|
-
return books.map(
|
|
15392
|
+
const books = unwrapData(await c3.getWantedCutoff());
|
|
15393
|
+
return books.map(withAuthorName);
|
|
15378
15394
|
}
|
|
15379
15395
|
}
|
|
15380
15396
|
]
|
|
@@ -17070,14 +17086,6 @@ var exports_prowlarr3 = {};
|
|
|
17070
17086
|
__export(exports_prowlarr3, {
|
|
17071
17087
|
prowlarr: () => prowlarr
|
|
17072
17088
|
});
|
|
17073
|
-
import { readFileSync as readFileSync6 } from "node:fs";
|
|
17074
|
-
function unwrapData5(result) {
|
|
17075
|
-
return result?.data ?? result;
|
|
17076
|
-
}
|
|
17077
|
-
function readJsonInput5(filePath) {
|
|
17078
|
-
const raw = filePath === "-" ? readFileSync6(0, "utf-8") : readFileSync6(filePath, "utf-8");
|
|
17079
|
-
return JSON.parse(raw);
|
|
17080
|
-
}
|
|
17081
17089
|
async function runIndexerTest(client6, indexer) {
|
|
17082
17090
|
const result = await client6.testIndexer(indexer);
|
|
17083
17091
|
if (result?.error) {
|
|
@@ -17091,7 +17099,7 @@ async function runIndexerTest(client6, indexer) {
|
|
|
17091
17099
|
message: error?.title ?? error?.message ?? `API error (${status ?? "unknown"})`
|
|
17092
17100
|
};
|
|
17093
17101
|
}
|
|
17094
|
-
const data =
|
|
17102
|
+
const data = unwrapData(result);
|
|
17095
17103
|
return {
|
|
17096
17104
|
id: indexer?.id,
|
|
17097
17105
|
name: indexer?.name ?? "Unknown indexer",
|
|
@@ -17144,7 +17152,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17144
17152
|
description: "Add an indexer from JSON file or stdin",
|
|
17145
17153
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
17146
17154
|
run: async (c3, a2) => {
|
|
17147
|
-
const body =
|
|
17155
|
+
const body = readJsonInput(a2.file);
|
|
17148
17156
|
return c3.addIndexer(body);
|
|
17149
17157
|
}
|
|
17150
17158
|
},
|
|
@@ -17156,8 +17164,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17156
17164
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
17157
17165
|
],
|
|
17158
17166
|
run: async (c3, a2) => {
|
|
17159
|
-
const existing =
|
|
17160
|
-
const updates =
|
|
17167
|
+
const existing = unwrapData(await c3.getIndexer(a2.id));
|
|
17168
|
+
const updates = readJsonInput(a2.file);
|
|
17161
17169
|
return c3.updateIndexer(a2.id, { ...existing, ...updates });
|
|
17162
17170
|
}
|
|
17163
17171
|
},
|
|
@@ -17174,7 +17182,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17174
17182
|
args: [{ name: "id", description: "Indexer ID", type: "number" }],
|
|
17175
17183
|
columns: ["id", "name", "status", "message"],
|
|
17176
17184
|
run: async (c3, a2) => {
|
|
17177
|
-
const indexers = a2.id ? [
|
|
17185
|
+
const indexers = a2.id ? [unwrapData(await c3.getIndexer(a2.id))] : unwrapData(await c3.getIndexers());
|
|
17178
17186
|
const results = [];
|
|
17179
17187
|
for (const indexer of indexers) {
|
|
17180
17188
|
results.push(await runIndexerTest(c3, indexer));
|
|
@@ -17221,7 +17229,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17221
17229
|
description: "Add an application from JSON file or stdin",
|
|
17222
17230
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
17223
17231
|
run: async (c3, a2) => {
|
|
17224
|
-
const body =
|
|
17232
|
+
const body = readJsonInput(a2.file);
|
|
17225
17233
|
return c3.addApplication(body);
|
|
17226
17234
|
}
|
|
17227
17235
|
},
|
|
@@ -17233,8 +17241,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17233
17241
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
17234
17242
|
],
|
|
17235
17243
|
run: async (c3, a2) => {
|
|
17236
|
-
const existing =
|
|
17237
|
-
const updates =
|
|
17244
|
+
const existing = unwrapData(await c3.getApplication(a2.id));
|
|
17245
|
+
const updates = readJsonInput(a2.file);
|
|
17238
17246
|
return c3.updateApplication(a2.id, { ...existing, ...updates });
|
|
17239
17247
|
}
|
|
17240
17248
|
},
|
|
@@ -17302,7 +17310,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17302
17310
|
"averageResponseTime"
|
|
17303
17311
|
],
|
|
17304
17312
|
run: async (c3) => {
|
|
17305
|
-
const result =
|
|
17313
|
+
const result = unwrapData(await c3.getIndexerStats());
|
|
17306
17314
|
return result?.indexers ?? result;
|
|
17307
17315
|
}
|
|
17308
17316
|
}
|
|
@@ -17328,7 +17336,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17328
17336
|
name: "add",
|
|
17329
17337
|
description: "Add a notification from JSON file or stdin",
|
|
17330
17338
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
17331
|
-
run: async (c3, a2) => c3.addNotification(
|
|
17339
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput(a2.file))
|
|
17332
17340
|
},
|
|
17333
17341
|
{
|
|
17334
17342
|
name: "edit",
|
|
@@ -17338,8 +17346,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17338
17346
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
17339
17347
|
],
|
|
17340
17348
|
run: async (c3, a2) => {
|
|
17341
|
-
const existing =
|
|
17342
|
-
return c3.updateNotification(a2.id, { ...existing, ...
|
|
17349
|
+
const existing = unwrapData(await c3.getNotification(a2.id));
|
|
17350
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
17343
17351
|
}
|
|
17344
17352
|
},
|
|
17345
17353
|
{
|
|
@@ -17376,7 +17384,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17376
17384
|
name: "add",
|
|
17377
17385
|
description: "Add a download client from JSON file or stdin",
|
|
17378
17386
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
17379
|
-
run: async (c3, a2) => c3.addDownloadClient(
|
|
17387
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput(a2.file))
|
|
17380
17388
|
},
|
|
17381
17389
|
{
|
|
17382
17390
|
name: "edit",
|
|
@@ -17386,8 +17394,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
17386
17394
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
17387
17395
|
],
|
|
17388
17396
|
run: async (c3, a2) => {
|
|
17389
|
-
const existing =
|
|
17390
|
-
return c3.updateDownloadClient(a2.id, { ...existing, ...
|
|
17397
|
+
const existing = unwrapData(await c3.getDownloadClient(a2.id));
|
|
17398
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
17391
17399
|
}
|
|
17392
17400
|
},
|
|
17393
17401
|
{
|
|
@@ -21316,9 +21324,10 @@ var init_doctor = __esm(() => {
|
|
|
21316
21324
|
consola.info(`Checking connections...
|
|
21317
21325
|
`);
|
|
21318
21326
|
}
|
|
21327
|
+
let hasMultiInstance = false;
|
|
21319
21328
|
for (const service of SERVICES) {
|
|
21320
|
-
const
|
|
21321
|
-
if (
|
|
21329
|
+
const instances = getServiceInstances(service);
|
|
21330
|
+
if (instances.length === 0) {
|
|
21322
21331
|
results.push({
|
|
21323
21332
|
service,
|
|
21324
21333
|
configured: false,
|
|
@@ -21326,56 +21335,62 @@ var init_doctor = __esm(() => {
|
|
|
21326
21335
|
});
|
|
21327
21336
|
continue;
|
|
21328
21337
|
}
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21338
|
+
if (instances.length > 1)
|
|
21339
|
+
hasMultiInstance = true;
|
|
21340
|
+
for (const inst of instances) {
|
|
21341
|
+
const svcConfig = getServiceConfig(service, inst.name);
|
|
21342
|
+
if (!svcConfig) {
|
|
21343
|
+
results.push({
|
|
21344
|
+
service,
|
|
21345
|
+
...inst.name ? { instance: inst.name } : {},
|
|
21346
|
+
configured: false,
|
|
21347
|
+
status: "not configured"
|
|
21348
|
+
});
|
|
21349
|
+
continue;
|
|
21350
|
+
}
|
|
21351
|
+
hasAny = true;
|
|
21352
|
+
try {
|
|
21353
|
+
const client9 = clientFactories[service](svcConfig);
|
|
21354
|
+
const status = await client9.getSystemStatus();
|
|
21355
|
+
if (status?.error !== undefined) {
|
|
21356
|
+
const err = status.error;
|
|
21357
|
+
const code = err?.cause?.code ?? err?.code;
|
|
21358
|
+
const cause = code ? { code } : undefined;
|
|
21359
|
+
const message = err?.cause?.message ?? err?.message ?? err?.code ?? "Unknown API error";
|
|
21360
|
+
throw Object.assign(new Error(message), cause ? { cause } : {});
|
|
21361
|
+
}
|
|
21362
|
+
const version = extractVersion(service, status) ?? "?";
|
|
21363
|
+
if (version === "?") {
|
|
21364
|
+
throw new Error("Unexpected response payload");
|
|
21365
|
+
}
|
|
21333
21366
|
results.push({
|
|
21334
21367
|
service,
|
|
21368
|
+
...inst.name ? { instance: inst.name } : {},
|
|
21369
|
+
configured: true,
|
|
21370
|
+
status: "ok",
|
|
21371
|
+
version: String(version),
|
|
21372
|
+
baseUrl: svcConfig.baseUrl
|
|
21373
|
+
});
|
|
21374
|
+
} catch (error) {
|
|
21375
|
+
results.push({
|
|
21376
|
+
service,
|
|
21377
|
+
...inst.name ? { instance: inst.name } : {},
|
|
21335
21378
|
configured: true,
|
|
21336
21379
|
status: "fail",
|
|
21337
21380
|
baseUrl: svcConfig.baseUrl,
|
|
21338
|
-
error:
|
|
21381
|
+
error: classifyError(error)
|
|
21339
21382
|
});
|
|
21340
|
-
continue;
|
|
21341
|
-
}
|
|
21342
|
-
const client9 = factory(svcConfig);
|
|
21343
|
-
const status = await client9.getSystemStatus();
|
|
21344
|
-
if (status?.error !== undefined) {
|
|
21345
|
-
const err = status.error;
|
|
21346
|
-
const code = err?.cause?.code ?? err?.code;
|
|
21347
|
-
const cause = code ? { code } : undefined;
|
|
21348
|
-
const message = err?.cause?.message ?? err?.message ?? err?.code ?? "Unknown API error";
|
|
21349
|
-
throw Object.assign(new Error(message), cause ? { cause } : {});
|
|
21350
21383
|
}
|
|
21351
|
-
const version = extractVersion(service, status) ?? "?";
|
|
21352
|
-
if (version === "?") {
|
|
21353
|
-
throw new Error("Unexpected response payload");
|
|
21354
|
-
}
|
|
21355
|
-
results.push({
|
|
21356
|
-
service,
|
|
21357
|
-
configured: true,
|
|
21358
|
-
status: "ok",
|
|
21359
|
-
version: String(version),
|
|
21360
|
-
baseUrl: svcConfig.baseUrl
|
|
21361
|
-
});
|
|
21362
|
-
} catch (error) {
|
|
21363
|
-
results.push({
|
|
21364
|
-
service,
|
|
21365
|
-
configured: true,
|
|
21366
|
-
status: "fail",
|
|
21367
|
-
baseUrl: svcConfig.baseUrl,
|
|
21368
|
-
error: classifyError(error)
|
|
21369
|
-
});
|
|
21370
21384
|
}
|
|
21371
21385
|
}
|
|
21372
21386
|
const hadFailure = !hasAny || results.some((r3) => r3.status === "fail");
|
|
21373
21387
|
if (!hasAny && format === "table") {
|
|
21374
21388
|
consola.warn("\nNo services configured. Run `tsarr config init` to set up.");
|
|
21375
21389
|
}
|
|
21390
|
+
const columns = hasMultiInstance ? ["service", "instance", "status", "configured", "version", "baseUrl", "error"] : ["service", "status", "configured", "version", "baseUrl", "error"];
|
|
21376
21391
|
formatOutput(results, {
|
|
21377
21392
|
format,
|
|
21378
|
-
columns
|
|
21393
|
+
columns,
|
|
21379
21394
|
idField: "service",
|
|
21380
21395
|
select: args.select
|
|
21381
21396
|
});
|
|
@@ -21391,6 +21406,61 @@ var exports_config = {};
|
|
|
21391
21406
|
__export(exports_config, {
|
|
21392
21407
|
config: () => config
|
|
21393
21408
|
});
|
|
21409
|
+
async function configureInstance(service, instanceName) {
|
|
21410
|
+
const baseUrl = await promptIfMissing(undefined, `${service}${instanceName ? ` (${instanceName})` : ""} base URL (e.g. http://localhost:${DEFAULT_PORTS[service]})`);
|
|
21411
|
+
if (service === "qbittorrent") {
|
|
21412
|
+
const username = await promptIfMissing(undefined, `${service} username`);
|
|
21413
|
+
const password = await promptIfMissing(undefined, `${service} password`);
|
|
21414
|
+
const cfg2 = { baseUrl, username, password };
|
|
21415
|
+
if (instanceName)
|
|
21416
|
+
cfg2.name = instanceName;
|
|
21417
|
+
return cfg2;
|
|
21418
|
+
}
|
|
21419
|
+
const apiKey = await promptIfMissing(undefined, `${service} API key`);
|
|
21420
|
+
const cfg = { baseUrl, apiKey };
|
|
21421
|
+
if (instanceName)
|
|
21422
|
+
cfg.name = instanceName;
|
|
21423
|
+
return cfg;
|
|
21424
|
+
}
|
|
21425
|
+
async function testConnection(service, serviceConfig) {
|
|
21426
|
+
try {
|
|
21427
|
+
if (service === "qbittorrent") {
|
|
21428
|
+
const { QBittorrentClient: QBittorrentClient2 } = await Promise.resolve().then(() => (init_qbittorrent2(), exports_qbittorrent));
|
|
21429
|
+
const client9 = new QBittorrentClient2({
|
|
21430
|
+
baseUrl: serviceConfig.baseUrl,
|
|
21431
|
+
username: serviceConfig.username,
|
|
21432
|
+
password: serviceConfig.password
|
|
21433
|
+
});
|
|
21434
|
+
const status = await client9.getSystemStatus();
|
|
21435
|
+
consola.success(`Connected to ${service}${serviceConfig.name ? ` (${serviceConfig.name})` : ""} v${status.version}`);
|
|
21436
|
+
} else {
|
|
21437
|
+
const { RadarrClient: RadarrClient2 } = await Promise.resolve().then(() => (init_radarr2(), exports_radarr));
|
|
21438
|
+
const { SonarrClient: SonarrClient2 } = await Promise.resolve().then(() => (init_sonarr2(), exports_sonarr));
|
|
21439
|
+
const { LidarrClient: LidarrClient2 } = await Promise.resolve().then(() => (init_lidarr2(), exports_lidarr));
|
|
21440
|
+
const { ReadarrClient: ReadarrClient2 } = await Promise.resolve().then(() => (init_readarr2(), exports_readarr));
|
|
21441
|
+
const { ProwlarrClient: ProwlarrClient2 } = await Promise.resolve().then(() => (init_prowlarr2(), exports_prowlarr));
|
|
21442
|
+
const { BazarrClient: BazarrClient2 } = await Promise.resolve().then(() => (init_bazarr2(), exports_bazarr));
|
|
21443
|
+
const { SeerrClient: SeerrClient2 } = await Promise.resolve().then(() => (init_seerr2(), exports_seerr));
|
|
21444
|
+
const factories = {
|
|
21445
|
+
radarr: (c3) => new RadarrClient2(c3),
|
|
21446
|
+
sonarr: (c3) => new SonarrClient2(c3),
|
|
21447
|
+
lidarr: (c3) => new LidarrClient2(c3),
|
|
21448
|
+
readarr: (c3) => new ReadarrClient2(c3),
|
|
21449
|
+
prowlarr: (c3) => new ProwlarrClient2(c3),
|
|
21450
|
+
bazarr: (c3) => new BazarrClient2(c3),
|
|
21451
|
+
seerr: (c3) => new SeerrClient2(c3)
|
|
21452
|
+
};
|
|
21453
|
+
const client9 = factories[service]?.(serviceConfig);
|
|
21454
|
+
if (client9) {
|
|
21455
|
+
const status = await client9.getSystemStatus();
|
|
21456
|
+
const version = status?.data?.version ?? status?.version ?? "?";
|
|
21457
|
+
consola.success(`Connected to ${service}${serviceConfig.name ? ` (${serviceConfig.name})` : ""} v${version}`);
|
|
21458
|
+
}
|
|
21459
|
+
}
|
|
21460
|
+
} catch {
|
|
21461
|
+
consola.warn(`Could not connect to ${service}${serviceConfig.name ? ` (${serviceConfig.name})` : ""} — config saved anyway.`);
|
|
21462
|
+
}
|
|
21463
|
+
}
|
|
21394
21464
|
var DEFAULT_PORTS, configInit, configSet, configGet, configShow, config;
|
|
21395
21465
|
var init_config2 = __esm(() => {
|
|
21396
21466
|
init_dist();
|
|
@@ -21430,49 +21500,25 @@ var init_config2 = __esm(() => {
|
|
|
21430
21500
|
const config = { services: {} };
|
|
21431
21501
|
for (const service of selected) {
|
|
21432
21502
|
console.log();
|
|
21433
|
-
const
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
|
|
21439
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
consola.warn(`Could not connect to ${service} — config saved anyway.`);
|
|
21445
|
-
}
|
|
21446
|
-
} else {
|
|
21447
|
-
const apiKey = await promptIfMissing(undefined, `${service} API key`);
|
|
21448
|
-
config.services[service] = { baseUrl, apiKey };
|
|
21449
|
-
try {
|
|
21450
|
-
const { RadarrClient: RadarrClient2 } = await Promise.resolve().then(() => (init_radarr2(), exports_radarr));
|
|
21451
|
-
const { SonarrClient: SonarrClient2 } = await Promise.resolve().then(() => (init_sonarr2(), exports_sonarr));
|
|
21452
|
-
const { LidarrClient: LidarrClient2 } = await Promise.resolve().then(() => (init_lidarr2(), exports_lidarr));
|
|
21453
|
-
const { ReadarrClient: ReadarrClient2 } = await Promise.resolve().then(() => (init_readarr2(), exports_readarr));
|
|
21454
|
-
const { ProwlarrClient: ProwlarrClient2 } = await Promise.resolve().then(() => (init_prowlarr2(), exports_prowlarr));
|
|
21455
|
-
const { BazarrClient: BazarrClient2 } = await Promise.resolve().then(() => (init_bazarr2(), exports_bazarr));
|
|
21456
|
-
const { SeerrClient: SeerrClient2 } = await Promise.resolve().then(() => (init_seerr2(), exports_seerr));
|
|
21457
|
-
const factories = {
|
|
21458
|
-
radarr: (c3) => new RadarrClient2(c3),
|
|
21459
|
-
sonarr: (c3) => new SonarrClient2(c3),
|
|
21460
|
-
lidarr: (c3) => new LidarrClient2(c3),
|
|
21461
|
-
readarr: (c3) => new ReadarrClient2(c3),
|
|
21462
|
-
prowlarr: (c3) => new ProwlarrClient2(c3),
|
|
21463
|
-
bazarr: (c3) => new BazarrClient2(c3),
|
|
21464
|
-
seerr: (c3) => new SeerrClient2(c3)
|
|
21465
|
-
};
|
|
21466
|
-
const client9 = factories[service]?.(config.services[service]);
|
|
21467
|
-
if (client9) {
|
|
21468
|
-
const status = await client9.getSystemStatus();
|
|
21469
|
-
const version = status?.data?.version ?? status?.version ?? "?";
|
|
21470
|
-
consola.success(`Connected to ${service} v${version}`);
|
|
21471
|
-
}
|
|
21472
|
-
} catch {
|
|
21473
|
-
consola.warn(`Could not connect to ${service} — config saved anyway.`);
|
|
21503
|
+
const instances = [];
|
|
21504
|
+
const first = await configureInstance(service);
|
|
21505
|
+
await testConnection(service, first);
|
|
21506
|
+
instances.push(first);
|
|
21507
|
+
while (true) {
|
|
21508
|
+
const addMore = await promptConfirm(`Add another ${service} instance?`);
|
|
21509
|
+
if (!addMore)
|
|
21510
|
+
break;
|
|
21511
|
+
if (instances.length === 1 && !instances[0].name) {
|
|
21512
|
+
const firstName = await promptIfMissing(undefined, `Name for the existing ${service} instance (e.g. "main", "1080p")`);
|
|
21513
|
+
instances[0].name = firstName;
|
|
21474
21514
|
}
|
|
21515
|
+
const newName = await promptIfMissing(undefined, `Name for the new ${service} instance (e.g. "4K")`);
|
|
21516
|
+
console.log();
|
|
21517
|
+
const newInstance = await configureInstance(service, newName);
|
|
21518
|
+
await testConnection(service, newInstance);
|
|
21519
|
+
instances.push(newInstance);
|
|
21475
21520
|
}
|
|
21521
|
+
config.services[service] = instances;
|
|
21476
21522
|
}
|
|
21477
21523
|
const location = await promptSelect("Save config to:", [
|
|
21478
21524
|
{ label: `Global (${GLOBAL_CONFIG_PATH})`, value: "global" },
|
|
@@ -21535,11 +21581,15 @@ var init_config2 = __esm(() => {
|
|
|
21535
21581
|
const config = loadConfig();
|
|
21536
21582
|
const redacted = JSON.parse(JSON.stringify(config));
|
|
21537
21583
|
if (redacted.services) {
|
|
21538
|
-
for (const
|
|
21539
|
-
if (
|
|
21540
|
-
svc
|
|
21541
|
-
|
|
21542
|
-
|
|
21584
|
+
for (const instances of Object.values(redacted.services)) {
|
|
21585
|
+
if (Array.isArray(instances)) {
|
|
21586
|
+
for (const svc of instances) {
|
|
21587
|
+
if (svc?.apiKey)
|
|
21588
|
+
svc.apiKey = "*****";
|
|
21589
|
+
if (svc?.password)
|
|
21590
|
+
svc.password = "*****";
|
|
21591
|
+
}
|
|
21592
|
+
}
|
|
21543
21593
|
}
|
|
21544
21594
|
}
|
|
21545
21595
|
console.log(JSON.stringify(redacted, null, 2));
|
|
@@ -21654,7 +21704,8 @@ ${actionAssoc}
|
|
|
21654
21704
|
'--json[Output as JSON]' \\
|
|
21655
21705
|
'--table[Output as table]' \\
|
|
21656
21706
|
'--quiet[Output IDs only]' \\
|
|
21657
|
-
'--yes[Skip confirmation prompts]'
|
|
21707
|
+
'--yes[Skip confirmation prompts]' \\
|
|
21708
|
+
'--instance[Instance name for multi-instance services]:instance:'
|
|
21658
21709
|
;;
|
|
21659
21710
|
esac
|
|
21660
21711
|
}
|
|
@@ -21691,7 +21742,9 @@ ${actionCompletions}
|
|
|
21691
21742
|
complete -c tsarr -l json -d "Output as JSON"
|
|
21692
21743
|
complete -c tsarr -l table -d "Output as table"
|
|
21693
21744
|
complete -c tsarr -l quiet -s q -d "Output IDs only"
|
|
21694
|
-
complete -c tsarr -l yes -s y -d "Skip confirmation prompts"
|
|
21745
|
+
complete -c tsarr -l yes -s y -d "Skip confirmation prompts"
|
|
21746
|
+
complete -c tsarr -l instance -s i -d "Instance name (multi-instance services)"
|
|
21747
|
+
`;
|
|
21695
21748
|
}
|
|
21696
21749
|
var SERVICE_COMMANDS, completions;
|
|
21697
21750
|
var init_completions = __esm(() => {
|
|
@@ -21790,7 +21843,7 @@ init_dist();
|
|
|
21790
21843
|
// package.json
|
|
21791
21844
|
var package_default = {
|
|
21792
21845
|
name: "tsarr",
|
|
21793
|
-
version: "2.
|
|
21846
|
+
version: "2.8.0",
|
|
21794
21847
|
author: "Robbe Verhelst",
|
|
21795
21848
|
repository: {
|
|
21796
21849
|
type: "git",
|
|
@@ -21802,7 +21855,7 @@ var package_default = {
|
|
|
21802
21855
|
main: "dist/index.js",
|
|
21803
21856
|
module: "dist/index.js",
|
|
21804
21857
|
devDependencies: {
|
|
21805
|
-
"@biomejs/biome": "2.4.
|
|
21858
|
+
"@biomejs/biome": "2.4.12",
|
|
21806
21859
|
"@hey-api/openapi-ts": "^0.96.0",
|
|
21807
21860
|
"@semantic-release/changelog": "^6.0.3",
|
|
21808
21861
|
"@semantic-release/git": "^10.0.1",
|