tsarr 2.3.2 → 2.4.1
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/dist/cli/commands/lidarr.d.ts.map +1 -1
- package/dist/cli/commands/prowlarr.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 +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/index.js +1398 -124
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/clients/lidarr.d.ts +10 -0
- package/dist/clients/lidarr.d.ts.map +1 -1
- package/dist/clients/lidarr.js +12 -0
- package/dist/clients/prowlarr.d.ts +10 -0
- package/dist/clients/prowlarr.d.ts.map +1 -1
- package/dist/clients/prowlarr.js +12 -0
- package/dist/clients/radarr.d.ts +24 -1
- package/dist/clients/radarr.d.ts.map +1 -1
- package/dist/clients/radarr.js +39 -2
- package/dist/clients/readarr.d.ts +10 -0
- package/dist/clients/readarr.d.ts.map +1 -1
- package/dist/clients/readarr.js +12 -0
- package/dist/clients/sonarr.d.ts +6 -3
- package/dist/clients/sonarr.d.ts.map +1 -1
- package/dist/clients/sonarr.js +15 -5
- package/dist/index.js +13 -13
- package/dist/tsarr-2.4.1.tgz +0 -0
- package/package.json +1 -1
- package/dist/tsarr-2.3.2.tgz +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -1471,6 +1471,14 @@ var getApiV3SystemBackup = (options) => (options?.client ?? client).get({
|
|
|
1471
1471
|
}],
|
|
1472
1472
|
url: "/api/v3/customformat/schema",
|
|
1473
1473
|
...options
|
|
1474
|
+
}), getApiV3WantedCutoff = (options) => (options?.client ?? client).get({
|
|
1475
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
1476
|
+
in: "query",
|
|
1477
|
+
name: "apikey",
|
|
1478
|
+
type: "apiKey"
|
|
1479
|
+
}],
|
|
1480
|
+
url: "/api/v3/wanted/cutoff",
|
|
1481
|
+
...options
|
|
1474
1482
|
}), getApiV3Diskspace = (options) => (options?.client ?? client).get({
|
|
1475
1483
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
1476
1484
|
in: "query",
|
|
@@ -1867,6 +1875,14 @@ var getApiV3SystemBackup = (options) => (options?.client ?? client).get({
|
|
|
1867
1875
|
"Content-Type": "application/json",
|
|
1868
1876
|
...options.headers
|
|
1869
1877
|
}
|
|
1878
|
+
}), getApiV3WantedMissing = (options) => (options?.client ?? client).get({
|
|
1879
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
1880
|
+
in: "query",
|
|
1881
|
+
name: "apikey",
|
|
1882
|
+
type: "apiKey"
|
|
1883
|
+
}],
|
|
1884
|
+
url: "/api/v3/wanted/missing",
|
|
1885
|
+
...options
|
|
1870
1886
|
}), getApiV3Movie = (options) => (options?.client ?? client).get({
|
|
1871
1887
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
1872
1888
|
in: "query",
|
|
@@ -2370,8 +2386,11 @@ class RadarrClient {
|
|
|
2370
2386
|
async updateMovie(id, movie) {
|
|
2371
2387
|
return putApiV3MovieById({ path: { id: String(id) }, body: movie });
|
|
2372
2388
|
}
|
|
2373
|
-
async deleteMovie(id) {
|
|
2374
|
-
return deleteApiV3MovieById({
|
|
2389
|
+
async deleteMovie(id, options) {
|
|
2390
|
+
return deleteApiV3MovieById({
|
|
2391
|
+
path: { id },
|
|
2392
|
+
...options ? { query: options } : {}
|
|
2393
|
+
});
|
|
2375
2394
|
}
|
|
2376
2395
|
async searchMovies(term) {
|
|
2377
2396
|
return getApiV3MovieLookup({ query: { term } });
|
|
@@ -2700,6 +2719,22 @@ class RadarrClient {
|
|
|
2700
2719
|
async removeBlocklistItemsBulk(ids) {
|
|
2701
2720
|
return deleteApiV3BlocklistBulk({ body: { ids } });
|
|
2702
2721
|
}
|
|
2722
|
+
async getWantedMissing(page, pageSize) {
|
|
2723
|
+
const query = {};
|
|
2724
|
+
if (page !== undefined)
|
|
2725
|
+
query.page = page;
|
|
2726
|
+
if (pageSize !== undefined)
|
|
2727
|
+
query.pageSize = pageSize;
|
|
2728
|
+
return getApiV3WantedMissing(Object.keys(query).length > 0 ? { query } : {});
|
|
2729
|
+
}
|
|
2730
|
+
async getWantedCutoff(page, pageSize) {
|
|
2731
|
+
const query = {};
|
|
2732
|
+
if (page !== undefined)
|
|
2733
|
+
query.page = page;
|
|
2734
|
+
if (pageSize !== undefined)
|
|
2735
|
+
query.pageSize = pageSize;
|
|
2736
|
+
return getApiV3WantedCutoff(Object.keys(query).length > 0 ? { query } : {});
|
|
2737
|
+
}
|
|
2703
2738
|
async getHostConfig() {
|
|
2704
2739
|
return getApiV3ConfigHost();
|
|
2705
2740
|
}
|
|
@@ -4810,6 +4845,10 @@ function formatOutput(data, options) {
|
|
|
4810
4845
|
if (data == null) {
|
|
4811
4846
|
return;
|
|
4812
4847
|
}
|
|
4848
|
+
if (isMessageOnly(data) && options.format !== "json" && options.format !== "quiet") {
|
|
4849
|
+
console.log(data.message);
|
|
4850
|
+
return;
|
|
4851
|
+
}
|
|
4813
4852
|
switch (options.format) {
|
|
4814
4853
|
case "json": {
|
|
4815
4854
|
const output = options.select ? selectFields(data, options.select) : data;
|
|
@@ -4901,6 +4940,13 @@ function formatHeader(col) {
|
|
|
4901
4940
|
function formatCell(column, value) {
|
|
4902
4941
|
if (value == null)
|
|
4903
4942
|
return "—";
|
|
4943
|
+
const flattened = flattenStructuredValue(value);
|
|
4944
|
+
if (flattened !== undefined) {
|
|
4945
|
+
if (column === "status") {
|
|
4946
|
+
return formatStatus(flattened);
|
|
4947
|
+
}
|
|
4948
|
+
return flattened;
|
|
4949
|
+
}
|
|
4904
4950
|
if (typeof value === "boolean") {
|
|
4905
4951
|
return value ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
|
|
4906
4952
|
}
|
|
@@ -4913,8 +4959,6 @@ function formatCell(column, value) {
|
|
|
4913
4959
|
if (column.toLowerCase().includes("date") || column === "createdAt" || column === "updatedAt") {
|
|
4914
4960
|
return formatDate(value);
|
|
4915
4961
|
}
|
|
4916
|
-
if (typeof value === "object")
|
|
4917
|
-
return JSON.stringify(value);
|
|
4918
4962
|
return String(value);
|
|
4919
4963
|
}
|
|
4920
4964
|
function formatCellPlain(value) {
|
|
@@ -4922,10 +4966,46 @@ function formatCellPlain(value) {
|
|
|
4922
4966
|
return "";
|
|
4923
4967
|
if (typeof value === "boolean")
|
|
4924
4968
|
return value ? "true" : "false";
|
|
4969
|
+
const flattened = flattenStructuredValue(value);
|
|
4970
|
+
if (flattened !== undefined)
|
|
4971
|
+
return flattened;
|
|
4925
4972
|
if (typeof value === "object")
|
|
4926
4973
|
return JSON.stringify(value);
|
|
4927
4974
|
return String(value);
|
|
4928
4975
|
}
|
|
4976
|
+
function flattenStructuredValue(value) {
|
|
4977
|
+
if (Array.isArray(value)) {
|
|
4978
|
+
if (value.length === 0)
|
|
4979
|
+
return "—";
|
|
4980
|
+
const flattened = value.map((item) => getObjectLabel(item) ?? (isPrimitive(item) ? String(item) : undefined)).filter((item) => typeof item === "string" && item.length > 0);
|
|
4981
|
+
if (flattened.length === value.length) {
|
|
4982
|
+
return flattened.join(", ");
|
|
4983
|
+
}
|
|
4984
|
+
return `${value.length} item${value.length === 1 ? "" : "s"}`;
|
|
4985
|
+
}
|
|
4986
|
+
if (typeof value === "object") {
|
|
4987
|
+
return getObjectLabel(value) ?? JSON.stringify(value);
|
|
4988
|
+
}
|
|
4989
|
+
return;
|
|
4990
|
+
}
|
|
4991
|
+
function getObjectLabel(value) {
|
|
4992
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) {
|
|
4993
|
+
return;
|
|
4994
|
+
}
|
|
4995
|
+
const record = value;
|
|
4996
|
+
for (const key of ["name", "title", "label", "path", "value"]) {
|
|
4997
|
+
if (typeof record[key] === "string" || typeof record[key] === "number") {
|
|
4998
|
+
return String(record[key]);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
return;
|
|
5002
|
+
}
|
|
5003
|
+
function isPrimitive(value) {
|
|
5004
|
+
return ["string", "number", "boolean", "bigint", "symbol"].includes(typeof value);
|
|
5005
|
+
}
|
|
5006
|
+
function isMessageOnly(data) {
|
|
5007
|
+
return typeof data === "object" && data !== null && !Array.isArray(data) && Object.keys(data).length === 1 && typeof data.message === "string";
|
|
5008
|
+
}
|
|
4929
5009
|
function formatStatus(status) {
|
|
4930
5010
|
const lower = status.toLowerCase();
|
|
4931
5011
|
if (lower === "ok" || lower === "available" || lower === "ended" || lower === "continuing") {
|
|
@@ -4963,20 +5043,10 @@ function stripAnsi3(str) {
|
|
|
4963
5043
|
return str.replace(ANSI_PATTERN, "");
|
|
4964
5044
|
}
|
|
4965
5045
|
function truncateWithAnsi(str, maxWidth) {
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
const end = str.indexOf("m", i2);
|
|
4971
|
-
if (end !== -1) {
|
|
4972
|
-
i2 = end + 1;
|
|
4973
|
-
continue;
|
|
4974
|
-
}
|
|
4975
|
-
}
|
|
4976
|
-
visible++;
|
|
4977
|
-
i2++;
|
|
4978
|
-
}
|
|
4979
|
-
return `${str.slice(0, i2)}…${RESET}`;
|
|
5046
|
+
const plain = stripAnsi3(str);
|
|
5047
|
+
if (plain.length <= maxWidth)
|
|
5048
|
+
return str;
|
|
5049
|
+
return `${plain.slice(0, Math.max(0, maxWidth - 1))}…`;
|
|
4980
5050
|
}
|
|
4981
5051
|
var ESC, GREEN, RED, YELLOW, RESET, ANSI_PATTERN;
|
|
4982
5052
|
var init_output = __esm(() => {
|
|
@@ -5005,6 +5075,7 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
5005
5075
|
plain: { type: "boolean", description: "Output as TSV (no colors, for piping)" },
|
|
5006
5076
|
quiet: { type: "boolean", alias: "q", description: "Output IDs only" },
|
|
5007
5077
|
"no-header": { type: "boolean", description: "Hide table header row" },
|
|
5078
|
+
"dry-run": { type: "boolean", description: "Show what would happen without executing" },
|
|
5008
5079
|
select: {
|
|
5009
5080
|
type: "string",
|
|
5010
5081
|
description: "Cherry-pick fields (comma-separated, JSON mode)"
|
|
@@ -5012,7 +5083,7 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
5012
5083
|
yes: { type: "boolean", alias: "y", description: "Skip confirmation prompts" },
|
|
5013
5084
|
...(action.args ?? []).reduce((acc, arg) => {
|
|
5014
5085
|
acc[arg.name] = {
|
|
5015
|
-
type: arg.type === "number" ? "string" : "string",
|
|
5086
|
+
type: arg.type === "boolean" ? "boolean" : arg.type === "number" ? "string" : "string",
|
|
5016
5087
|
description: arg.description,
|
|
5017
5088
|
required: false
|
|
5018
5089
|
};
|
|
@@ -5038,8 +5109,20 @@ function buildServiceCommand(serviceName, description, clientFactory, resources)
|
|
|
5038
5109
|
consola.error(`${argDef.name} must be a number.`);
|
|
5039
5110
|
process.exit(1);
|
|
5040
5111
|
}
|
|
5112
|
+
} else if (argDef.type === "boolean" && resolvedArgs[argDef.name] != null) {
|
|
5113
|
+
resolvedArgs[argDef.name] = coerceBooleanArg(resolvedArgs[argDef.name]);
|
|
5041
5114
|
}
|
|
5042
5115
|
}
|
|
5116
|
+
const format = detectFormat(args);
|
|
5117
|
+
const noHeader = process.argv.includes("--no-header") || !!args.noHeader;
|
|
5118
|
+
const dryRun = !!(args["dry-run"] ?? args.dryRun ?? process.argv.includes("--dry-run"));
|
|
5119
|
+
if (dryRun && isWriteAction(action.name)) {
|
|
5120
|
+
formatOutput(buildDryRunPreview(format, serviceName, resource.name, action.name, resolvedArgs), {
|
|
5121
|
+
format,
|
|
5122
|
+
noHeader
|
|
5123
|
+
});
|
|
5124
|
+
return;
|
|
5125
|
+
}
|
|
5043
5126
|
if (action.confirmMessage) {
|
|
5044
5127
|
const confirmed = await promptConfirm(action.confirmMessage, !!args.yes);
|
|
5045
5128
|
if (!confirmed) {
|
|
@@ -5068,12 +5151,11 @@ Run \`tsarr config init\` or set TSARR_${serviceName.toUpperCase()}_API_KEY`);
|
|
|
5068
5151
|
if (result?.records !== undefined && Array.isArray(result.records)) {
|
|
5069
5152
|
result = result.records;
|
|
5070
5153
|
}
|
|
5071
|
-
const format = detectFormat(args);
|
|
5072
5154
|
formatOutput(result, {
|
|
5073
5155
|
format,
|
|
5074
5156
|
columns: action.columns,
|
|
5075
5157
|
idField: action.idField,
|
|
5076
|
-
noHeader
|
|
5158
|
+
noHeader,
|
|
5077
5159
|
select: args.select
|
|
5078
5160
|
});
|
|
5079
5161
|
} catch (error) {
|
|
@@ -5098,6 +5180,53 @@ Run \`tsarr config init\` or set TSARR_${serviceName.toUpperCase()}_API_KEY`);
|
|
|
5098
5180
|
subCommands
|
|
5099
5181
|
});
|
|
5100
5182
|
}
|
|
5183
|
+
function coerceBooleanArg(value) {
|
|
5184
|
+
if (typeof value === "boolean")
|
|
5185
|
+
return value;
|
|
5186
|
+
if (typeof value === "string") {
|
|
5187
|
+
const normalized = value.trim().toLowerCase();
|
|
5188
|
+
if (normalized === "true")
|
|
5189
|
+
return true;
|
|
5190
|
+
if (normalized === "false")
|
|
5191
|
+
return false;
|
|
5192
|
+
}
|
|
5193
|
+
return Boolean(value);
|
|
5194
|
+
}
|
|
5195
|
+
function isWriteAction(actionName) {
|
|
5196
|
+
return [
|
|
5197
|
+
"add",
|
|
5198
|
+
"create",
|
|
5199
|
+
"delete",
|
|
5200
|
+
"edit",
|
|
5201
|
+
"refresh",
|
|
5202
|
+
"manual-search",
|
|
5203
|
+
"grab",
|
|
5204
|
+
"sync",
|
|
5205
|
+
"test",
|
|
5206
|
+
"search"
|
|
5207
|
+
].includes(actionName);
|
|
5208
|
+
}
|
|
5209
|
+
function buildDryRunPreview(format, serviceName, resourceName, actionName, args) {
|
|
5210
|
+
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"));
|
|
5211
|
+
if (format === "json") {
|
|
5212
|
+
return {
|
|
5213
|
+
dryRun: true,
|
|
5214
|
+
service: serviceName,
|
|
5215
|
+
resource: resourceName,
|
|
5216
|
+
action: actionName,
|
|
5217
|
+
args: filteredArgs
|
|
5218
|
+
};
|
|
5219
|
+
}
|
|
5220
|
+
return {
|
|
5221
|
+
message: `Dry run: would execute ${serviceName} ${resourceName} ${actionName}${formatDryRunArgs(filteredArgs)}`
|
|
5222
|
+
};
|
|
5223
|
+
}
|
|
5224
|
+
function formatDryRunArgs(args) {
|
|
5225
|
+
const entries = Object.entries(args);
|
|
5226
|
+
if (entries.length === 0)
|
|
5227
|
+
return "";
|
|
5228
|
+
return ` with ${entries.map(([key, value]) => `${key}=${String(value)}`).join(", ")}`;
|
|
5229
|
+
}
|
|
5101
5230
|
function handleError(error, serviceName) {
|
|
5102
5231
|
if (error instanceof ApiKeyError) {
|
|
5103
5232
|
consola.error(`API key error: ${error.message}
|
|
@@ -5130,6 +5259,51 @@ var exports_radarr3 = {};
|
|
|
5130
5259
|
__export(exports_radarr3, {
|
|
5131
5260
|
radarr: () => radarr
|
|
5132
5261
|
});
|
|
5262
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
5263
|
+
function unwrapData(result) {
|
|
5264
|
+
return result?.data ?? result;
|
|
5265
|
+
}
|
|
5266
|
+
function parseBooleanArg(value, fallback) {
|
|
5267
|
+
if (value === undefined)
|
|
5268
|
+
return fallback;
|
|
5269
|
+
if (typeof value === "boolean")
|
|
5270
|
+
return value;
|
|
5271
|
+
if (typeof value === "string") {
|
|
5272
|
+
const normalized = value.trim().toLowerCase();
|
|
5273
|
+
if (normalized === "true")
|
|
5274
|
+
return true;
|
|
5275
|
+
if (normalized === "false")
|
|
5276
|
+
return false;
|
|
5277
|
+
}
|
|
5278
|
+
return Boolean(value);
|
|
5279
|
+
}
|
|
5280
|
+
function resolveQualityProfileId(profiles, profileId) {
|
|
5281
|
+
const profile = profiles.find((item) => item?.id === profileId);
|
|
5282
|
+
if (!profile) {
|
|
5283
|
+
throw new Error(`Quality profile ${profileId} was not found.`);
|
|
5284
|
+
}
|
|
5285
|
+
return profileId;
|
|
5286
|
+
}
|
|
5287
|
+
function resolveRootFolderPath(folders, rootFolderPath) {
|
|
5288
|
+
const folder = folders.find((item) => item?.path === rootFolderPath);
|
|
5289
|
+
if (!folder) {
|
|
5290
|
+
throw new Error(`Root folder "${rootFolderPath}" was not found.`);
|
|
5291
|
+
}
|
|
5292
|
+
return rootFolderPath;
|
|
5293
|
+
}
|
|
5294
|
+
async function findMovieByTmdbId(client2, tmdbId) {
|
|
5295
|
+
if (tmdbId === undefined)
|
|
5296
|
+
return;
|
|
5297
|
+
const movies = unwrapData(await client2.getMovies());
|
|
5298
|
+
return movies.find((movie) => movie?.tmdbId === tmdbId);
|
|
5299
|
+
}
|
|
5300
|
+
function getApiStatus(result) {
|
|
5301
|
+
return result?.error?.status ?? result?.response?.status;
|
|
5302
|
+
}
|
|
5303
|
+
function readJsonInput(filePath) {
|
|
5304
|
+
const raw = filePath === "-" ? readFileSync2(0, "utf-8") : readFileSync2(filePath, "utf-8");
|
|
5305
|
+
return JSON.parse(raw);
|
|
5306
|
+
}
|
|
5133
5307
|
var resources, radarr;
|
|
5134
5308
|
var init_radarr3 = __esm(() => {
|
|
5135
5309
|
init_radarr2();
|
|
@@ -5150,6 +5324,7 @@ var init_radarr3 = __esm(() => {
|
|
|
5150
5324
|
name: "get",
|
|
5151
5325
|
description: "Get a movie by ID",
|
|
5152
5326
|
args: [{ name: "id", description: "Movie ID", required: true, type: "number" }],
|
|
5327
|
+
columns: ["id", "title", "year", "monitored", "hasFile", "status", "qualityProfileId"],
|
|
5153
5328
|
run: (c3, a2) => c3.getMovie(a2.id)
|
|
5154
5329
|
},
|
|
5155
5330
|
{
|
|
@@ -5163,40 +5338,68 @@ var init_radarr3 = __esm(() => {
|
|
|
5163
5338
|
{
|
|
5164
5339
|
name: "add",
|
|
5165
5340
|
description: "Search and add a movie",
|
|
5166
|
-
args: [
|
|
5341
|
+
args: [
|
|
5342
|
+
{ name: "term", description: "Search term" },
|
|
5343
|
+
{ name: "tmdb-id", description: "TMDB ID", type: "number" },
|
|
5344
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
5345
|
+
{ name: "root-folder", description: "Root folder path" },
|
|
5346
|
+
{ name: "monitored", description: "Set monitored (true/false)" }
|
|
5347
|
+
],
|
|
5167
5348
|
run: async (c3, a2) => {
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5349
|
+
let movie;
|
|
5350
|
+
if (a2["tmdb-id"] !== undefined) {
|
|
5351
|
+
const lookupResult = await c3.lookupMovieByTmdbId(a2["tmdb-id"]);
|
|
5352
|
+
const lookup = unwrapData(lookupResult);
|
|
5353
|
+
const matches = Array.isArray(lookup) ? lookup : [lookup];
|
|
5354
|
+
movie = matches.find((m2) => m2?.tmdbId === a2["tmdb-id"]) ?? matches[0];
|
|
5355
|
+
if (!movie) {
|
|
5356
|
+
throw new Error(`No movie found for TMDB ID ${a2["tmdb-id"]}.`);
|
|
5357
|
+
}
|
|
5358
|
+
} else {
|
|
5359
|
+
const term = await promptIfMissing(a2.term, "Search term:");
|
|
5360
|
+
const searchResult = await c3.searchMovies(term);
|
|
5361
|
+
const results = unwrapData(searchResult);
|
|
5362
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
5363
|
+
throw new Error("No movies found.");
|
|
5364
|
+
}
|
|
5365
|
+
const movieId = await promptSelect("Select a movie:", results.map((m2) => ({
|
|
5366
|
+
label: `${m2.title} (${m2.year})`,
|
|
5367
|
+
value: String(m2.tmdbId)
|
|
5368
|
+
})));
|
|
5369
|
+
movie = results.find((m2) => String(m2.tmdbId) === movieId);
|
|
5370
|
+
if (!movie) {
|
|
5371
|
+
throw new Error("Selected movie was not found in the search results.");
|
|
5372
|
+
}
|
|
5177
5373
|
}
|
|
5178
5374
|
const profilesResult = await c3.getQualityProfiles();
|
|
5179
|
-
const profiles = profilesResult
|
|
5375
|
+
const profiles = unwrapData(profilesResult);
|
|
5180
5376
|
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
5181
5377
|
throw new Error("No quality profiles found. Configure one in Radarr first.");
|
|
5182
5378
|
}
|
|
5183
|
-
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
5379
|
+
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) }))));
|
|
5184
5380
|
const foldersResult = await c3.getRootFolders();
|
|
5185
|
-
const folders = foldersResult
|
|
5381
|
+
const folders = unwrapData(foldersResult);
|
|
5186
5382
|
if (!Array.isArray(folders) || folders.length === 0) {
|
|
5187
5383
|
throw new Error("No root folders found. Configure one in Radarr first.");
|
|
5188
5384
|
}
|
|
5189
|
-
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
5385
|
+
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 })));
|
|
5190
5386
|
const confirmed = await promptConfirm(`Add "${movie.title} (${movie.year})"?`, !!a2.yes);
|
|
5191
5387
|
if (!confirmed)
|
|
5192
5388
|
throw new Error("Cancelled.");
|
|
5193
|
-
|
|
5389
|
+
const addResult = await c3.addMovie({
|
|
5194
5390
|
...movie,
|
|
5195
|
-
qualityProfileId:
|
|
5391
|
+
qualityProfileId: profileId,
|
|
5196
5392
|
rootFolderPath,
|
|
5197
|
-
monitored: true,
|
|
5393
|
+
monitored: parseBooleanArg(a2.monitored, true),
|
|
5198
5394
|
addOptions: { searchForMovie: true }
|
|
5199
5395
|
});
|
|
5396
|
+
if (addResult?.error && getApiStatus(addResult) === 400) {
|
|
5397
|
+
const existingMovie = await findMovieByTmdbId(c3, movie.tmdbId);
|
|
5398
|
+
if (existingMovie) {
|
|
5399
|
+
throw new Error(`${existingMovie.title} is already in your library (ID: ${existingMovie.id})`);
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
return addResult;
|
|
5200
5403
|
}
|
|
5201
5404
|
},
|
|
5202
5405
|
{
|
|
@@ -5236,9 +5439,29 @@ var init_radarr3 = __esm(() => {
|
|
|
5236
5439
|
{
|
|
5237
5440
|
name: "delete",
|
|
5238
5441
|
description: "Delete a movie",
|
|
5239
|
-
args: [
|
|
5442
|
+
args: [
|
|
5443
|
+
{ name: "id", description: "Movie ID", required: true, type: "number" },
|
|
5444
|
+
{ name: "delete-files", description: "Delete movie files", type: "boolean" },
|
|
5445
|
+
{
|
|
5446
|
+
name: "add-import-exclusion",
|
|
5447
|
+
description: "Add import exclusion after delete",
|
|
5448
|
+
type: "boolean"
|
|
5449
|
+
}
|
|
5450
|
+
],
|
|
5240
5451
|
confirmMessage: "Are you sure you want to delete this movie?",
|
|
5241
|
-
run: (c3, a2) =>
|
|
5452
|
+
run: async (c3, a2) => {
|
|
5453
|
+
const movieResult = await c3.getMovie(a2.id);
|
|
5454
|
+
if (movieResult?.error)
|
|
5455
|
+
return movieResult;
|
|
5456
|
+
const movie = unwrapData(movieResult);
|
|
5457
|
+
const deleteResult = await c3.deleteMovie(a2.id, {
|
|
5458
|
+
deleteFiles: a2["delete-files"],
|
|
5459
|
+
addImportExclusion: a2["add-import-exclusion"]
|
|
5460
|
+
});
|
|
5461
|
+
if (deleteResult?.error)
|
|
5462
|
+
return deleteResult;
|
|
5463
|
+
return { message: `Deleted: ${movie.title} (ID: ${movie.id})` };
|
|
5464
|
+
}
|
|
5242
5465
|
}
|
|
5243
5466
|
]
|
|
5244
5467
|
},
|
|
@@ -5264,6 +5487,28 @@ var init_radarr3 = __esm(() => {
|
|
|
5264
5487
|
name: "tag",
|
|
5265
5488
|
description: "Manage tags",
|
|
5266
5489
|
actions: [
|
|
5490
|
+
{
|
|
5491
|
+
name: "create",
|
|
5492
|
+
description: "Create a tag",
|
|
5493
|
+
args: [{ name: "label", description: "Tag label", required: true }],
|
|
5494
|
+
run: (c3, a2) => c3.addTag({ label: a2.label })
|
|
5495
|
+
},
|
|
5496
|
+
{
|
|
5497
|
+
name: "delete",
|
|
5498
|
+
description: "Delete a tag",
|
|
5499
|
+
args: [{ name: "id", description: "Tag ID", required: true, type: "number" }],
|
|
5500
|
+
confirmMessage: "Are you sure you want to delete this tag?",
|
|
5501
|
+
run: async (c3, a2) => {
|
|
5502
|
+
const tagResult = await c3.getTag(a2.id);
|
|
5503
|
+
if (tagResult?.error)
|
|
5504
|
+
return tagResult;
|
|
5505
|
+
const tag = unwrapData(tagResult);
|
|
5506
|
+
const deleteResult = await c3.deleteTag(a2.id);
|
|
5507
|
+
if (deleteResult?.error)
|
|
5508
|
+
return deleteResult;
|
|
5509
|
+
return { message: `Deleted tag: ${tag.label} (ID: ${tag.id})` };
|
|
5510
|
+
}
|
|
5511
|
+
},
|
|
5267
5512
|
{
|
|
5268
5513
|
name: "list",
|
|
5269
5514
|
description: "List all tags",
|
|
@@ -5286,6 +5531,27 @@ var init_radarr3 = __esm(() => {
|
|
|
5286
5531
|
name: "status",
|
|
5287
5532
|
description: "Get queue status",
|
|
5288
5533
|
run: (c3) => c3.getQueueStatus()
|
|
5534
|
+
},
|
|
5535
|
+
{
|
|
5536
|
+
name: "delete",
|
|
5537
|
+
description: "Remove an item from the queue",
|
|
5538
|
+
args: [
|
|
5539
|
+
{ name: "id", description: "Queue item ID", required: true, type: "number" },
|
|
5540
|
+
{ name: "blocklist", description: "Add to blocklist", type: "boolean" },
|
|
5541
|
+
{
|
|
5542
|
+
name: "remove-from-client",
|
|
5543
|
+
description: "Remove from download client",
|
|
5544
|
+
type: "boolean"
|
|
5545
|
+
}
|
|
5546
|
+
],
|
|
5547
|
+
confirmMessage: "Are you sure you want to remove this queue item?",
|
|
5548
|
+
run: (c3, a2) => c3.removeQueueItem(a2.id, a2["remove-from-client"], a2.blocklist)
|
|
5549
|
+
},
|
|
5550
|
+
{
|
|
5551
|
+
name: "grab",
|
|
5552
|
+
description: "Force download a queue item",
|
|
5553
|
+
args: [{ name: "id", description: "Queue item ID", required: true, type: "number" }],
|
|
5554
|
+
run: (c3, a2) => c3.grabQueueItem(a2.id)
|
|
5289
5555
|
}
|
|
5290
5556
|
]
|
|
5291
5557
|
},
|
|
@@ -5298,6 +5564,19 @@ var init_radarr3 = __esm(() => {
|
|
|
5298
5564
|
description: "List root folders",
|
|
5299
5565
|
columns: ["id", "path", "freeSpace"],
|
|
5300
5566
|
run: (c3) => c3.getRootFolders()
|
|
5567
|
+
},
|
|
5568
|
+
{
|
|
5569
|
+
name: "add",
|
|
5570
|
+
description: "Add a root folder",
|
|
5571
|
+
args: [{ name: "path", description: "Folder path", required: true }],
|
|
5572
|
+
run: (c3, a2) => c3.addRootFolder(a2.path)
|
|
5573
|
+
},
|
|
5574
|
+
{
|
|
5575
|
+
name: "delete",
|
|
5576
|
+
description: "Delete a root folder",
|
|
5577
|
+
args: [{ name: "id", description: "Root folder ID", required: true, type: "number" }],
|
|
5578
|
+
confirmMessage: "Are you sure you want to delete this root folder?",
|
|
5579
|
+
run: (c3, a2) => c3.deleteRootFolder(a2.id)
|
|
5301
5580
|
}
|
|
5302
5581
|
]
|
|
5303
5582
|
},
|
|
@@ -5325,8 +5604,222 @@ var init_radarr3 = __esm(() => {
|
|
|
5325
5604
|
{
|
|
5326
5605
|
name: "list",
|
|
5327
5606
|
description: "List recent history",
|
|
5607
|
+
args: [
|
|
5608
|
+
{ name: "since", description: "Start date (ISO 8601, e.g. 2024-01-01)" },
|
|
5609
|
+
{ name: "until", description: "End date (ISO 8601, e.g. 2024-12-31)" }
|
|
5610
|
+
],
|
|
5328
5611
|
columns: ["id", "eventType", "sourceTitle", "date"],
|
|
5329
|
-
run: (c3) =>
|
|
5612
|
+
run: async (c3, a2) => {
|
|
5613
|
+
if (a2.since) {
|
|
5614
|
+
const result2 = await c3.getHistorySince(a2.since);
|
|
5615
|
+
const items2 = unwrapData(result2);
|
|
5616
|
+
if (a2.until) {
|
|
5617
|
+
const untilDate = new Date(a2.until);
|
|
5618
|
+
return items2.filter((item) => new Date(item.date) <= untilDate);
|
|
5619
|
+
}
|
|
5620
|
+
return items2;
|
|
5621
|
+
}
|
|
5622
|
+
const result = await c3.getHistory();
|
|
5623
|
+
const items = unwrapData(result);
|
|
5624
|
+
if (a2.until) {
|
|
5625
|
+
const untilDate = new Date(a2.until);
|
|
5626
|
+
return items.filter((item) => new Date(item.date) <= untilDate);
|
|
5627
|
+
}
|
|
5628
|
+
return items;
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
]
|
|
5632
|
+
},
|
|
5633
|
+
{
|
|
5634
|
+
name: "calendar",
|
|
5635
|
+
description: "View upcoming releases",
|
|
5636
|
+
actions: [
|
|
5637
|
+
{
|
|
5638
|
+
name: "list",
|
|
5639
|
+
description: "List upcoming movie releases",
|
|
5640
|
+
args: [
|
|
5641
|
+
{ name: "start", description: "Start date (ISO 8601)" },
|
|
5642
|
+
{ name: "end", description: "End date (ISO 8601)" },
|
|
5643
|
+
{ name: "unmonitored", description: "Include unmonitored", type: "boolean" }
|
|
5644
|
+
],
|
|
5645
|
+
columns: ["id", "title", "year", "inCinemas", "digitalRelease", "physicalRelease"],
|
|
5646
|
+
run: (c3, a2) => c3.getCalendar(a2.start, a2.end, a2.unmonitored)
|
|
5647
|
+
}
|
|
5648
|
+
]
|
|
5649
|
+
},
|
|
5650
|
+
{
|
|
5651
|
+
name: "notification",
|
|
5652
|
+
description: "Manage notifications",
|
|
5653
|
+
actions: [
|
|
5654
|
+
{
|
|
5655
|
+
name: "list",
|
|
5656
|
+
description: "List notification providers",
|
|
5657
|
+
columns: ["id", "name", "implementation"],
|
|
5658
|
+
run: (c3) => c3.getNotifications()
|
|
5659
|
+
},
|
|
5660
|
+
{
|
|
5661
|
+
name: "get",
|
|
5662
|
+
description: "Get a notification by ID",
|
|
5663
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
5664
|
+
run: (c3, a2) => c3.getNotification(a2.id)
|
|
5665
|
+
},
|
|
5666
|
+
{
|
|
5667
|
+
name: "add",
|
|
5668
|
+
description: "Add a notification from JSON file or stdin",
|
|
5669
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
5670
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput(a2.file))
|
|
5671
|
+
},
|
|
5672
|
+
{
|
|
5673
|
+
name: "edit",
|
|
5674
|
+
description: "Edit a notification (merges JSON with existing)",
|
|
5675
|
+
args: [
|
|
5676
|
+
{ name: "id", description: "Notification ID", required: true, type: "number" },
|
|
5677
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
5678
|
+
],
|
|
5679
|
+
run: async (c3, a2) => {
|
|
5680
|
+
const existing = unwrapData(await c3.getNotification(a2.id));
|
|
5681
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
5682
|
+
}
|
|
5683
|
+
},
|
|
5684
|
+
{
|
|
5685
|
+
name: "delete",
|
|
5686
|
+
description: "Delete a notification",
|
|
5687
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
5688
|
+
confirmMessage: "Are you sure you want to delete this notification?",
|
|
5689
|
+
run: (c3, a2) => c3.deleteNotification(a2.id)
|
|
5690
|
+
},
|
|
5691
|
+
{
|
|
5692
|
+
name: "test",
|
|
5693
|
+
description: "Test all notifications",
|
|
5694
|
+
run: (c3) => c3.testAllNotifications()
|
|
5695
|
+
}
|
|
5696
|
+
]
|
|
5697
|
+
},
|
|
5698
|
+
{
|
|
5699
|
+
name: "downloadclient",
|
|
5700
|
+
description: "Manage download clients",
|
|
5701
|
+
actions: [
|
|
5702
|
+
{
|
|
5703
|
+
name: "list",
|
|
5704
|
+
description: "List download clients",
|
|
5705
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
5706
|
+
run: (c3) => c3.getDownloadClients()
|
|
5707
|
+
},
|
|
5708
|
+
{
|
|
5709
|
+
name: "get",
|
|
5710
|
+
description: "Get a download client by ID",
|
|
5711
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
5712
|
+
run: (c3, a2) => c3.getDownloadClient(a2.id)
|
|
5713
|
+
},
|
|
5714
|
+
{
|
|
5715
|
+
name: "add",
|
|
5716
|
+
description: "Add a download client from JSON file or stdin",
|
|
5717
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
5718
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput(a2.file))
|
|
5719
|
+
},
|
|
5720
|
+
{
|
|
5721
|
+
name: "edit",
|
|
5722
|
+
description: "Edit a download client (merges JSON with existing)",
|
|
5723
|
+
args: [
|
|
5724
|
+
{ name: "id", description: "Download client ID", required: true, type: "number" },
|
|
5725
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
5726
|
+
],
|
|
5727
|
+
run: async (c3, a2) => {
|
|
5728
|
+
const existing = unwrapData(await c3.getDownloadClient(a2.id));
|
|
5729
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
5730
|
+
}
|
|
5731
|
+
},
|
|
5732
|
+
{
|
|
5733
|
+
name: "delete",
|
|
5734
|
+
description: "Delete a download client",
|
|
5735
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
5736
|
+
confirmMessage: "Are you sure you want to delete this download client?",
|
|
5737
|
+
run: (c3, a2) => c3.deleteDownloadClient(a2.id)
|
|
5738
|
+
},
|
|
5739
|
+
{
|
|
5740
|
+
name: "test",
|
|
5741
|
+
description: "Test all download clients",
|
|
5742
|
+
run: (c3) => c3.testAllDownloadClients()
|
|
5743
|
+
}
|
|
5744
|
+
]
|
|
5745
|
+
},
|
|
5746
|
+
{
|
|
5747
|
+
name: "blocklist",
|
|
5748
|
+
description: "Manage blocked releases",
|
|
5749
|
+
actions: [
|
|
5750
|
+
{
|
|
5751
|
+
name: "list",
|
|
5752
|
+
description: "List blocked releases",
|
|
5753
|
+
columns: ["id", "sourceTitle", "date"],
|
|
5754
|
+
run: (c3) => c3.getBlocklist()
|
|
5755
|
+
},
|
|
5756
|
+
{
|
|
5757
|
+
name: "delete",
|
|
5758
|
+
description: "Remove a release from the blocklist",
|
|
5759
|
+
args: [{ name: "id", description: "Blocklist item ID", required: true, type: "number" }],
|
|
5760
|
+
confirmMessage: "Are you sure you want to remove this blocklist entry?",
|
|
5761
|
+
run: (c3, a2) => c3.removeBlocklistItem(a2.id)
|
|
5762
|
+
}
|
|
5763
|
+
]
|
|
5764
|
+
},
|
|
5765
|
+
{
|
|
5766
|
+
name: "wanted",
|
|
5767
|
+
description: "View missing and cutoff unmet movies",
|
|
5768
|
+
actions: [
|
|
5769
|
+
{
|
|
5770
|
+
name: "missing",
|
|
5771
|
+
description: "List movies with missing files",
|
|
5772
|
+
columns: ["id", "title", "year", "monitored"],
|
|
5773
|
+
run: (c3) => c3.getWantedMissing()
|
|
5774
|
+
},
|
|
5775
|
+
{
|
|
5776
|
+
name: "cutoff",
|
|
5777
|
+
description: "List movies below quality cutoff",
|
|
5778
|
+
columns: ["id", "title", "year", "monitored"],
|
|
5779
|
+
run: (c3) => c3.getWantedCutoff()
|
|
5780
|
+
}
|
|
5781
|
+
]
|
|
5782
|
+
},
|
|
5783
|
+
{
|
|
5784
|
+
name: "importlist",
|
|
5785
|
+
description: "Manage import lists",
|
|
5786
|
+
actions: [
|
|
5787
|
+
{
|
|
5788
|
+
name: "list",
|
|
5789
|
+
description: "List import lists",
|
|
5790
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
5791
|
+
run: (c3) => c3.getImportLists()
|
|
5792
|
+
},
|
|
5793
|
+
{
|
|
5794
|
+
name: "get",
|
|
5795
|
+
description: "Get an import list by ID",
|
|
5796
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
5797
|
+
run: (c3, a2) => c3.getImportList(a2.id)
|
|
5798
|
+
},
|
|
5799
|
+
{
|
|
5800
|
+
name: "add",
|
|
5801
|
+
description: "Add an import list from JSON file or stdin",
|
|
5802
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
5803
|
+
run: async (c3, a2) => c3.addImportList(readJsonInput(a2.file))
|
|
5804
|
+
},
|
|
5805
|
+
{
|
|
5806
|
+
name: "edit",
|
|
5807
|
+
description: "Edit an import list (merges JSON with existing)",
|
|
5808
|
+
args: [
|
|
5809
|
+
{ name: "id", description: "Import list ID", required: true, type: "number" },
|
|
5810
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
5811
|
+
],
|
|
5812
|
+
run: async (c3, a2) => {
|
|
5813
|
+
const existing = unwrapData(await c3.getImportList(a2.id));
|
|
5814
|
+
return c3.updateImportList(a2.id, { ...existing, ...readJsonInput(a2.file) });
|
|
5815
|
+
}
|
|
5816
|
+
},
|
|
5817
|
+
{
|
|
5818
|
+
name: "delete",
|
|
5819
|
+
description: "Delete an import list",
|
|
5820
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
5821
|
+
confirmMessage: "Are you sure you want to delete this import list?",
|
|
5822
|
+
run: (c3, a2) => c3.deleteImportList(a2.id)
|
|
5330
5823
|
}
|
|
5331
5824
|
]
|
|
5332
5825
|
},
|
|
@@ -7261,8 +7754,11 @@ class SonarrClient {
|
|
|
7261
7754
|
async updateSeries(id, series) {
|
|
7262
7755
|
return putApiV3SeriesById({ path: { id }, body: series });
|
|
7263
7756
|
}
|
|
7264
|
-
async deleteSeries(id) {
|
|
7265
|
-
return deleteApiV3SeriesById({
|
|
7757
|
+
async deleteSeries(id, options) {
|
|
7758
|
+
return deleteApiV3SeriesById({
|
|
7759
|
+
path: { id },
|
|
7760
|
+
...options ? { query: options } : {}
|
|
7761
|
+
});
|
|
7266
7762
|
}
|
|
7267
7763
|
async getSeriesFolder(id) {
|
|
7268
7764
|
return getApiV3SeriesByIdFolder({ path: { id } });
|
|
@@ -7385,8 +7881,13 @@ class SonarrClient {
|
|
|
7385
7881
|
async getTagDetailById(id) {
|
|
7386
7882
|
return getApiV3TagDetailById2({ path: { id } });
|
|
7387
7883
|
}
|
|
7388
|
-
async getEpisodes() {
|
|
7389
|
-
|
|
7884
|
+
async getEpisodes(seriesId, episodeIds) {
|
|
7885
|
+
const query = {};
|
|
7886
|
+
if (seriesId !== undefined)
|
|
7887
|
+
query.seriesId = seriesId;
|
|
7888
|
+
if (episodeIds !== undefined)
|
|
7889
|
+
query.episodeIds = episodeIds;
|
|
7890
|
+
return getApiV3Episode(Object.keys(query).length > 0 ? { query } : {});
|
|
7390
7891
|
}
|
|
7391
7892
|
async getEpisode(id) {
|
|
7392
7893
|
return getApiV3EpisodeById({ path: { id } });
|
|
@@ -7600,7 +8101,7 @@ class SonarrClient {
|
|
|
7600
8101
|
query.tags = tags;
|
|
7601
8102
|
return getFeedV3CalendarSonarrIcs(Object.keys(query).length > 0 ? { query } : {});
|
|
7602
8103
|
}
|
|
7603
|
-
async getQueue(page, pageSize, sortKey, sortDirection, includeUnknownSeriesItems) {
|
|
8104
|
+
async getQueue(page, pageSize, sortKey, sortDirection, includeUnknownSeriesItems, seriesId) {
|
|
7604
8105
|
const query = {};
|
|
7605
8106
|
if (page !== undefined)
|
|
7606
8107
|
query.page = page;
|
|
@@ -7612,6 +8113,8 @@ class SonarrClient {
|
|
|
7612
8113
|
query.sortDirection = sortDirection;
|
|
7613
8114
|
if (includeUnknownSeriesItems !== undefined)
|
|
7614
8115
|
query.includeUnknownSeriesItems = includeUnknownSeriesItems;
|
|
8116
|
+
if (seriesId !== undefined)
|
|
8117
|
+
query.seriesIds = [seriesId];
|
|
7615
8118
|
return getApiV3Queue2(Object.keys(query).length > 0 ? { query } : {});
|
|
7616
8119
|
}
|
|
7617
8120
|
async removeQueueItem(id, removeFromClient, blocklist) {
|
|
@@ -7734,6 +8237,70 @@ var exports_sonarr3 = {};
|
|
|
7734
8237
|
__export(exports_sonarr3, {
|
|
7735
8238
|
sonarr: () => sonarr
|
|
7736
8239
|
});
|
|
8240
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
8241
|
+
function unwrapData2(result) {
|
|
8242
|
+
return result?.data ?? result;
|
|
8243
|
+
}
|
|
8244
|
+
function parseBooleanArg2(value, fallback) {
|
|
8245
|
+
if (value === undefined)
|
|
8246
|
+
return fallback;
|
|
8247
|
+
if (typeof value === "boolean")
|
|
8248
|
+
return value;
|
|
8249
|
+
if (typeof value === "string") {
|
|
8250
|
+
const normalized = value.trim().toLowerCase();
|
|
8251
|
+
if (normalized === "true")
|
|
8252
|
+
return true;
|
|
8253
|
+
if (normalized === "false")
|
|
8254
|
+
return false;
|
|
8255
|
+
}
|
|
8256
|
+
return Boolean(value);
|
|
8257
|
+
}
|
|
8258
|
+
function resolveQualityProfileId2(profiles, profileId) {
|
|
8259
|
+
const profile = profiles.find((item) => item?.id === profileId);
|
|
8260
|
+
if (!profile) {
|
|
8261
|
+
throw new Error(`Quality profile ${profileId} was not found.`);
|
|
8262
|
+
}
|
|
8263
|
+
return profileId;
|
|
8264
|
+
}
|
|
8265
|
+
function resolveRootFolderPath2(folders, rootFolderPath) {
|
|
8266
|
+
const folder = folders.find((item) => item?.path === rootFolderPath);
|
|
8267
|
+
if (!folder) {
|
|
8268
|
+
throw new Error(`Root folder "${rootFolderPath}" was not found.`);
|
|
8269
|
+
}
|
|
8270
|
+
return rootFolderPath;
|
|
8271
|
+
}
|
|
8272
|
+
function formatSeriesListItem(series) {
|
|
8273
|
+
const seasons = Array.isArray(series?.seasons) ? series.seasons.filter((season) => season?.seasonNumber !== 0) : [];
|
|
8274
|
+
const statistics = series?.statistics ?? {};
|
|
8275
|
+
return {
|
|
8276
|
+
...series,
|
|
8277
|
+
seasonCount: seasons.length,
|
|
8278
|
+
episodeCount: statistics.episodeCount !== undefined ? `${statistics.episodeFileCount ?? 0}/${statistics.episodeCount}` : "—",
|
|
8279
|
+
network: series?.network,
|
|
8280
|
+
status: series?.status
|
|
8281
|
+
};
|
|
8282
|
+
}
|
|
8283
|
+
async function lookupSeriesByTvdbId(client3, tvdbId) {
|
|
8284
|
+
const tvdbSearch = unwrapData2(await client3.searchSeries(`tvdb:${tvdbId}`));
|
|
8285
|
+
const exactTvdbMatch = tvdbSearch.find((series) => series?.tvdbId === tvdbId);
|
|
8286
|
+
if (exactTvdbMatch)
|
|
8287
|
+
return exactTvdbMatch;
|
|
8288
|
+
const fallbackSearch = unwrapData2(await client3.searchSeries(String(tvdbId)));
|
|
8289
|
+
return fallbackSearch.find((series) => series?.tvdbId === tvdbId);
|
|
8290
|
+
}
|
|
8291
|
+
async function findSeriesByTvdbId(client3, tvdbId) {
|
|
8292
|
+
if (tvdbId === undefined)
|
|
8293
|
+
return;
|
|
8294
|
+
const series = unwrapData2(await client3.getSeries());
|
|
8295
|
+
return series.find((item) => item?.tvdbId === tvdbId);
|
|
8296
|
+
}
|
|
8297
|
+
function getApiStatus2(result) {
|
|
8298
|
+
return result?.error?.status ?? result?.response?.status;
|
|
8299
|
+
}
|
|
8300
|
+
function readJsonInput2(filePath) {
|
|
8301
|
+
const raw = filePath === "-" ? readFileSync3(0, "utf-8") : readFileSync3(filePath, "utf-8");
|
|
8302
|
+
return JSON.parse(raw);
|
|
8303
|
+
}
|
|
7737
8304
|
var resources2, sonarr;
|
|
7738
8305
|
var init_sonarr3 = __esm(() => {
|
|
7739
8306
|
init_sonarr2();
|
|
@@ -7747,14 +8314,40 @@ var init_sonarr3 = __esm(() => {
|
|
|
7747
8314
|
{
|
|
7748
8315
|
name: "list",
|
|
7749
8316
|
description: "List all series",
|
|
7750
|
-
columns: [
|
|
7751
|
-
|
|
8317
|
+
columns: [
|
|
8318
|
+
"id",
|
|
8319
|
+
"title",
|
|
8320
|
+
"year",
|
|
8321
|
+
"monitored",
|
|
8322
|
+
"seasonCount",
|
|
8323
|
+
"episodeCount",
|
|
8324
|
+
"network",
|
|
8325
|
+
"status"
|
|
8326
|
+
],
|
|
8327
|
+
run: async (c3) => {
|
|
8328
|
+
const series = unwrapData2(await c3.getSeries());
|
|
8329
|
+
return series.map(formatSeriesListItem);
|
|
8330
|
+
}
|
|
7752
8331
|
},
|
|
7753
8332
|
{
|
|
7754
8333
|
name: "get",
|
|
7755
8334
|
description: "Get a series by ID",
|
|
7756
8335
|
args: [{ name: "id", description: "Series ID", required: true, type: "number" }],
|
|
7757
|
-
|
|
8336
|
+
columns: [
|
|
8337
|
+
"id",
|
|
8338
|
+
"title",
|
|
8339
|
+
"year",
|
|
8340
|
+
"monitored",
|
|
8341
|
+
"seasonCount",
|
|
8342
|
+
"episodeCount",
|
|
8343
|
+
"network",
|
|
8344
|
+
"status"
|
|
8345
|
+
],
|
|
8346
|
+
run: async (c3, a2) => {
|
|
8347
|
+
const result = await c3.getSeriesById(a2.id);
|
|
8348
|
+
const series = unwrapData2(result);
|
|
8349
|
+
return formatSeriesListItem(series);
|
|
8350
|
+
}
|
|
7758
8351
|
},
|
|
7759
8352
|
{
|
|
7760
8353
|
name: "search",
|
|
@@ -7766,136 +8359,502 @@ var init_sonarr3 = __esm(() => {
|
|
|
7766
8359
|
{
|
|
7767
8360
|
name: "add",
|
|
7768
8361
|
description: "Search and add a series",
|
|
7769
|
-
args: [
|
|
8362
|
+
args: [
|
|
8363
|
+
{ name: "term", description: "Search term" },
|
|
8364
|
+
{ name: "tvdb-id", description: "TVDB ID", type: "number" },
|
|
8365
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
8366
|
+
{ name: "root-folder", description: "Root folder path" },
|
|
8367
|
+
{ name: "monitored", description: "Set monitored (true/false)" }
|
|
8368
|
+
],
|
|
7770
8369
|
run: async (c3, a2) => {
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
8370
|
+
let series;
|
|
8371
|
+
if (a2["tvdb-id"] !== undefined) {
|
|
8372
|
+
series = await lookupSeriesByTvdbId(c3, a2["tvdb-id"]);
|
|
8373
|
+
if (!series) {
|
|
8374
|
+
throw new Error(`No series found for TVDB ID ${a2["tvdb-id"]}.`);
|
|
8375
|
+
}
|
|
8376
|
+
} else {
|
|
8377
|
+
const term = await promptIfMissing(a2.term, "Search term:");
|
|
8378
|
+
const searchResult = await c3.searchSeries(term);
|
|
8379
|
+
const results = unwrapData2(searchResult);
|
|
8380
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
8381
|
+
throw new Error("No series found.");
|
|
8382
|
+
}
|
|
8383
|
+
const seriesId = await promptSelect("Select a series:", results.map((s2) => ({
|
|
8384
|
+
label: `${s2.title} (${s2.year})`,
|
|
8385
|
+
value: String(s2.tvdbId)
|
|
8386
|
+
})));
|
|
8387
|
+
series = results.find((s2) => String(s2.tvdbId) === seriesId);
|
|
8388
|
+
if (!series) {
|
|
8389
|
+
throw new Error("Selected series was not found in the search results.");
|
|
8390
|
+
}
|
|
7780
8391
|
}
|
|
7781
8392
|
const profilesResult = await c3.getQualityProfiles();
|
|
7782
|
-
const profiles = profilesResult
|
|
8393
|
+
const profiles = unwrapData2(profilesResult);
|
|
7783
8394
|
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
7784
8395
|
throw new Error("No quality profiles found. Configure one in Sonarr first.");
|
|
7785
8396
|
}
|
|
7786
|
-
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
8397
|
+
const profileId = a2["quality-profile-id"] !== undefined ? resolveQualityProfileId2(profiles, a2["quality-profile-id"]) : Number(await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) }))));
|
|
7787
8398
|
const foldersResult = await c3.getRootFolders();
|
|
7788
|
-
const folders = foldersResult
|
|
8399
|
+
const folders = unwrapData2(foldersResult);
|
|
7789
8400
|
if (!Array.isArray(folders) || folders.length === 0) {
|
|
7790
8401
|
throw new Error("No root folders found. Configure one in Sonarr first.");
|
|
7791
8402
|
}
|
|
7792
|
-
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
8403
|
+
const rootFolderPath = a2["root-folder"] !== undefined ? resolveRootFolderPath2(folders, a2["root-folder"]) : await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
7793
8404
|
const confirmed = await promptConfirm(`Add "${series.title} (${series.year})"?`, !!a2.yes);
|
|
7794
8405
|
if (!confirmed)
|
|
7795
8406
|
throw new Error("Cancelled.");
|
|
7796
|
-
|
|
8407
|
+
const addResult = await c3.addSeries({
|
|
7797
8408
|
...series,
|
|
7798
|
-
qualityProfileId:
|
|
8409
|
+
qualityProfileId: profileId,
|
|
7799
8410
|
rootFolderPath,
|
|
7800
|
-
monitored: true,
|
|
8411
|
+
monitored: parseBooleanArg2(a2.monitored, true),
|
|
7801
8412
|
addOptions: { searchForMissingEpisodes: true }
|
|
7802
8413
|
});
|
|
8414
|
+
if (addResult?.error && getApiStatus2(addResult) === 400) {
|
|
8415
|
+
const existingSeries = await findSeriesByTvdbId(c3, series.tvdbId);
|
|
8416
|
+
if (existingSeries) {
|
|
8417
|
+
throw new Error(`${existingSeries.title} is already in your library (ID: ${existingSeries.id})`);
|
|
8418
|
+
}
|
|
8419
|
+
}
|
|
8420
|
+
return addResult;
|
|
8421
|
+
}
|
|
8422
|
+
},
|
|
8423
|
+
{
|
|
8424
|
+
name: "edit",
|
|
8425
|
+
description: "Edit a series",
|
|
8426
|
+
args: [
|
|
8427
|
+
{ name: "id", description: "Series ID", required: true, type: "number" },
|
|
8428
|
+
{ name: "monitored", description: "Set monitored (true/false)" },
|
|
8429
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
8430
|
+
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
8431
|
+
],
|
|
8432
|
+
run: async (c3, a2) => {
|
|
8433
|
+
const result = await c3.getSeriesById(a2.id);
|
|
8434
|
+
const series = result?.data ?? result;
|
|
8435
|
+
const updates = { ...series };
|
|
8436
|
+
if (a2.monitored !== undefined)
|
|
8437
|
+
updates.monitored = a2.monitored === "true";
|
|
8438
|
+
if (a2["quality-profile-id"] !== undefined)
|
|
8439
|
+
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
8440
|
+
if (a2.tags !== undefined)
|
|
8441
|
+
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
8442
|
+
return c3.updateSeries(String(a2.id), updates);
|
|
8443
|
+
}
|
|
8444
|
+
},
|
|
8445
|
+
{
|
|
8446
|
+
name: "refresh",
|
|
8447
|
+
description: "Refresh series metadata",
|
|
8448
|
+
args: [{ name: "id", description: "Series ID", required: true, type: "number" }],
|
|
8449
|
+
run: (c3, a2) => c3.runCommand({ name: "RefreshSeries", seriesId: a2.id })
|
|
8450
|
+
},
|
|
8451
|
+
{
|
|
8452
|
+
name: "manual-search",
|
|
8453
|
+
description: "Trigger a manual search for releases",
|
|
8454
|
+
args: [{ name: "id", description: "Series ID", required: true, type: "number" }],
|
|
8455
|
+
run: (c3, a2) => c3.runCommand({ name: "SeriesSearch", seriesId: a2.id })
|
|
8456
|
+
},
|
|
8457
|
+
{
|
|
8458
|
+
name: "delete",
|
|
8459
|
+
description: "Delete a series",
|
|
8460
|
+
args: [
|
|
8461
|
+
{ name: "id", description: "Series ID", required: true, type: "number" },
|
|
8462
|
+
{ name: "delete-files", description: "Delete series files", type: "boolean" },
|
|
8463
|
+
{
|
|
8464
|
+
name: "add-import-list-exclusion",
|
|
8465
|
+
description: "Add import list exclusion after delete",
|
|
8466
|
+
type: "boolean"
|
|
8467
|
+
}
|
|
8468
|
+
],
|
|
8469
|
+
confirmMessage: "Are you sure you want to delete this series?",
|
|
8470
|
+
run: async (c3, a2) => {
|
|
8471
|
+
const seriesResult = await c3.getSeriesById(a2.id);
|
|
8472
|
+
if (seriesResult?.error)
|
|
8473
|
+
return seriesResult;
|
|
8474
|
+
const series = unwrapData2(seriesResult);
|
|
8475
|
+
const deleteResult = await c3.deleteSeries(a2.id, {
|
|
8476
|
+
deleteFiles: a2["delete-files"],
|
|
8477
|
+
addImportListExclusion: a2["add-import-list-exclusion"]
|
|
8478
|
+
});
|
|
8479
|
+
if (deleteResult?.error)
|
|
8480
|
+
return deleteResult;
|
|
8481
|
+
return { message: `Deleted: ${series.title} (ID: ${series.id})` };
|
|
8482
|
+
}
|
|
8483
|
+
}
|
|
8484
|
+
]
|
|
8485
|
+
},
|
|
8486
|
+
{
|
|
8487
|
+
name: "episode",
|
|
8488
|
+
description: "Manage episodes",
|
|
8489
|
+
actions: [
|
|
8490
|
+
{
|
|
8491
|
+
name: "list",
|
|
8492
|
+
description: "List all episodes",
|
|
8493
|
+
args: [{ name: "series-id", description: "Series ID", required: true, type: "number" }],
|
|
8494
|
+
columns: ["id", "title", "seasonNumber", "episodeNumber", "hasFile"],
|
|
8495
|
+
run: (c3, a2) => c3.getEpisodes(a2["series-id"])
|
|
8496
|
+
},
|
|
8497
|
+
{
|
|
8498
|
+
name: "get",
|
|
8499
|
+
description: "Get an episode by ID",
|
|
8500
|
+
args: [{ name: "id", description: "Episode ID", required: true, type: "number" }],
|
|
8501
|
+
run: (c3, a2) => c3.getEpisode(a2.id)
|
|
8502
|
+
},
|
|
8503
|
+
{
|
|
8504
|
+
name: "search",
|
|
8505
|
+
description: "Trigger a search for an episode",
|
|
8506
|
+
args: [{ name: "id", description: "Episode ID", required: true, type: "number" }],
|
|
8507
|
+
run: (c3, a2) => c3.runCommand({ name: "EpisodeSearch", episodeIds: [a2.id] })
|
|
8508
|
+
}
|
|
8509
|
+
]
|
|
8510
|
+
},
|
|
8511
|
+
{
|
|
8512
|
+
name: "profile",
|
|
8513
|
+
description: "Manage quality profiles",
|
|
8514
|
+
actions: [
|
|
8515
|
+
{
|
|
8516
|
+
name: "list",
|
|
8517
|
+
description: "List quality profiles",
|
|
8518
|
+
columns: ["id", "name"],
|
|
8519
|
+
run: (c3) => c3.getQualityProfiles()
|
|
8520
|
+
},
|
|
8521
|
+
{
|
|
8522
|
+
name: "get",
|
|
8523
|
+
description: "Get a quality profile by ID",
|
|
8524
|
+
args: [{ name: "id", description: "Profile ID", required: true, type: "number" }],
|
|
8525
|
+
run: (c3, a2) => c3.getQualityProfile(a2.id)
|
|
8526
|
+
}
|
|
8527
|
+
]
|
|
8528
|
+
},
|
|
8529
|
+
{
|
|
8530
|
+
name: "tag",
|
|
8531
|
+
description: "Manage tags",
|
|
8532
|
+
actions: [
|
|
8533
|
+
{
|
|
8534
|
+
name: "create",
|
|
8535
|
+
description: "Create a tag",
|
|
8536
|
+
args: [{ name: "label", description: "Tag label", required: true }],
|
|
8537
|
+
run: (c3, a2) => c3.addTag({ label: a2.label })
|
|
8538
|
+
},
|
|
8539
|
+
{
|
|
8540
|
+
name: "delete",
|
|
8541
|
+
description: "Delete a tag",
|
|
8542
|
+
args: [{ name: "id", description: "Tag ID", required: true, type: "number" }],
|
|
8543
|
+
confirmMessage: "Are you sure you want to delete this tag?",
|
|
8544
|
+
run: async (c3, a2) => {
|
|
8545
|
+
const tagResult = await c3.getTag(a2.id);
|
|
8546
|
+
if (tagResult?.error)
|
|
8547
|
+
return tagResult;
|
|
8548
|
+
const tag = unwrapData2(tagResult);
|
|
8549
|
+
const deleteResult = await c3.deleteTag(a2.id);
|
|
8550
|
+
if (deleteResult?.error)
|
|
8551
|
+
return deleteResult;
|
|
8552
|
+
return { message: `Deleted tag: ${tag.label} (ID: ${tag.id})` };
|
|
8553
|
+
}
|
|
8554
|
+
},
|
|
8555
|
+
{
|
|
8556
|
+
name: "list",
|
|
8557
|
+
description: "List all tags",
|
|
8558
|
+
columns: ["id", "label"],
|
|
8559
|
+
run: (c3) => c3.getTags()
|
|
8560
|
+
}
|
|
8561
|
+
]
|
|
8562
|
+
},
|
|
8563
|
+
{
|
|
8564
|
+
name: "queue",
|
|
8565
|
+
description: "Manage download queue",
|
|
8566
|
+
actions: [
|
|
8567
|
+
{
|
|
8568
|
+
name: "list",
|
|
8569
|
+
description: "List queue items",
|
|
8570
|
+
args: [{ name: "series-id", description: "Series ID", type: "number" }],
|
|
8571
|
+
columns: ["id", "title", "status", "sizeleft", "timeleft"],
|
|
8572
|
+
run: (c3, a2) => c3.getQueue(undefined, undefined, undefined, undefined, undefined, a2["series-id"])
|
|
8573
|
+
},
|
|
8574
|
+
{
|
|
8575
|
+
name: "status",
|
|
8576
|
+
description: "Get queue status",
|
|
8577
|
+
run: (c3) => c3.getQueueStatus()
|
|
8578
|
+
},
|
|
8579
|
+
{
|
|
8580
|
+
name: "delete",
|
|
8581
|
+
description: "Remove an item from the queue",
|
|
8582
|
+
args: [
|
|
8583
|
+
{ name: "id", description: "Queue item ID", required: true, type: "number" },
|
|
8584
|
+
{ name: "blocklist", description: "Add to blocklist", type: "boolean" },
|
|
8585
|
+
{
|
|
8586
|
+
name: "remove-from-client",
|
|
8587
|
+
description: "Remove from download client",
|
|
8588
|
+
type: "boolean"
|
|
8589
|
+
}
|
|
8590
|
+
],
|
|
8591
|
+
confirmMessage: "Are you sure you want to remove this queue item?",
|
|
8592
|
+
run: (c3, a2) => c3.removeQueueItem(a2.id, a2["remove-from-client"], a2.blocklist)
|
|
8593
|
+
},
|
|
8594
|
+
{
|
|
8595
|
+
name: "grab",
|
|
8596
|
+
description: "Force download a queue item",
|
|
8597
|
+
args: [{ name: "id", description: "Queue item ID", required: true, type: "number" }],
|
|
8598
|
+
run: (c3, a2) => c3.grabQueueItem(a2.id)
|
|
8599
|
+
}
|
|
8600
|
+
]
|
|
8601
|
+
},
|
|
8602
|
+
{
|
|
8603
|
+
name: "history",
|
|
8604
|
+
description: "View history",
|
|
8605
|
+
actions: [
|
|
8606
|
+
{
|
|
8607
|
+
name: "list",
|
|
8608
|
+
description: "List recent history",
|
|
8609
|
+
args: [
|
|
8610
|
+
{ name: "series-id", description: "Series ID", type: "number" },
|
|
8611
|
+
{ name: "since", description: "Start date (ISO 8601, e.g. 2024-01-01)" },
|
|
8612
|
+
{ name: "until", description: "End date (ISO 8601, e.g. 2024-12-31)" }
|
|
8613
|
+
],
|
|
8614
|
+
columns: ["id", "eventType", "sourceTitle", "date"],
|
|
8615
|
+
run: async (c3, a2) => {
|
|
8616
|
+
if (a2.since) {
|
|
8617
|
+
const result2 = await c3.getHistorySince(a2.since, a2["series-id"]);
|
|
8618
|
+
const items2 = unwrapData2(result2);
|
|
8619
|
+
if (a2.until) {
|
|
8620
|
+
const untilDate = new Date(a2.until);
|
|
8621
|
+
return items2.filter((item) => new Date(item.date) <= untilDate);
|
|
8622
|
+
}
|
|
8623
|
+
return items2;
|
|
8624
|
+
}
|
|
8625
|
+
const result = await c3.getHistory(undefined, undefined, undefined, undefined, a2["series-id"]);
|
|
8626
|
+
const items = unwrapData2(result);
|
|
8627
|
+
if (a2.until) {
|
|
8628
|
+
const untilDate = new Date(a2.until);
|
|
8629
|
+
return items.filter((item) => new Date(item.date) <= untilDate);
|
|
8630
|
+
}
|
|
8631
|
+
return items;
|
|
8632
|
+
}
|
|
8633
|
+
}
|
|
8634
|
+
]
|
|
8635
|
+
},
|
|
8636
|
+
{
|
|
8637
|
+
name: "rootfolder",
|
|
8638
|
+
description: "Manage root folders",
|
|
8639
|
+
actions: [
|
|
8640
|
+
{
|
|
8641
|
+
name: "list",
|
|
8642
|
+
description: "List root folders",
|
|
8643
|
+
columns: ["id", "path", "freeSpace"],
|
|
8644
|
+
run: (c3) => c3.getRootFolders()
|
|
8645
|
+
},
|
|
8646
|
+
{
|
|
8647
|
+
name: "add",
|
|
8648
|
+
description: "Add a root folder",
|
|
8649
|
+
args: [{ name: "path", description: "Folder path", required: true }],
|
|
8650
|
+
run: (c3, a2) => c3.addRootFolder(a2.path)
|
|
8651
|
+
},
|
|
8652
|
+
{
|
|
8653
|
+
name: "delete",
|
|
8654
|
+
description: "Delete a root folder",
|
|
8655
|
+
args: [{ name: "id", description: "Root folder ID", required: true, type: "number" }],
|
|
8656
|
+
confirmMessage: "Are you sure you want to delete this root folder?",
|
|
8657
|
+
run: (c3, a2) => c3.deleteRootFolder(a2.id)
|
|
8658
|
+
}
|
|
8659
|
+
]
|
|
8660
|
+
},
|
|
8661
|
+
{
|
|
8662
|
+
name: "calendar",
|
|
8663
|
+
description: "View upcoming releases",
|
|
8664
|
+
actions: [
|
|
8665
|
+
{
|
|
8666
|
+
name: "list",
|
|
8667
|
+
description: "List upcoming episode releases",
|
|
8668
|
+
args: [
|
|
8669
|
+
{ name: "start", description: "Start date (ISO 8601)" },
|
|
8670
|
+
{ name: "end", description: "End date (ISO 8601)" },
|
|
8671
|
+
{ name: "unmonitored", description: "Include unmonitored", type: "boolean" }
|
|
8672
|
+
],
|
|
8673
|
+
columns: ["id", "seriesTitle", "title", "seasonNumber", "episodeNumber", "airDateUtc"],
|
|
8674
|
+
run: async (c3, a2) => {
|
|
8675
|
+
const result = await c3.getCalendar(a2.start, a2.end, a2.unmonitored);
|
|
8676
|
+
const episodes = unwrapData2(result);
|
|
8677
|
+
return episodes.map((ep) => ({
|
|
8678
|
+
...ep,
|
|
8679
|
+
seriesTitle: ep.seriesTitle || ep.series?.title || "—"
|
|
8680
|
+
}));
|
|
7803
8681
|
}
|
|
8682
|
+
}
|
|
8683
|
+
]
|
|
8684
|
+
},
|
|
8685
|
+
{
|
|
8686
|
+
name: "notification",
|
|
8687
|
+
description: "Manage notifications",
|
|
8688
|
+
actions: [
|
|
8689
|
+
{
|
|
8690
|
+
name: "list",
|
|
8691
|
+
description: "List notification providers",
|
|
8692
|
+
columns: ["id", "name", "implementation"],
|
|
8693
|
+
run: (c3) => c3.getNotifications()
|
|
8694
|
+
},
|
|
8695
|
+
{
|
|
8696
|
+
name: "get",
|
|
8697
|
+
description: "Get a notification by ID",
|
|
8698
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
8699
|
+
run: (c3, a2) => c3.getNotification(a2.id)
|
|
8700
|
+
},
|
|
8701
|
+
{
|
|
8702
|
+
name: "add",
|
|
8703
|
+
description: "Add a notification from JSON file or stdin",
|
|
8704
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
8705
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput2(a2.file))
|
|
7804
8706
|
},
|
|
7805
8707
|
{
|
|
7806
8708
|
name: "edit",
|
|
7807
|
-
description: "Edit a
|
|
8709
|
+
description: "Edit a notification (merges JSON with existing)",
|
|
7808
8710
|
args: [
|
|
7809
|
-
{ name: "id", description: "
|
|
7810
|
-
{ name: "
|
|
7811
|
-
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
7812
|
-
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
8711
|
+
{ name: "id", description: "Notification ID", required: true, type: "number" },
|
|
8712
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
7813
8713
|
],
|
|
7814
8714
|
run: async (c3, a2) => {
|
|
7815
|
-
const
|
|
7816
|
-
|
|
7817
|
-
const updates = { ...series };
|
|
7818
|
-
if (a2.monitored !== undefined)
|
|
7819
|
-
updates.monitored = a2.monitored === "true";
|
|
7820
|
-
if (a2["quality-profile-id"] !== undefined)
|
|
7821
|
-
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
7822
|
-
if (a2.tags !== undefined)
|
|
7823
|
-
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
7824
|
-
return c3.updateSeries(String(a2.id), updates);
|
|
8715
|
+
const existing = unwrapData2(await c3.getNotification(a2.id));
|
|
8716
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput2(a2.file) });
|
|
7825
8717
|
}
|
|
7826
8718
|
},
|
|
7827
8719
|
{
|
|
7828
|
-
name: "
|
|
7829
|
-
description: "
|
|
7830
|
-
args: [{ name: "id", description: "
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
{
|
|
7834
|
-
name: "manual-search",
|
|
7835
|
-
description: "Trigger a manual search for releases",
|
|
7836
|
-
args: [{ name: "id", description: "Series ID", required: true, type: "number" }],
|
|
7837
|
-
run: (c3, a2) => c3.runCommand({ name: "SeriesSearch", seriesId: a2.id })
|
|
8720
|
+
name: "delete",
|
|
8721
|
+
description: "Delete a notification",
|
|
8722
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
8723
|
+
confirmMessage: "Are you sure you want to delete this notification?",
|
|
8724
|
+
run: (c3, a2) => c3.deleteNotification(a2.id)
|
|
7838
8725
|
},
|
|
7839
8726
|
{
|
|
7840
|
-
name: "
|
|
7841
|
-
description: "
|
|
7842
|
-
|
|
7843
|
-
confirmMessage: "Are you sure you want to delete this series?",
|
|
7844
|
-
run: (c3, a2) => c3.deleteSeries(a2.id)
|
|
8727
|
+
name: "test",
|
|
8728
|
+
description: "Test all notifications",
|
|
8729
|
+
run: (c3) => c3.testAllNotifications()
|
|
7845
8730
|
}
|
|
7846
8731
|
]
|
|
7847
8732
|
},
|
|
7848
8733
|
{
|
|
7849
|
-
name: "
|
|
7850
|
-
description: "Manage
|
|
8734
|
+
name: "downloadclient",
|
|
8735
|
+
description: "Manage download clients",
|
|
7851
8736
|
actions: [
|
|
7852
8737
|
{
|
|
7853
8738
|
name: "list",
|
|
7854
|
-
description: "List
|
|
7855
|
-
columns: ["id", "
|
|
7856
|
-
run: (c3) => c3.
|
|
8739
|
+
description: "List download clients",
|
|
8740
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
8741
|
+
run: (c3) => c3.getDownloadClients()
|
|
7857
8742
|
},
|
|
7858
8743
|
{
|
|
7859
8744
|
name: "get",
|
|
7860
|
-
description: "Get
|
|
7861
|
-
args: [{ name: "id", description: "
|
|
7862
|
-
run: (c3, a2) => c3.
|
|
8745
|
+
description: "Get a download client by ID",
|
|
8746
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
8747
|
+
run: (c3, a2) => c3.getDownloadClient(a2.id)
|
|
8748
|
+
},
|
|
8749
|
+
{
|
|
8750
|
+
name: "add",
|
|
8751
|
+
description: "Add a download client from JSON file or stdin",
|
|
8752
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
8753
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput2(a2.file))
|
|
8754
|
+
},
|
|
8755
|
+
{
|
|
8756
|
+
name: "edit",
|
|
8757
|
+
description: "Edit a download client (merges JSON with existing)",
|
|
8758
|
+
args: [
|
|
8759
|
+
{ name: "id", description: "Download client ID", required: true, type: "number" },
|
|
8760
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
8761
|
+
],
|
|
8762
|
+
run: async (c3, a2) => {
|
|
8763
|
+
const existing = unwrapData2(await c3.getDownloadClient(a2.id));
|
|
8764
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput2(a2.file) });
|
|
8765
|
+
}
|
|
8766
|
+
},
|
|
8767
|
+
{
|
|
8768
|
+
name: "delete",
|
|
8769
|
+
description: "Delete a download client",
|
|
8770
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
8771
|
+
confirmMessage: "Are you sure you want to delete this download client?",
|
|
8772
|
+
run: (c3, a2) => c3.deleteDownloadClient(a2.id)
|
|
8773
|
+
},
|
|
8774
|
+
{
|
|
8775
|
+
name: "test",
|
|
8776
|
+
description: "Test all download clients",
|
|
8777
|
+
run: (c3) => c3.testAllDownloadClients()
|
|
7863
8778
|
}
|
|
7864
8779
|
]
|
|
7865
8780
|
},
|
|
7866
8781
|
{
|
|
7867
|
-
name: "
|
|
7868
|
-
description: "Manage
|
|
8782
|
+
name: "blocklist",
|
|
8783
|
+
description: "Manage blocked releases",
|
|
7869
8784
|
actions: [
|
|
7870
8785
|
{
|
|
7871
8786
|
name: "list",
|
|
7872
|
-
description: "List
|
|
7873
|
-
columns: ["id", "
|
|
7874
|
-
run: (c3) => c3.
|
|
8787
|
+
description: "List blocked releases",
|
|
8788
|
+
columns: ["id", "sourceTitle", "date"],
|
|
8789
|
+
run: (c3) => c3.getBlocklist()
|
|
8790
|
+
},
|
|
8791
|
+
{
|
|
8792
|
+
name: "delete",
|
|
8793
|
+
description: "Remove a release from the blocklist",
|
|
8794
|
+
args: [{ name: "id", description: "Blocklist item ID", required: true, type: "number" }],
|
|
8795
|
+
confirmMessage: "Are you sure you want to remove this blocklist entry?",
|
|
8796
|
+
run: (c3, a2) => c3.removeBlocklistItem(a2.id)
|
|
7875
8797
|
}
|
|
7876
8798
|
]
|
|
7877
8799
|
},
|
|
7878
8800
|
{
|
|
7879
|
-
name: "
|
|
7880
|
-
description: "
|
|
8801
|
+
name: "wanted",
|
|
8802
|
+
description: "View missing and cutoff unmet episodes",
|
|
7881
8803
|
actions: [
|
|
7882
8804
|
{
|
|
7883
|
-
name: "
|
|
7884
|
-
description: "List
|
|
7885
|
-
columns: ["id", "
|
|
7886
|
-
run: (c3) => c3.
|
|
8805
|
+
name: "missing",
|
|
8806
|
+
description: "List episodes with missing files",
|
|
8807
|
+
columns: ["id", "title", "seasonNumber", "episodeNumber", "airDateUtc"],
|
|
8808
|
+
run: (c3) => c3.getWantedMissing()
|
|
8809
|
+
},
|
|
8810
|
+
{
|
|
8811
|
+
name: "cutoff",
|
|
8812
|
+
description: "List episodes below quality cutoff",
|
|
8813
|
+
columns: ["id", "title", "seasonNumber", "episodeNumber", "airDateUtc"],
|
|
8814
|
+
run: (c3) => c3.getWantedCutoff()
|
|
7887
8815
|
}
|
|
7888
8816
|
]
|
|
7889
8817
|
},
|
|
7890
8818
|
{
|
|
7891
|
-
name: "
|
|
7892
|
-
description: "Manage
|
|
8819
|
+
name: "importlist",
|
|
8820
|
+
description: "Manage import lists",
|
|
7893
8821
|
actions: [
|
|
7894
8822
|
{
|
|
7895
8823
|
name: "list",
|
|
7896
|
-
description: "List
|
|
7897
|
-
columns: ["id", "
|
|
7898
|
-
run: (c3) => c3.
|
|
8824
|
+
description: "List import lists",
|
|
8825
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
8826
|
+
run: (c3) => c3.getImportLists()
|
|
8827
|
+
},
|
|
8828
|
+
{
|
|
8829
|
+
name: "get",
|
|
8830
|
+
description: "Get an import list by ID",
|
|
8831
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
8832
|
+
run: (c3, a2) => c3.getImportList(a2.id)
|
|
8833
|
+
},
|
|
8834
|
+
{
|
|
8835
|
+
name: "add",
|
|
8836
|
+
description: "Add an import list from JSON file or stdin",
|
|
8837
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
8838
|
+
run: async (c3, a2) => c3.addImportList(readJsonInput2(a2.file))
|
|
8839
|
+
},
|
|
8840
|
+
{
|
|
8841
|
+
name: "edit",
|
|
8842
|
+
description: "Edit an import list (merges JSON with existing)",
|
|
8843
|
+
args: [
|
|
8844
|
+
{ name: "id", description: "Import list ID", required: true, type: "number" },
|
|
8845
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
8846
|
+
],
|
|
8847
|
+
run: async (c3, a2) => {
|
|
8848
|
+
const existing = unwrapData2(await c3.getImportList(a2.id));
|
|
8849
|
+
return c3.updateImportList(a2.id, { ...existing, ...readJsonInput2(a2.file) });
|
|
8850
|
+
}
|
|
8851
|
+
},
|
|
8852
|
+
{
|
|
8853
|
+
name: "delete",
|
|
8854
|
+
description: "Delete an import list",
|
|
8855
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
8856
|
+
confirmMessage: "Are you sure you want to delete this import list?",
|
|
8857
|
+
run: (c3, a2) => c3.deleteImportList(a2.id)
|
|
7899
8858
|
}
|
|
7900
8859
|
]
|
|
7901
8860
|
},
|
|
@@ -9649,6 +10608,14 @@ var getApiV1Album = (options) => (options?.client ?? client3).get({
|
|
|
9649
10608
|
}],
|
|
9650
10609
|
url: "/api/v1/queue/status",
|
|
9651
10610
|
...options
|
|
10611
|
+
}), deleteApiV1RootfolderById = (options) => (options.client ?? client3).delete({
|
|
10612
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
10613
|
+
in: "query",
|
|
10614
|
+
name: "apikey",
|
|
10615
|
+
type: "apiKey"
|
|
10616
|
+
}],
|
|
10617
|
+
url: "/api/v1/rootfolder/{id}",
|
|
10618
|
+
...options
|
|
9652
10619
|
}), getApiV1Rootfolder = (options) => (options?.client ?? client3).get({
|
|
9653
10620
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
9654
10621
|
in: "query",
|
|
@@ -9854,6 +10821,9 @@ class LidarrClient {
|
|
|
9854
10821
|
body: { path }
|
|
9855
10822
|
});
|
|
9856
10823
|
}
|
|
10824
|
+
async deleteRootFolder(id) {
|
|
10825
|
+
return deleteApiV1RootfolderById({ path: { id } });
|
|
10826
|
+
}
|
|
9857
10827
|
async addAlbum(album) {
|
|
9858
10828
|
return postApiV1Album({ body: album });
|
|
9859
10829
|
}
|
|
@@ -10409,6 +11379,28 @@ var init_lidarr3 = __esm(() => {
|
|
|
10409
11379
|
name: "tag",
|
|
10410
11380
|
description: "Manage tags",
|
|
10411
11381
|
actions: [
|
|
11382
|
+
{
|
|
11383
|
+
name: "create",
|
|
11384
|
+
description: "Create a tag",
|
|
11385
|
+
args: [{ name: "label", description: "Tag label", required: true }],
|
|
11386
|
+
run: (c3, a2) => c3.addTag({ label: a2.label })
|
|
11387
|
+
},
|
|
11388
|
+
{
|
|
11389
|
+
name: "delete",
|
|
11390
|
+
description: "Delete a tag",
|
|
11391
|
+
args: [{ name: "id", description: "Tag ID", required: true, type: "number" }],
|
|
11392
|
+
confirmMessage: "Are you sure you want to delete this tag?",
|
|
11393
|
+
run: async (c3, a2) => {
|
|
11394
|
+
const tagResult = await c3.getTag(a2.id);
|
|
11395
|
+
if (tagResult?.error)
|
|
11396
|
+
return tagResult;
|
|
11397
|
+
const tag = tagResult?.data ?? tagResult;
|
|
11398
|
+
const deleteResult = await c3.deleteTag(a2.id);
|
|
11399
|
+
if (deleteResult?.error)
|
|
11400
|
+
return deleteResult;
|
|
11401
|
+
return { message: `Deleted tag: ${tag.label} (ID: ${tag.id})` };
|
|
11402
|
+
}
|
|
11403
|
+
},
|
|
10412
11404
|
{
|
|
10413
11405
|
name: "list",
|
|
10414
11406
|
description: "List all tags",
|
|
@@ -10426,6 +11418,19 @@ var init_lidarr3 = __esm(() => {
|
|
|
10426
11418
|
description: "List root folders",
|
|
10427
11419
|
columns: ["id", "path", "freeSpace"],
|
|
10428
11420
|
run: (c3) => c3.getRootFolders()
|
|
11421
|
+
},
|
|
11422
|
+
{
|
|
11423
|
+
name: "add",
|
|
11424
|
+
description: "Add a root folder",
|
|
11425
|
+
args: [{ name: "path", description: "Folder path", required: true }],
|
|
11426
|
+
run: (c3, a2) => c3.addRootFolder(a2.path)
|
|
11427
|
+
},
|
|
11428
|
+
{
|
|
11429
|
+
name: "delete",
|
|
11430
|
+
description: "Delete a root folder",
|
|
11431
|
+
args: [{ name: "id", description: "Root folder ID", required: true, type: "number" }],
|
|
11432
|
+
confirmMessage: "Are you sure you want to delete this root folder?",
|
|
11433
|
+
run: (c3, a2) => c3.deleteRootFolder(a2.id)
|
|
10429
11434
|
}
|
|
10430
11435
|
]
|
|
10431
11436
|
},
|
|
@@ -12163,6 +13168,14 @@ var getApiV1Author = (options) => (options?.client ?? client4).get({
|
|
|
12163
13168
|
"Content-Type": "application/json",
|
|
12164
13169
|
...options?.headers
|
|
12165
13170
|
}
|
|
13171
|
+
}), deleteApiV1RootfolderById2 = (options) => (options.client ?? client4).delete({
|
|
13172
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
13173
|
+
in: "query",
|
|
13174
|
+
name: "apikey",
|
|
13175
|
+
type: "apiKey"
|
|
13176
|
+
}],
|
|
13177
|
+
url: "/api/v1/rootfolder/{id}",
|
|
13178
|
+
...options
|
|
12166
13179
|
}), getApiV1SystemStatus2 = (options) => (options?.client ?? client4).get({
|
|
12167
13180
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12168
13181
|
in: "query",
|
|
@@ -12348,6 +13361,9 @@ class ReadarrClient {
|
|
|
12348
13361
|
body: { path }
|
|
12349
13362
|
});
|
|
12350
13363
|
}
|
|
13364
|
+
async deleteRootFolder(id) {
|
|
13365
|
+
return deleteApiV1RootfolderById2({ path: { id } });
|
|
13366
|
+
}
|
|
12351
13367
|
async getHostConfig() {
|
|
12352
13368
|
return getApiV1ConfigHost2();
|
|
12353
13369
|
}
|
|
@@ -12880,6 +13896,28 @@ var init_readarr3 = __esm(() => {
|
|
|
12880
13896
|
name: "tag",
|
|
12881
13897
|
description: "Manage tags",
|
|
12882
13898
|
actions: [
|
|
13899
|
+
{
|
|
13900
|
+
name: "create",
|
|
13901
|
+
description: "Create a tag",
|
|
13902
|
+
args: [{ name: "label", description: "Tag label", required: true }],
|
|
13903
|
+
run: (c3, a2) => c3.addTag({ label: a2.label })
|
|
13904
|
+
},
|
|
13905
|
+
{
|
|
13906
|
+
name: "delete",
|
|
13907
|
+
description: "Delete a tag",
|
|
13908
|
+
args: [{ name: "id", description: "Tag ID", required: true, type: "number" }],
|
|
13909
|
+
confirmMessage: "Are you sure you want to delete this tag?",
|
|
13910
|
+
run: async (c3, a2) => {
|
|
13911
|
+
const tagResult = await c3.getTag(a2.id);
|
|
13912
|
+
if (tagResult?.error)
|
|
13913
|
+
return tagResult;
|
|
13914
|
+
const tag = tagResult?.data ?? tagResult;
|
|
13915
|
+
const deleteResult = await c3.deleteTag(a2.id);
|
|
13916
|
+
if (deleteResult?.error)
|
|
13917
|
+
return deleteResult;
|
|
13918
|
+
return { message: `Deleted tag: ${tag.label} (ID: ${tag.id})` };
|
|
13919
|
+
}
|
|
13920
|
+
},
|
|
12883
13921
|
{
|
|
12884
13922
|
name: "list",
|
|
12885
13923
|
description: "List all tags",
|
|
@@ -12897,6 +13935,19 @@ var init_readarr3 = __esm(() => {
|
|
|
12897
13935
|
description: "List root folders",
|
|
12898
13936
|
columns: ["id", "path", "freeSpace"],
|
|
12899
13937
|
run: (c3) => c3.getRootFolders()
|
|
13938
|
+
},
|
|
13939
|
+
{
|
|
13940
|
+
name: "add",
|
|
13941
|
+
description: "Add a root folder",
|
|
13942
|
+
args: [{ name: "path", description: "Folder path", required: true }],
|
|
13943
|
+
run: (c3, a2) => c3.addRootFolder(a2.path)
|
|
13944
|
+
},
|
|
13945
|
+
{
|
|
13946
|
+
name: "delete",
|
|
13947
|
+
description: "Delete a root folder",
|
|
13948
|
+
args: [{ name: "id", description: "Root folder ID", required: true, type: "number" }],
|
|
13949
|
+
confirmMessage: "Are you sure you want to delete this root folder?",
|
|
13950
|
+
run: (c3, a2) => c3.deleteRootFolder(a2.id)
|
|
12900
13951
|
}
|
|
12901
13952
|
]
|
|
12902
13953
|
},
|
|
@@ -14066,6 +15117,14 @@ var deleteApiV1ApplicationsById = (options) => (options.client ?? client5).delet
|
|
|
14066
15117
|
}],
|
|
14067
15118
|
url: "/api/v1/indexer/testall",
|
|
14068
15119
|
...options
|
|
15120
|
+
}), getApiV1Indexerstats = (options) => (options?.client ?? client5).get({
|
|
15121
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
15122
|
+
in: "query",
|
|
15123
|
+
name: "apikey",
|
|
15124
|
+
type: "apiKey"
|
|
15125
|
+
}],
|
|
15126
|
+
url: "/api/v1/indexerstats",
|
|
15127
|
+
...options
|
|
14069
15128
|
}), getApiV1Log3 = (options) => (options?.client ?? client5).get({
|
|
14070
15129
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
14071
15130
|
in: "query",
|
|
@@ -14336,6 +15395,9 @@ class ProwlarrClient {
|
|
|
14336
15395
|
async deleteIndexer(id) {
|
|
14337
15396
|
return deleteApiV1IndexerById3({ path: { id } });
|
|
14338
15397
|
}
|
|
15398
|
+
async getIndexerStats() {
|
|
15399
|
+
return getApiV1Indexerstats();
|
|
15400
|
+
}
|
|
14339
15401
|
async getDownloadClients() {
|
|
14340
15402
|
return getApiV1Downloadclient3();
|
|
14341
15403
|
}
|
|
@@ -14530,9 +15592,18 @@ var exports_prowlarr3 = {};
|
|
|
14530
15592
|
__export(exports_prowlarr3, {
|
|
14531
15593
|
prowlarr: () => prowlarr
|
|
14532
15594
|
});
|
|
15595
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
15596
|
+
function unwrapData3(result) {
|
|
15597
|
+
return result?.data ?? result;
|
|
15598
|
+
}
|
|
15599
|
+
function readJsonInput3(filePath) {
|
|
15600
|
+
const raw = filePath === "-" ? readFileSync4(0, "utf-8") : readFileSync4(filePath, "utf-8");
|
|
15601
|
+
return JSON.parse(raw);
|
|
15602
|
+
}
|
|
14533
15603
|
var resources5, prowlarr;
|
|
14534
15604
|
var init_prowlarr3 = __esm(() => {
|
|
14535
15605
|
init_prowlarr2();
|
|
15606
|
+
init_prompt2();
|
|
14536
15607
|
init_service();
|
|
14537
15608
|
resources5 = [
|
|
14538
15609
|
{
|
|
@@ -14551,12 +15622,39 @@ var init_prowlarr3 = __esm(() => {
|
|
|
14551
15622
|
args: [{ name: "id", description: "Indexer ID", required: true, type: "number" }],
|
|
14552
15623
|
run: (c3, a2) => c3.getIndexer(a2.id)
|
|
14553
15624
|
},
|
|
15625
|
+
{
|
|
15626
|
+
name: "add",
|
|
15627
|
+
description: "Add an indexer from JSON file or stdin",
|
|
15628
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15629
|
+
run: async (c3, a2) => {
|
|
15630
|
+
const body = readJsonInput3(a2.file);
|
|
15631
|
+
return c3.addIndexer(body);
|
|
15632
|
+
}
|
|
15633
|
+
},
|
|
15634
|
+
{
|
|
15635
|
+
name: "edit",
|
|
15636
|
+
description: "Edit an indexer (merges JSON with existing)",
|
|
15637
|
+
args: [
|
|
15638
|
+
{ name: "id", description: "Indexer ID", required: true, type: "number" },
|
|
15639
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15640
|
+
],
|
|
15641
|
+
run: async (c3, a2) => {
|
|
15642
|
+
const existing = unwrapData3(await c3.getIndexer(a2.id));
|
|
15643
|
+
const updates = readJsonInput3(a2.file);
|
|
15644
|
+
return c3.updateIndexer(a2.id, { ...existing, ...updates });
|
|
15645
|
+
}
|
|
15646
|
+
},
|
|
14554
15647
|
{
|
|
14555
15648
|
name: "delete",
|
|
14556
15649
|
description: "Delete an indexer",
|
|
14557
15650
|
args: [{ name: "id", description: "Indexer ID", required: true, type: "number" }],
|
|
14558
15651
|
confirmMessage: "Are you sure you want to delete this indexer?",
|
|
14559
15652
|
run: (c3, a2) => c3.deleteIndexer(a2.id)
|
|
15653
|
+
},
|
|
15654
|
+
{
|
|
15655
|
+
name: "test",
|
|
15656
|
+
description: "Test all indexers",
|
|
15657
|
+
run: (c3) => c3.testAllIndexers()
|
|
14560
15658
|
}
|
|
14561
15659
|
]
|
|
14562
15660
|
},
|
|
@@ -14567,9 +15665,12 @@ var init_prowlarr3 = __esm(() => {
|
|
|
14567
15665
|
{
|
|
14568
15666
|
name: "run",
|
|
14569
15667
|
description: "Search across indexers",
|
|
14570
|
-
args: [
|
|
15668
|
+
args: [
|
|
15669
|
+
{ name: "term", description: "Search term" },
|
|
15670
|
+
{ name: "query", description: "Search query" }
|
|
15671
|
+
],
|
|
14571
15672
|
columns: ["indexer", "title", "size", "seeders"],
|
|
14572
|
-
run: (c3, a2) => c3.search(a2.query)
|
|
15673
|
+
run: async (c3, a2) => c3.search(await promptIfMissing(a2.term ?? a2.query, "Search term:"))
|
|
14573
15674
|
}
|
|
14574
15675
|
]
|
|
14575
15676
|
},
|
|
@@ -14588,6 +15689,40 @@ var init_prowlarr3 = __esm(() => {
|
|
|
14588
15689
|
description: "Get an application by ID",
|
|
14589
15690
|
args: [{ name: "id", description: "Application ID", required: true, type: "number" }],
|
|
14590
15691
|
run: (c3, a2) => c3.getApplication(a2.id)
|
|
15692
|
+
},
|
|
15693
|
+
{
|
|
15694
|
+
name: "add",
|
|
15695
|
+
description: "Add an application from JSON file or stdin",
|
|
15696
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15697
|
+
run: async (c3, a2) => {
|
|
15698
|
+
const body = readJsonInput3(a2.file);
|
|
15699
|
+
return c3.addApplication(body);
|
|
15700
|
+
}
|
|
15701
|
+
},
|
|
15702
|
+
{
|
|
15703
|
+
name: "edit",
|
|
15704
|
+
description: "Edit an application (merges JSON with existing)",
|
|
15705
|
+
args: [
|
|
15706
|
+
{ name: "id", description: "Application ID", required: true, type: "number" },
|
|
15707
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15708
|
+
],
|
|
15709
|
+
run: async (c3, a2) => {
|
|
15710
|
+
const existing = unwrapData3(await c3.getApplication(a2.id));
|
|
15711
|
+
const updates = readJsonInput3(a2.file);
|
|
15712
|
+
return c3.updateApplication(a2.id, { ...existing, ...updates });
|
|
15713
|
+
}
|
|
15714
|
+
},
|
|
15715
|
+
{
|
|
15716
|
+
name: "delete",
|
|
15717
|
+
description: "Delete an application",
|
|
15718
|
+
args: [{ name: "id", description: "Application ID", required: true, type: "number" }],
|
|
15719
|
+
confirmMessage: "Are you sure you want to delete this application?",
|
|
15720
|
+
run: (c3, a2) => c3.deleteApplication(a2.id)
|
|
15721
|
+
},
|
|
15722
|
+
{
|
|
15723
|
+
name: "sync",
|
|
15724
|
+
description: "Trigger app indexer sync",
|
|
15725
|
+
run: (c3) => c3.runCommand({ name: "AppIndexerMapSync" })
|
|
14591
15726
|
}
|
|
14592
15727
|
]
|
|
14593
15728
|
},
|
|
@@ -14595,6 +15730,28 @@ var init_prowlarr3 = __esm(() => {
|
|
|
14595
15730
|
name: "tag",
|
|
14596
15731
|
description: "Manage tags",
|
|
14597
15732
|
actions: [
|
|
15733
|
+
{
|
|
15734
|
+
name: "create",
|
|
15735
|
+
description: "Create a tag",
|
|
15736
|
+
args: [{ name: "label", description: "Tag label", required: true }],
|
|
15737
|
+
run: (c3, a2) => c3.addTag({ label: a2.label })
|
|
15738
|
+
},
|
|
15739
|
+
{
|
|
15740
|
+
name: "delete",
|
|
15741
|
+
description: "Delete a tag",
|
|
15742
|
+
args: [{ name: "id", description: "Tag ID", required: true, type: "number" }],
|
|
15743
|
+
confirmMessage: "Are you sure you want to delete this tag?",
|
|
15744
|
+
run: async (c3, a2) => {
|
|
15745
|
+
const tagResult = await c3.getTag(a2.id);
|
|
15746
|
+
if (tagResult?.error)
|
|
15747
|
+
return tagResult;
|
|
15748
|
+
const tag = tagResult?.data ?? tagResult;
|
|
15749
|
+
const deleteResult = await c3.deleteTag(a2.id);
|
|
15750
|
+
if (deleteResult?.error)
|
|
15751
|
+
return deleteResult;
|
|
15752
|
+
return { message: `Deleted tag: ${tag.label} (ID: ${tag.id})` };
|
|
15753
|
+
}
|
|
15754
|
+
},
|
|
14598
15755
|
{
|
|
14599
15756
|
name: "list",
|
|
14600
15757
|
description: "List all tags",
|
|
@@ -14603,6 +15760,123 @@ var init_prowlarr3 = __esm(() => {
|
|
|
14603
15760
|
}
|
|
14604
15761
|
]
|
|
14605
15762
|
},
|
|
15763
|
+
{
|
|
15764
|
+
name: "indexerstats",
|
|
15765
|
+
description: "View indexer statistics",
|
|
15766
|
+
actions: [
|
|
15767
|
+
{
|
|
15768
|
+
name: "list",
|
|
15769
|
+
description: "Get indexer performance statistics",
|
|
15770
|
+
columns: [
|
|
15771
|
+
"indexerName",
|
|
15772
|
+
"numberOfQueries",
|
|
15773
|
+
"numberOfGrabs",
|
|
15774
|
+
"numberOfFailures",
|
|
15775
|
+
"averageResponseTime"
|
|
15776
|
+
],
|
|
15777
|
+
run: async (c3) => {
|
|
15778
|
+
const result = unwrapData3(await c3.getIndexerStats());
|
|
15779
|
+
return result?.indexers ?? result;
|
|
15780
|
+
}
|
|
15781
|
+
}
|
|
15782
|
+
]
|
|
15783
|
+
},
|
|
15784
|
+
{
|
|
15785
|
+
name: "notification",
|
|
15786
|
+
description: "Manage notifications",
|
|
15787
|
+
actions: [
|
|
15788
|
+
{
|
|
15789
|
+
name: "list",
|
|
15790
|
+
description: "List notification providers",
|
|
15791
|
+
columns: ["id", "name", "implementation"],
|
|
15792
|
+
run: (c3) => c3.getNotifications()
|
|
15793
|
+
},
|
|
15794
|
+
{
|
|
15795
|
+
name: "get",
|
|
15796
|
+
description: "Get a notification by ID",
|
|
15797
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
15798
|
+
run: (c3, a2) => c3.getNotification(a2.id)
|
|
15799
|
+
},
|
|
15800
|
+
{
|
|
15801
|
+
name: "add",
|
|
15802
|
+
description: "Add a notification from JSON file or stdin",
|
|
15803
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15804
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput3(a2.file))
|
|
15805
|
+
},
|
|
15806
|
+
{
|
|
15807
|
+
name: "edit",
|
|
15808
|
+
description: "Edit a notification (merges JSON with existing)",
|
|
15809
|
+
args: [
|
|
15810
|
+
{ name: "id", description: "Notification ID", required: true, type: "number" },
|
|
15811
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15812
|
+
],
|
|
15813
|
+
run: async (c3, a2) => {
|
|
15814
|
+
const existing = unwrapData3(await c3.getNotification(a2.id));
|
|
15815
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput3(a2.file) });
|
|
15816
|
+
}
|
|
15817
|
+
},
|
|
15818
|
+
{
|
|
15819
|
+
name: "delete",
|
|
15820
|
+
description: "Delete a notification",
|
|
15821
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
15822
|
+
confirmMessage: "Are you sure you want to delete this notification?",
|
|
15823
|
+
run: (c3, a2) => c3.deleteNotification(a2.id)
|
|
15824
|
+
},
|
|
15825
|
+
{
|
|
15826
|
+
name: "test",
|
|
15827
|
+
description: "Test all notifications",
|
|
15828
|
+
run: (c3) => c3.testAllNotifications()
|
|
15829
|
+
}
|
|
15830
|
+
]
|
|
15831
|
+
},
|
|
15832
|
+
{
|
|
15833
|
+
name: "downloadclient",
|
|
15834
|
+
description: "Manage download clients",
|
|
15835
|
+
actions: [
|
|
15836
|
+
{
|
|
15837
|
+
name: "list",
|
|
15838
|
+
description: "List download clients",
|
|
15839
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
15840
|
+
run: (c3) => c3.getDownloadClients()
|
|
15841
|
+
},
|
|
15842
|
+
{
|
|
15843
|
+
name: "get",
|
|
15844
|
+
description: "Get a download client by ID",
|
|
15845
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
15846
|
+
run: (c3, a2) => c3.getDownloadClient(a2.id)
|
|
15847
|
+
},
|
|
15848
|
+
{
|
|
15849
|
+
name: "add",
|
|
15850
|
+
description: "Add a download client from JSON file or stdin",
|
|
15851
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15852
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput3(a2.file))
|
|
15853
|
+
},
|
|
15854
|
+
{
|
|
15855
|
+
name: "edit",
|
|
15856
|
+
description: "Edit a download client (merges JSON with existing)",
|
|
15857
|
+
args: [
|
|
15858
|
+
{ name: "id", description: "Download client ID", required: true, type: "number" },
|
|
15859
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15860
|
+
],
|
|
15861
|
+
run: async (c3, a2) => {
|
|
15862
|
+
const existing = unwrapData3(await c3.getDownloadClient(a2.id));
|
|
15863
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput3(a2.file) });
|
|
15864
|
+
}
|
|
15865
|
+
},
|
|
15866
|
+
{
|
|
15867
|
+
name: "delete",
|
|
15868
|
+
description: "Delete a download client",
|
|
15869
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
15870
|
+
confirmMessage: "Are you sure you want to delete this download client?",
|
|
15871
|
+
run: (c3, a2) => c3.deleteDownloadClient(a2.id)
|
|
15872
|
+
},
|
|
15873
|
+
{
|
|
15874
|
+
name: "test",
|
|
15875
|
+
description: "Test all download clients",
|
|
15876
|
+
run: (c3) => c3.testAllDownloadClients()
|
|
15877
|
+
}
|
|
15878
|
+
]
|
|
15879
|
+
},
|
|
14606
15880
|
{
|
|
14607
15881
|
name: "system",
|
|
14608
15882
|
description: "System information",
|
|
@@ -16721,8 +17995,8 @@ var init_completions = __esm(() => {
|
|
|
16721
17995
|
|
|
16722
17996
|
// src/cli/index.ts
|
|
16723
17997
|
init_dist();
|
|
16724
|
-
import { readFileSync as
|
|
16725
|
-
var { version } = JSON.parse(
|
|
17998
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
17999
|
+
var { version } = JSON.parse(readFileSync5(new URL("../../package.json", import.meta.url), "utf-8"));
|
|
16726
18000
|
var main = defineCommand({
|
|
16727
18001
|
meta: {
|
|
16728
18002
|
name: "tsarr",
|