tsarr 2.4.1 → 2.4.2
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/readarr.d.ts.map +1 -1
- package/dist/cli/index.js +1016 -193
- package/dist/clients/bazarr.d.ts.map +1 -1
- package/dist/clients/bazarr.js +10 -2
- package/dist/clients/lidarr.d.ts +26 -0
- package/dist/clients/lidarr.d.ts.map +1 -1
- package/dist/clients/lidarr.js +47 -0
- package/dist/clients/readarr.d.ts +46 -0
- package/dist/clients/readarr.d.ts.map +1 -1
- package/dist/clients/readarr.js +84 -0
- package/dist/clients/sonarr.d.ts.map +1 -1
- package/dist/clients/sonarr.js +1 -0
- package/dist/index.js +13 -13
- package/dist/tsarr-2.4.2.tgz +0 -0
- package/package.json +1 -1
- package/dist/tsarr-2.4.1.tgz +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -8089,6 +8089,7 @@ class SonarrClient {
|
|
|
8089
8089
|
query.end = endDate;
|
|
8090
8090
|
if (unmonitored !== undefined)
|
|
8091
8091
|
query.unmonitored = unmonitored;
|
|
8092
|
+
query.includeSeries = true;
|
|
8092
8093
|
return getApiV3Calendar2(Object.keys(query).length > 0 ? { query } : {});
|
|
8093
8094
|
}
|
|
8094
8095
|
async getCalendarFeed(pastDays, futureDays, tags) {
|
|
@@ -9968,6 +9969,14 @@ var getApiV1Album = (options) => (options?.client ?? client3).get({
|
|
|
9968
9969
|
}],
|
|
9969
9970
|
url: "/api/v1/customformat/schema",
|
|
9970
9971
|
...options
|
|
9972
|
+
}), getApiV1WantedCutoff = (options) => (options?.client ?? client3).get({
|
|
9973
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
9974
|
+
in: "query",
|
|
9975
|
+
name: "apikey",
|
|
9976
|
+
type: "apiKey"
|
|
9977
|
+
}],
|
|
9978
|
+
url: "/api/v1/wanted/cutoff",
|
|
9979
|
+
...options
|
|
9971
9980
|
}), getApiV1Diskspace = (options) => (options?.client ?? client3).get({
|
|
9972
9981
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
9973
9982
|
in: "query",
|
|
@@ -10376,6 +10385,14 @@ var getApiV1Album = (options) => (options?.client ?? client3).get({
|
|
|
10376
10385
|
}],
|
|
10377
10386
|
url: "/api/v1/config/metadataprovider",
|
|
10378
10387
|
...options
|
|
10388
|
+
}), getApiV1WantedMissing = (options) => (options?.client ?? client3).get({
|
|
10389
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
10390
|
+
in: "query",
|
|
10391
|
+
name: "apikey",
|
|
10392
|
+
type: "apiKey"
|
|
10393
|
+
}],
|
|
10394
|
+
url: "/api/v1/wanted/missing",
|
|
10395
|
+
...options
|
|
10379
10396
|
}), getApiV1ConfigNamingById = (options) => (options.client ?? client3).get({
|
|
10380
10397
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
10381
10398
|
in: "query",
|
|
@@ -10844,6 +10861,7 @@ class LidarrClient {
|
|
|
10844
10861
|
query.end = end;
|
|
10845
10862
|
if (unmonitored !== undefined)
|
|
10846
10863
|
query.unmonitored = unmonitored;
|
|
10864
|
+
query.includeArtist = true;
|
|
10847
10865
|
return getApiV1Calendar(Object.keys(query).length > 0 ? { query } : {});
|
|
10848
10866
|
}
|
|
10849
10867
|
async getCalendarFeed(pastDays, futureDays, tags) {
|
|
@@ -11201,6 +11219,34 @@ class LidarrClient {
|
|
|
11201
11219
|
async removeBlocklistItemsBulk(ids) {
|
|
11202
11220
|
return deleteApiV1BlocklistBulk({ body: { ids } });
|
|
11203
11221
|
}
|
|
11222
|
+
async getWantedMissing(page, pageSize, sortKey, sortDirection, monitored) {
|
|
11223
|
+
const query = { includeArtist: true };
|
|
11224
|
+
if (page !== undefined)
|
|
11225
|
+
query.page = page;
|
|
11226
|
+
if (pageSize !== undefined)
|
|
11227
|
+
query.pageSize = pageSize;
|
|
11228
|
+
if (sortKey)
|
|
11229
|
+
query.sortKey = sortKey;
|
|
11230
|
+
if (sortDirection)
|
|
11231
|
+
query.sortDirection = sortDirection;
|
|
11232
|
+
if (monitored !== undefined)
|
|
11233
|
+
query.monitored = monitored;
|
|
11234
|
+
return getApiV1WantedMissing(Object.keys(query).length > 0 ? { query } : {});
|
|
11235
|
+
}
|
|
11236
|
+
async getWantedCutoff(page, pageSize, sortKey, sortDirection, monitored) {
|
|
11237
|
+
const query = { includeArtist: true };
|
|
11238
|
+
if (page !== undefined)
|
|
11239
|
+
query.page = page;
|
|
11240
|
+
if (pageSize !== undefined)
|
|
11241
|
+
query.pageSize = pageSize;
|
|
11242
|
+
if (sortKey)
|
|
11243
|
+
query.sortKey = sortKey;
|
|
11244
|
+
if (sortDirection)
|
|
11245
|
+
query.sortDirection = sortDirection;
|
|
11246
|
+
if (monitored !== undefined)
|
|
11247
|
+
query.monitored = monitored;
|
|
11248
|
+
return getApiV1WantedCutoff(Object.keys(query).length > 0 ? { query } : {});
|
|
11249
|
+
}
|
|
11204
11250
|
updateConfig(newConfig) {
|
|
11205
11251
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
11206
11252
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
@@ -11222,6 +11268,38 @@ var exports_lidarr3 = {};
|
|
|
11222
11268
|
__export(exports_lidarr3, {
|
|
11223
11269
|
lidarr: () => lidarr
|
|
11224
11270
|
});
|
|
11271
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
11272
|
+
function unwrapData3(result) {
|
|
11273
|
+
return result?.data ?? result;
|
|
11274
|
+
}
|
|
11275
|
+
function formatAlbumListItem(album) {
|
|
11276
|
+
return {
|
|
11277
|
+
...album,
|
|
11278
|
+
artistName: album?.artistName ?? album?.artist?.artistName ?? "—"
|
|
11279
|
+
};
|
|
11280
|
+
}
|
|
11281
|
+
function formatQueueListItem(item) {
|
|
11282
|
+
return {
|
|
11283
|
+
...item,
|
|
11284
|
+
artistName: item?.artistName ?? item?.artist?.artistName ?? "—"
|
|
11285
|
+
};
|
|
11286
|
+
}
|
|
11287
|
+
function formatHistoryListItem(item) {
|
|
11288
|
+
return {
|
|
11289
|
+
...item,
|
|
11290
|
+
artistName: item?.artistName ?? item?.artist?.artistName ?? "—"
|
|
11291
|
+
};
|
|
11292
|
+
}
|
|
11293
|
+
function formatBlocklistItem(item) {
|
|
11294
|
+
return {
|
|
11295
|
+
...item,
|
|
11296
|
+
artistName: item?.artistName ?? item?.artist?.artistName ?? "—"
|
|
11297
|
+
};
|
|
11298
|
+
}
|
|
11299
|
+
function readJsonInput3(filePath) {
|
|
11300
|
+
const raw = filePath === "-" ? readFileSync4(0, "utf-8") : readFileSync4(filePath, "utf-8");
|
|
11301
|
+
return JSON.parse(raw);
|
|
11302
|
+
}
|
|
11225
11303
|
var resources3, lidarr;
|
|
11226
11304
|
var init_lidarr3 = __esm(() => {
|
|
11227
11305
|
init_lidarr2();
|
|
@@ -11257,31 +11335,28 @@ var init_lidarr3 = __esm(() => {
|
|
|
11257
11335
|
description: "Search and add an artist",
|
|
11258
11336
|
args: [{ name: "term", description: "Search term", required: true }],
|
|
11259
11337
|
run: async (c3, a2) => {
|
|
11260
|
-
const
|
|
11261
|
-
const results = searchResult?.data ?? searchResult;
|
|
11338
|
+
const results = unwrapData3(await c3.searchArtists(a2.term));
|
|
11262
11339
|
if (!Array.isArray(results) || results.length === 0) {
|
|
11263
11340
|
throw new Error("No artists found.");
|
|
11264
11341
|
}
|
|
11265
|
-
const artistId = await promptSelect("Select an artist:", results.map((
|
|
11266
|
-
label:
|
|
11267
|
-
value: String(
|
|
11342
|
+
const artistId = await promptSelect("Select an artist:", results.map((artist2) => ({
|
|
11343
|
+
label: artist2.artistName,
|
|
11344
|
+
value: String(artist2.foreignArtistId)
|
|
11268
11345
|
})));
|
|
11269
|
-
const artist = results.find((
|
|
11346
|
+
const artist = results.find((item) => String(item.foreignArtistId) === artistId);
|
|
11270
11347
|
if (!artist) {
|
|
11271
11348
|
throw new Error("Selected artist was not found in the search results.");
|
|
11272
11349
|
}
|
|
11273
|
-
const
|
|
11274
|
-
const profiles = profilesResult?.data ?? profilesResult;
|
|
11350
|
+
const profiles = unwrapData3(await c3.getQualityProfiles());
|
|
11275
11351
|
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
11276
11352
|
throw new Error("No quality profiles found. Configure one in Lidarr first.");
|
|
11277
11353
|
}
|
|
11278
|
-
const profileId = await promptSelect("Select quality profile:", profiles.map((
|
|
11279
|
-
const
|
|
11280
|
-
const folders = foldersResult?.data ?? foldersResult;
|
|
11354
|
+
const profileId = await promptSelect("Select quality profile:", profiles.map((profile) => ({ label: profile.name, value: String(profile.id) })));
|
|
11355
|
+
const folders = unwrapData3(await c3.getRootFolders());
|
|
11281
11356
|
if (!Array.isArray(folders) || folders.length === 0) {
|
|
11282
11357
|
throw new Error("No root folders found. Configure one in Lidarr first.");
|
|
11283
11358
|
}
|
|
11284
|
-
const rootFolderPath = await promptSelect("Select root folder:", folders.map((
|
|
11359
|
+
const rootFolderPath = await promptSelect("Select root folder:", folders.map((folder) => ({ label: folder.path, value: folder.path })));
|
|
11285
11360
|
const confirmed = await promptConfirm(`Add "${artist.artistName}"?`, !!a2.yes);
|
|
11286
11361
|
if (!confirmed)
|
|
11287
11362
|
throw new Error("Cancelled.");
|
|
@@ -11304,15 +11379,16 @@ var init_lidarr3 = __esm(() => {
|
|
|
11304
11379
|
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
11305
11380
|
],
|
|
11306
11381
|
run: async (c3, a2) => {
|
|
11307
|
-
const
|
|
11308
|
-
const artist = result?.data ?? result;
|
|
11382
|
+
const artist = unwrapData3(await c3.getArtist(a2.id));
|
|
11309
11383
|
const updates = { ...artist };
|
|
11310
11384
|
if (a2.monitored !== undefined)
|
|
11311
11385
|
updates.monitored = a2.monitored === "true";
|
|
11312
|
-
if (a2["quality-profile-id"] !== undefined)
|
|
11386
|
+
if (a2["quality-profile-id"] !== undefined) {
|
|
11313
11387
|
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
11314
|
-
|
|
11315
|
-
|
|
11388
|
+
}
|
|
11389
|
+
if (a2.tags !== undefined) {
|
|
11390
|
+
updates.tags = a2.tags.split(",").map((tag) => Number(tag.trim()));
|
|
11391
|
+
}
|
|
11316
11392
|
return c3.updateArtist(a2.id, updates);
|
|
11317
11393
|
}
|
|
11318
11394
|
},
|
|
@@ -11344,22 +11420,56 @@ var init_lidarr3 = __esm(() => {
|
|
|
11344
11420
|
{
|
|
11345
11421
|
name: "list",
|
|
11346
11422
|
description: "List all albums",
|
|
11347
|
-
columns: ["id", "
|
|
11348
|
-
run: (c3) =>
|
|
11423
|
+
columns: ["id", "artistName", "title", "monitored"],
|
|
11424
|
+
run: async (c3) => {
|
|
11425
|
+
const albums = unwrapData3(await c3.getAlbums());
|
|
11426
|
+
return albums.map(formatAlbumListItem);
|
|
11427
|
+
}
|
|
11349
11428
|
},
|
|
11350
11429
|
{
|
|
11351
11430
|
name: "get",
|
|
11352
11431
|
description: "Get an album by ID",
|
|
11353
11432
|
args: [{ name: "id", description: "Album ID", required: true, type: "number" }],
|
|
11354
|
-
run: (c3, a2) =>
|
|
11433
|
+
run: async (c3, a2) => {
|
|
11434
|
+
const album = unwrapData3(await c3.getAlbum(a2.id));
|
|
11435
|
+
return formatAlbumListItem(album);
|
|
11436
|
+
}
|
|
11355
11437
|
},
|
|
11356
11438
|
{
|
|
11357
11439
|
name: "search",
|
|
11358
11440
|
description: "Search for albums",
|
|
11359
11441
|
args: [{ name: "term", description: "Search term", required: true }],
|
|
11360
|
-
columns: ["foreignAlbumId", "title", "
|
|
11442
|
+
columns: ["foreignAlbumId", "artistName", "title", "monitored"],
|
|
11361
11443
|
idField: "foreignAlbumId",
|
|
11362
|
-
run: (c3, a2) =>
|
|
11444
|
+
run: async (c3, a2) => {
|
|
11445
|
+
const albums = unwrapData3(await c3.searchAlbums(a2.term));
|
|
11446
|
+
return albums.map(formatAlbumListItem);
|
|
11447
|
+
}
|
|
11448
|
+
},
|
|
11449
|
+
{
|
|
11450
|
+
name: "add",
|
|
11451
|
+
description: "Add an album from JSON file or stdin",
|
|
11452
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
11453
|
+
run: async (c3, a2) => c3.addAlbum(readJsonInput3(a2.file))
|
|
11454
|
+
},
|
|
11455
|
+
{
|
|
11456
|
+
name: "edit",
|
|
11457
|
+
description: "Edit an album (merges JSON with existing)",
|
|
11458
|
+
args: [
|
|
11459
|
+
{ name: "id", description: "Album ID", required: true, type: "number" },
|
|
11460
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
11461
|
+
],
|
|
11462
|
+
run: async (c3, a2) => {
|
|
11463
|
+
const existing = unwrapData3(await c3.getAlbum(a2.id));
|
|
11464
|
+
return c3.updateAlbum(a2.id, { ...existing, ...readJsonInput3(a2.file) });
|
|
11465
|
+
}
|
|
11466
|
+
},
|
|
11467
|
+
{
|
|
11468
|
+
name: "delete",
|
|
11469
|
+
description: "Delete an album",
|
|
11470
|
+
args: [{ name: "id", description: "Album ID", required: true, type: "number" }],
|
|
11471
|
+
confirmMessage: "Are you sure you want to delete this album?",
|
|
11472
|
+
run: (c3, a2) => c3.deleteAlbum(a2.id)
|
|
11363
11473
|
}
|
|
11364
11474
|
]
|
|
11365
11475
|
},
|
|
@@ -11372,6 +11482,12 @@ var init_lidarr3 = __esm(() => {
|
|
|
11372
11482
|
description: "List quality profiles",
|
|
11373
11483
|
columns: ["id", "name"],
|
|
11374
11484
|
run: (c3) => c3.getQualityProfiles()
|
|
11485
|
+
},
|
|
11486
|
+
{
|
|
11487
|
+
name: "get",
|
|
11488
|
+
description: "Get a quality profile by ID",
|
|
11489
|
+
args: [{ name: "id", description: "Profile ID", required: true, type: "number" }],
|
|
11490
|
+
run: (c3, a2) => c3.getQualityProfile(a2.id)
|
|
11375
11491
|
}
|
|
11376
11492
|
]
|
|
11377
11493
|
},
|
|
@@ -11394,7 +11510,7 @@ var init_lidarr3 = __esm(() => {
|
|
|
11394
11510
|
const tagResult = await c3.getTag(a2.id);
|
|
11395
11511
|
if (tagResult?.error)
|
|
11396
11512
|
return tagResult;
|
|
11397
|
-
const tag = tagResult
|
|
11513
|
+
const tag = unwrapData3(tagResult);
|
|
11398
11514
|
const deleteResult = await c3.deleteTag(a2.id);
|
|
11399
11515
|
if (deleteResult?.error)
|
|
11400
11516
|
return deleteResult;
|
|
@@ -11410,50 +11526,298 @@ var init_lidarr3 = __esm(() => {
|
|
|
11410
11526
|
]
|
|
11411
11527
|
},
|
|
11412
11528
|
{
|
|
11413
|
-
name: "
|
|
11414
|
-
description: "Manage
|
|
11529
|
+
name: "queue",
|
|
11530
|
+
description: "Manage download queue",
|
|
11415
11531
|
actions: [
|
|
11416
11532
|
{
|
|
11417
11533
|
name: "list",
|
|
11418
|
-
description: "List
|
|
11419
|
-
columns: ["id", "
|
|
11420
|
-
run: (c3) =>
|
|
11534
|
+
description: "List queue items",
|
|
11535
|
+
columns: ["id", "artistName", "title", "status", "sizeleft", "timeleft"],
|
|
11536
|
+
run: async (c3) => {
|
|
11537
|
+
const items = unwrapData3(await c3.getQueue());
|
|
11538
|
+
return items.map(formatQueueListItem);
|
|
11539
|
+
}
|
|
11540
|
+
},
|
|
11541
|
+
{
|
|
11542
|
+
name: "status",
|
|
11543
|
+
description: "Get queue status",
|
|
11544
|
+
run: (c3) => c3.getQueueStatus()
|
|
11545
|
+
},
|
|
11546
|
+
{
|
|
11547
|
+
name: "delete",
|
|
11548
|
+
description: "Remove an item from the queue",
|
|
11549
|
+
args: [
|
|
11550
|
+
{ name: "id", description: "Queue item ID", required: true, type: "number" },
|
|
11551
|
+
{ name: "blocklist", description: "Add to blocklist", type: "boolean" },
|
|
11552
|
+
{
|
|
11553
|
+
name: "remove-from-client",
|
|
11554
|
+
description: "Remove from download client",
|
|
11555
|
+
type: "boolean"
|
|
11556
|
+
}
|
|
11557
|
+
],
|
|
11558
|
+
confirmMessage: "Are you sure you want to remove this queue item?",
|
|
11559
|
+
run: (c3, a2) => c3.removeQueueItem(a2.id, a2["remove-from-client"], a2.blocklist)
|
|
11560
|
+
},
|
|
11561
|
+
{
|
|
11562
|
+
name: "grab",
|
|
11563
|
+
description: "Force download a queue item",
|
|
11564
|
+
args: [{ name: "id", description: "Queue item ID", required: true, type: "number" }],
|
|
11565
|
+
run: (c3, a2) => c3.grabQueueItem(a2.id)
|
|
11566
|
+
}
|
|
11567
|
+
]
|
|
11568
|
+
},
|
|
11569
|
+
{
|
|
11570
|
+
name: "history",
|
|
11571
|
+
description: "View history",
|
|
11572
|
+
actions: [
|
|
11573
|
+
{
|
|
11574
|
+
name: "list",
|
|
11575
|
+
description: "List recent history",
|
|
11576
|
+
args: [
|
|
11577
|
+
{ name: "since", description: "Start date (ISO 8601, e.g. 2024-01-01)" },
|
|
11578
|
+
{ name: "until", description: "End date (ISO 8601, e.g. 2024-12-31)" }
|
|
11579
|
+
],
|
|
11580
|
+
columns: ["id", "artistName", "sourceTitle", "eventType", "date"],
|
|
11581
|
+
run: async (c3, a2) => {
|
|
11582
|
+
const items = a2.since ? unwrapData3(await c3.getHistorySince(a2.since)) : unwrapData3(await c3.getHistory());
|
|
11583
|
+
const filtered = a2.until ? items.filter((item) => new Date(item.date) <= new Date(a2.until)) : items;
|
|
11584
|
+
return filtered.map(formatHistoryListItem);
|
|
11585
|
+
}
|
|
11586
|
+
}
|
|
11587
|
+
]
|
|
11588
|
+
},
|
|
11589
|
+
{
|
|
11590
|
+
name: "calendar",
|
|
11591
|
+
description: "View upcoming releases",
|
|
11592
|
+
actions: [
|
|
11593
|
+
{
|
|
11594
|
+
name: "list",
|
|
11595
|
+
description: "List upcoming album releases",
|
|
11596
|
+
args: [
|
|
11597
|
+
{ name: "start", description: "Start date (ISO 8601)" },
|
|
11598
|
+
{ name: "end", description: "End date (ISO 8601)" },
|
|
11599
|
+
{ name: "unmonitored", description: "Include unmonitored", type: "boolean" }
|
|
11600
|
+
],
|
|
11601
|
+
columns: ["id", "artistName", "title", "releaseDate"],
|
|
11602
|
+
run: async (c3, a2) => {
|
|
11603
|
+
const albums = unwrapData3(await c3.getCalendar(a2.start, a2.end, a2.unmonitored));
|
|
11604
|
+
return albums.map(formatAlbumListItem);
|
|
11605
|
+
}
|
|
11606
|
+
}
|
|
11607
|
+
]
|
|
11608
|
+
},
|
|
11609
|
+
{
|
|
11610
|
+
name: "notification",
|
|
11611
|
+
description: "Manage notifications",
|
|
11612
|
+
actions: [
|
|
11613
|
+
{
|
|
11614
|
+
name: "list",
|
|
11615
|
+
description: "List notification providers",
|
|
11616
|
+
columns: ["id", "name", "implementation"],
|
|
11617
|
+
run: (c3) => c3.getNotifications()
|
|
11618
|
+
},
|
|
11619
|
+
{
|
|
11620
|
+
name: "get",
|
|
11621
|
+
description: "Get a notification by ID",
|
|
11622
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
11623
|
+
run: (c3, a2) => c3.getNotification(a2.id)
|
|
11421
11624
|
},
|
|
11422
11625
|
{
|
|
11423
11626
|
name: "add",
|
|
11424
|
-
description: "Add a
|
|
11425
|
-
args: [{ name: "
|
|
11426
|
-
run: (c3, a2) => c3.
|
|
11627
|
+
description: "Add a notification from JSON file or stdin",
|
|
11628
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
11629
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput3(a2.file))
|
|
11630
|
+
},
|
|
11631
|
+
{
|
|
11632
|
+
name: "edit",
|
|
11633
|
+
description: "Edit a notification (merges JSON with existing)",
|
|
11634
|
+
args: [
|
|
11635
|
+
{ name: "id", description: "Notification ID", required: true, type: "number" },
|
|
11636
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
11637
|
+
],
|
|
11638
|
+
run: async (c3, a2) => {
|
|
11639
|
+
const existing = unwrapData3(await c3.getNotification(a2.id));
|
|
11640
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput3(a2.file) });
|
|
11641
|
+
}
|
|
11427
11642
|
},
|
|
11428
11643
|
{
|
|
11429
11644
|
name: "delete",
|
|
11430
|
-
description: "Delete a
|
|
11431
|
-
args: [{ name: "id", description: "
|
|
11432
|
-
confirmMessage: "Are you sure you want to delete this
|
|
11433
|
-
run: (c3, a2) => c3.
|
|
11645
|
+
description: "Delete a notification",
|
|
11646
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
11647
|
+
confirmMessage: "Are you sure you want to delete this notification?",
|
|
11648
|
+
run: (c3, a2) => c3.deleteNotification(a2.id)
|
|
11649
|
+
},
|
|
11650
|
+
{
|
|
11651
|
+
name: "test",
|
|
11652
|
+
description: "Test all notifications",
|
|
11653
|
+
run: (c3) => c3.testAllNotifications()
|
|
11434
11654
|
}
|
|
11435
11655
|
]
|
|
11436
11656
|
},
|
|
11437
11657
|
{
|
|
11438
|
-
name: "
|
|
11439
|
-
description: "
|
|
11658
|
+
name: "downloadclient",
|
|
11659
|
+
description: "Manage download clients",
|
|
11440
11660
|
actions: [
|
|
11441
11661
|
{
|
|
11442
|
-
name: "
|
|
11443
|
-
description: "
|
|
11444
|
-
|
|
11662
|
+
name: "list",
|
|
11663
|
+
description: "List download clients",
|
|
11664
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
11665
|
+
run: (c3) => c3.getDownloadClients()
|
|
11445
11666
|
},
|
|
11446
11667
|
{
|
|
11447
|
-
name: "
|
|
11448
|
-
description: "Get
|
|
11449
|
-
|
|
11450
|
-
run: (c3) => c3.
|
|
11668
|
+
name: "get",
|
|
11669
|
+
description: "Get a download client by ID",
|
|
11670
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
11671
|
+
run: (c3, a2) => c3.getDownloadClient(a2.id)
|
|
11672
|
+
},
|
|
11673
|
+
{
|
|
11674
|
+
name: "add",
|
|
11675
|
+
description: "Add a download client from JSON file or stdin",
|
|
11676
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
11677
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput3(a2.file))
|
|
11678
|
+
},
|
|
11679
|
+
{
|
|
11680
|
+
name: "edit",
|
|
11681
|
+
description: "Edit a download client (merges JSON with existing)",
|
|
11682
|
+
args: [
|
|
11683
|
+
{ name: "id", description: "Download client ID", required: true, type: "number" },
|
|
11684
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
11685
|
+
],
|
|
11686
|
+
run: async (c3, a2) => {
|
|
11687
|
+
const existing = unwrapData3(await c3.getDownloadClient(a2.id));
|
|
11688
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput3(a2.file) });
|
|
11689
|
+
}
|
|
11690
|
+
},
|
|
11691
|
+
{
|
|
11692
|
+
name: "delete",
|
|
11693
|
+
description: "Delete a download client",
|
|
11694
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
11695
|
+
confirmMessage: "Are you sure you want to delete this download client?",
|
|
11696
|
+
run: (c3, a2) => c3.deleteDownloadClient(a2.id)
|
|
11697
|
+
},
|
|
11698
|
+
{
|
|
11699
|
+
name: "test",
|
|
11700
|
+
description: "Test all download clients",
|
|
11701
|
+
run: (c3) => c3.testAllDownloadClients()
|
|
11451
11702
|
}
|
|
11452
11703
|
]
|
|
11453
|
-
}
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11704
|
+
},
|
|
11705
|
+
{
|
|
11706
|
+
name: "blocklist",
|
|
11707
|
+
description: "View blocked releases",
|
|
11708
|
+
actions: [
|
|
11709
|
+
{
|
|
11710
|
+
name: "list",
|
|
11711
|
+
description: "List blocked releases",
|
|
11712
|
+
columns: ["id", "artistName", "sourceTitle", "date"],
|
|
11713
|
+
run: async (c3) => {
|
|
11714
|
+
const items = unwrapData3(await c3.getBlocklist());
|
|
11715
|
+
return items.map(formatBlocklistItem);
|
|
11716
|
+
}
|
|
11717
|
+
},
|
|
11718
|
+
{
|
|
11719
|
+
name: "delete",
|
|
11720
|
+
description: "Remove a release from the blocklist",
|
|
11721
|
+
args: [{ name: "id", description: "Blocklist item ID", required: true, type: "number" }],
|
|
11722
|
+
confirmMessage: "Are you sure you want to remove this blocklist entry?",
|
|
11723
|
+
run: (c3, a2) => c3.removeBlocklistItem(a2.id)
|
|
11724
|
+
}
|
|
11725
|
+
]
|
|
11726
|
+
},
|
|
11727
|
+
{
|
|
11728
|
+
name: "wanted",
|
|
11729
|
+
description: "View missing and cutoff unmet albums",
|
|
11730
|
+
actions: [
|
|
11731
|
+
{
|
|
11732
|
+
name: "missing",
|
|
11733
|
+
description: "List albums with missing tracks",
|
|
11734
|
+
columns: ["id", "artistName", "title", "releaseDate"],
|
|
11735
|
+
run: async (c3) => {
|
|
11736
|
+
const albums = unwrapData3(await c3.getWantedMissing());
|
|
11737
|
+
return albums.map(formatAlbumListItem);
|
|
11738
|
+
}
|
|
11739
|
+
},
|
|
11740
|
+
{
|
|
11741
|
+
name: "cutoff",
|
|
11742
|
+
description: "List albums below quality cutoff",
|
|
11743
|
+
columns: ["id", "artistName", "title", "releaseDate"],
|
|
11744
|
+
run: async (c3) => {
|
|
11745
|
+
const albums = unwrapData3(await c3.getWantedCutoff());
|
|
11746
|
+
return albums.map(formatAlbumListItem);
|
|
11747
|
+
}
|
|
11748
|
+
}
|
|
11749
|
+
]
|
|
11750
|
+
},
|
|
11751
|
+
{
|
|
11752
|
+
name: "importlist",
|
|
11753
|
+
description: "Manage import lists",
|
|
11754
|
+
actions: [
|
|
11755
|
+
{
|
|
11756
|
+
name: "list",
|
|
11757
|
+
description: "List import lists",
|
|
11758
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
11759
|
+
run: (c3) => c3.getImportLists()
|
|
11760
|
+
},
|
|
11761
|
+
{
|
|
11762
|
+
name: "get",
|
|
11763
|
+
description: "Get an import list by ID",
|
|
11764
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
11765
|
+
run: (c3, a2) => c3.getImportList(a2.id)
|
|
11766
|
+
},
|
|
11767
|
+
{
|
|
11768
|
+
name: "delete",
|
|
11769
|
+
description: "Delete an import list",
|
|
11770
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
11771
|
+
confirmMessage: "Are you sure you want to delete this import list?",
|
|
11772
|
+
run: (c3, a2) => c3.deleteImportList(a2.id)
|
|
11773
|
+
}
|
|
11774
|
+
]
|
|
11775
|
+
},
|
|
11776
|
+
{
|
|
11777
|
+
name: "rootfolder",
|
|
11778
|
+
description: "Manage root folders",
|
|
11779
|
+
actions: [
|
|
11780
|
+
{
|
|
11781
|
+
name: "list",
|
|
11782
|
+
description: "List root folders",
|
|
11783
|
+
columns: ["id", "path", "freeSpace"],
|
|
11784
|
+
run: (c3) => c3.getRootFolders()
|
|
11785
|
+
},
|
|
11786
|
+
{
|
|
11787
|
+
name: "add",
|
|
11788
|
+
description: "Add a root folder",
|
|
11789
|
+
args: [{ name: "path", description: "Folder path", required: true }],
|
|
11790
|
+
run: (c3, a2) => c3.addRootFolder(a2.path)
|
|
11791
|
+
},
|
|
11792
|
+
{
|
|
11793
|
+
name: "delete",
|
|
11794
|
+
description: "Delete a root folder",
|
|
11795
|
+
args: [{ name: "id", description: "Root folder ID", required: true, type: "number" }],
|
|
11796
|
+
confirmMessage: "Are you sure you want to delete this root folder?",
|
|
11797
|
+
run: (c3, a2) => c3.deleteRootFolder(a2.id)
|
|
11798
|
+
}
|
|
11799
|
+
]
|
|
11800
|
+
},
|
|
11801
|
+
{
|
|
11802
|
+
name: "system",
|
|
11803
|
+
description: "System information",
|
|
11804
|
+
actions: [
|
|
11805
|
+
{
|
|
11806
|
+
name: "status",
|
|
11807
|
+
description: "Get system status",
|
|
11808
|
+
run: (c3) => c3.getSystemStatus()
|
|
11809
|
+
},
|
|
11810
|
+
{
|
|
11811
|
+
name: "health",
|
|
11812
|
+
description: "Get health check results",
|
|
11813
|
+
columns: ["type", "message", "source"],
|
|
11814
|
+
run: (c3) => c3.getHealth()
|
|
11815
|
+
}
|
|
11816
|
+
]
|
|
11817
|
+
}
|
|
11818
|
+
];
|
|
11819
|
+
lidarr = buildServiceCommand("lidarr", "Manage Lidarr (Music)", (config) => new LidarrClient(config), resources3);
|
|
11820
|
+
});
|
|
11457
11821
|
|
|
11458
11822
|
// src/generated/readarr/core/bodySerializer.gen.ts
|
|
11459
11823
|
var jsonBodySerializer4;
|
|
@@ -12428,6 +12792,22 @@ var getApiV1Author = (options) => (options?.client ?? client4).get({
|
|
|
12428
12792
|
}],
|
|
12429
12793
|
url: "/api/v1/book/lookup",
|
|
12430
12794
|
...options
|
|
12795
|
+
}), getApiV1Calendar2 = (options) => (options?.client ?? client4).get({
|
|
12796
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12797
|
+
in: "query",
|
|
12798
|
+
name: "apikey",
|
|
12799
|
+
type: "apiKey"
|
|
12800
|
+
}],
|
|
12801
|
+
url: "/api/v1/calendar",
|
|
12802
|
+
...options
|
|
12803
|
+
}), getFeedV1CalendarReadarrIcs = (options) => (options?.client ?? client4).get({
|
|
12804
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12805
|
+
in: "query",
|
|
12806
|
+
name: "apikey",
|
|
12807
|
+
type: "apiKey"
|
|
12808
|
+
}],
|
|
12809
|
+
url: "/feed/v1/calendar/readarr.ics",
|
|
12810
|
+
...options
|
|
12431
12811
|
}), getApiV1Command2 = (options) => (options?.client ?? client4).get({
|
|
12432
12812
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12433
12813
|
in: "query",
|
|
@@ -12504,6 +12884,14 @@ var getApiV1Author = (options) => (options?.client ?? client4).get({
|
|
|
12504
12884
|
}],
|
|
12505
12885
|
url: "/api/v1/customformat/schema",
|
|
12506
12886
|
...options
|
|
12887
|
+
}), getApiV1WantedCutoff2 = (options) => (options?.client ?? client4).get({
|
|
12888
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12889
|
+
in: "query",
|
|
12890
|
+
name: "apikey",
|
|
12891
|
+
type: "apiKey"
|
|
12892
|
+
}],
|
|
12893
|
+
url: "/api/v1/wanted/cutoff",
|
|
12894
|
+
...options
|
|
12507
12895
|
}), getApiV1ConfigDevelopment = (options) => (options?.client ?? client4).get({
|
|
12508
12896
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12509
12897
|
in: "query",
|
|
@@ -12916,6 +13304,14 @@ var getApiV1Author = (options) => (options?.client ?? client4).get({
|
|
|
12916
13304
|
"Content-Type": "application/json",
|
|
12917
13305
|
...options.headers
|
|
12918
13306
|
}
|
|
13307
|
+
}), getApiV1WantedMissing2 = (options) => (options?.client ?? client4).get({
|
|
13308
|
+
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
13309
|
+
in: "query",
|
|
13310
|
+
name: "apikey",
|
|
13311
|
+
type: "apiKey"
|
|
13312
|
+
}],
|
|
13313
|
+
url: "/api/v1/wanted/missing",
|
|
13314
|
+
...options
|
|
12919
13315
|
}), getApiV1ConfigNaming2 = (options) => (options?.client ?? client4).get({
|
|
12920
13316
|
security: [{ name: "X-Api-Key", type: "apiKey" }, {
|
|
12921
13317
|
in: "query",
|
|
@@ -13487,6 +13883,26 @@ class ReadarrClient {
|
|
|
13487
13883
|
async searchBooks(term) {
|
|
13488
13884
|
return getApiV1BookLookup({ query: { term } });
|
|
13489
13885
|
}
|
|
13886
|
+
async getCalendar(start, end, unmonitored) {
|
|
13887
|
+
const query = { includeAuthor: true };
|
|
13888
|
+
if (start)
|
|
13889
|
+
query.start = start;
|
|
13890
|
+
if (end)
|
|
13891
|
+
query.end = end;
|
|
13892
|
+
if (unmonitored !== undefined)
|
|
13893
|
+
query.unmonitored = unmonitored;
|
|
13894
|
+
return getApiV1Calendar2(Object.keys(query).length > 0 ? { query } : {});
|
|
13895
|
+
}
|
|
13896
|
+
async getCalendarFeed(pastDays, futureDays, tagList) {
|
|
13897
|
+
const query = {};
|
|
13898
|
+
if (pastDays !== undefined)
|
|
13899
|
+
query.pastDays = pastDays;
|
|
13900
|
+
if (futureDays !== undefined)
|
|
13901
|
+
query.futureDays = futureDays;
|
|
13902
|
+
if (tagList)
|
|
13903
|
+
query.tagList = tagList;
|
|
13904
|
+
return getFeedV1CalendarReadarrIcs(Object.keys(query).length > 0 ? { query } : {});
|
|
13905
|
+
}
|
|
13490
13906
|
async getQualityProfiles() {
|
|
13491
13907
|
return getApiV1Qualityprofile2();
|
|
13492
13908
|
}
|
|
@@ -13723,6 +14139,34 @@ class ReadarrClient {
|
|
|
13723
14139
|
async removeBlocklistItemsBulk(ids) {
|
|
13724
14140
|
return deleteApiV1BlocklistBulk2({ body: { ids } });
|
|
13725
14141
|
}
|
|
14142
|
+
async getWantedMissing(page, pageSize, sortKey, sortDirection, monitored) {
|
|
14143
|
+
const query = { includeAuthor: true };
|
|
14144
|
+
if (page !== undefined)
|
|
14145
|
+
query.page = page;
|
|
14146
|
+
if (pageSize !== undefined)
|
|
14147
|
+
query.pageSize = pageSize;
|
|
14148
|
+
if (sortKey)
|
|
14149
|
+
query.sortKey = sortKey;
|
|
14150
|
+
if (sortDirection)
|
|
14151
|
+
query.sortDirection = sortDirection;
|
|
14152
|
+
if (monitored !== undefined)
|
|
14153
|
+
query.monitored = monitored;
|
|
14154
|
+
return getApiV1WantedMissing2(Object.keys(query).length > 0 ? { query } : {});
|
|
14155
|
+
}
|
|
14156
|
+
async getWantedCutoff(page, pageSize, sortKey, sortDirection, monitored) {
|
|
14157
|
+
const query = { includeAuthor: true };
|
|
14158
|
+
if (page !== undefined)
|
|
14159
|
+
query.page = page;
|
|
14160
|
+
if (pageSize !== undefined)
|
|
14161
|
+
query.pageSize = pageSize;
|
|
14162
|
+
if (sortKey)
|
|
14163
|
+
query.sortKey = sortKey;
|
|
14164
|
+
if (sortDirection)
|
|
14165
|
+
query.sortDirection = sortDirection;
|
|
14166
|
+
if (monitored !== undefined)
|
|
14167
|
+
query.monitored = monitored;
|
|
14168
|
+
return getApiV1WantedCutoff2(Object.keys(query).length > 0 ? { query } : {});
|
|
14169
|
+
}
|
|
13726
14170
|
updateConfig(newConfig) {
|
|
13727
14171
|
const updatedConfig = { ...this.clientConfig.config, ...newConfig };
|
|
13728
14172
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
@@ -13744,6 +14188,38 @@ var exports_readarr3 = {};
|
|
|
13744
14188
|
__export(exports_readarr3, {
|
|
13745
14189
|
readarr: () => readarr
|
|
13746
14190
|
});
|
|
14191
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
14192
|
+
function unwrapData4(result) {
|
|
14193
|
+
return result?.data ?? result;
|
|
14194
|
+
}
|
|
14195
|
+
function formatBookListItem(book) {
|
|
14196
|
+
return {
|
|
14197
|
+
...book,
|
|
14198
|
+
authorName: book?.authorName ?? book?.authorTitle ?? book?.author?.authorName ?? "—"
|
|
14199
|
+
};
|
|
14200
|
+
}
|
|
14201
|
+
function formatQueueListItem2(item) {
|
|
14202
|
+
return {
|
|
14203
|
+
...item,
|
|
14204
|
+
authorName: item?.authorName ?? item?.authorTitle ?? item?.author?.authorName ?? "—"
|
|
14205
|
+
};
|
|
14206
|
+
}
|
|
14207
|
+
function formatHistoryListItem2(item) {
|
|
14208
|
+
return {
|
|
14209
|
+
...item,
|
|
14210
|
+
authorName: item?.authorName ?? item?.authorTitle ?? item?.author?.authorName ?? "—"
|
|
14211
|
+
};
|
|
14212
|
+
}
|
|
14213
|
+
function formatBlocklistItem2(item) {
|
|
14214
|
+
return {
|
|
14215
|
+
...item,
|
|
14216
|
+
authorName: item?.authorName ?? item?.authorTitle ?? item?.author?.authorName ?? "—"
|
|
14217
|
+
};
|
|
14218
|
+
}
|
|
14219
|
+
function readJsonInput4(filePath) {
|
|
14220
|
+
const raw = filePath === "-" ? readFileSync5(0, "utf-8") : readFileSync5(filePath, "utf-8");
|
|
14221
|
+
return JSON.parse(raw);
|
|
14222
|
+
}
|
|
13747
14223
|
var resources4, readarr;
|
|
13748
14224
|
var init_readarr3 = __esm(() => {
|
|
13749
14225
|
init_readarr2();
|
|
@@ -13751,178 +14227,469 @@ var init_readarr3 = __esm(() => {
|
|
|
13751
14227
|
init_service();
|
|
13752
14228
|
resources4 = [
|
|
13753
14229
|
{
|
|
13754
|
-
name: "author",
|
|
13755
|
-
description: "Manage authors",
|
|
14230
|
+
name: "author",
|
|
14231
|
+
description: "Manage authors",
|
|
14232
|
+
actions: [
|
|
14233
|
+
{
|
|
14234
|
+
name: "list",
|
|
14235
|
+
description: "List all authors",
|
|
14236
|
+
columns: ["id", "authorName", "monitored", "qualityProfileId"],
|
|
14237
|
+
run: (c3) => c3.getAuthors()
|
|
14238
|
+
},
|
|
14239
|
+
{
|
|
14240
|
+
name: "get",
|
|
14241
|
+
description: "Get an author by ID",
|
|
14242
|
+
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
14243
|
+
run: (c3, a2) => c3.getAuthor(a2.id)
|
|
14244
|
+
},
|
|
14245
|
+
{
|
|
14246
|
+
name: "search",
|
|
14247
|
+
description: "Search for authors",
|
|
14248
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
14249
|
+
columns: ["foreignAuthorId", "authorName", "overview"],
|
|
14250
|
+
idField: "foreignAuthorId",
|
|
14251
|
+
run: (c3, a2) => c3.searchAuthors(a2.term)
|
|
14252
|
+
},
|
|
14253
|
+
{
|
|
14254
|
+
name: "add",
|
|
14255
|
+
description: "Search and add an author",
|
|
14256
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
14257
|
+
run: async (c3, a2) => {
|
|
14258
|
+
const results = unwrapData4(await c3.searchAuthors(a2.term));
|
|
14259
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
14260
|
+
throw new Error("No authors found.");
|
|
14261
|
+
}
|
|
14262
|
+
const authorId = await promptSelect("Select an author:", results.map((author2) => ({
|
|
14263
|
+
label: author2.authorName,
|
|
14264
|
+
value: String(author2.foreignAuthorId)
|
|
14265
|
+
})));
|
|
14266
|
+
const author = results.find((item) => String(item.foreignAuthorId) === authorId);
|
|
14267
|
+
if (!author) {
|
|
14268
|
+
throw new Error("Selected author was not found in the search results.");
|
|
14269
|
+
}
|
|
14270
|
+
const profiles = unwrapData4(await c3.getQualityProfiles());
|
|
14271
|
+
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
14272
|
+
throw new Error("No quality profiles found. Configure one in Readarr first.");
|
|
14273
|
+
}
|
|
14274
|
+
const profileId = await promptSelect("Select quality profile:", profiles.map((profile) => ({ label: profile.name, value: String(profile.id) })));
|
|
14275
|
+
const folders = unwrapData4(await c3.getRootFolders());
|
|
14276
|
+
if (!Array.isArray(folders) || folders.length === 0) {
|
|
14277
|
+
throw new Error("No root folders found. Configure one in Readarr first.");
|
|
14278
|
+
}
|
|
14279
|
+
const rootFolderPath = await promptSelect("Select root folder:", folders.map((folder) => ({ label: folder.path, value: folder.path })));
|
|
14280
|
+
const confirmed = await promptConfirm(`Add "${author.authorName}"?`, !!a2.yes);
|
|
14281
|
+
if (!confirmed)
|
|
14282
|
+
throw new Error("Cancelled.");
|
|
14283
|
+
return c3.addAuthor({
|
|
14284
|
+
...author,
|
|
14285
|
+
qualityProfileId: Number(profileId),
|
|
14286
|
+
rootFolderPath,
|
|
14287
|
+
monitored: true,
|
|
14288
|
+
addOptions: { searchForMissingBooks: true }
|
|
14289
|
+
});
|
|
14290
|
+
}
|
|
14291
|
+
},
|
|
14292
|
+
{
|
|
14293
|
+
name: "edit",
|
|
14294
|
+
description: "Edit an author",
|
|
14295
|
+
args: [
|
|
14296
|
+
{ name: "id", description: "Author ID", required: true, type: "number" },
|
|
14297
|
+
{ name: "monitored", description: "Set monitored (true/false)" },
|
|
14298
|
+
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
14299
|
+
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
14300
|
+
],
|
|
14301
|
+
run: async (c3, a2) => {
|
|
14302
|
+
const author = unwrapData4(await c3.getAuthor(a2.id));
|
|
14303
|
+
const updates = { ...author };
|
|
14304
|
+
if (a2.monitored !== undefined)
|
|
14305
|
+
updates.monitored = a2.monitored === "true";
|
|
14306
|
+
if (a2["quality-profile-id"] !== undefined) {
|
|
14307
|
+
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
14308
|
+
}
|
|
14309
|
+
if (a2.tags !== undefined) {
|
|
14310
|
+
updates.tags = a2.tags.split(",").map((tag) => Number(tag.trim()));
|
|
14311
|
+
}
|
|
14312
|
+
return c3.updateAuthor(a2.id, updates);
|
|
14313
|
+
}
|
|
14314
|
+
},
|
|
14315
|
+
{
|
|
14316
|
+
name: "refresh",
|
|
14317
|
+
description: "Refresh author metadata",
|
|
14318
|
+
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
14319
|
+
run: (c3, a2) => c3.runCommand({ name: "RefreshAuthor", authorId: a2.id })
|
|
14320
|
+
},
|
|
14321
|
+
{
|
|
14322
|
+
name: "manual-search",
|
|
14323
|
+
description: "Trigger a manual search for releases",
|
|
14324
|
+
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
14325
|
+
run: (c3, a2) => c3.runCommand({ name: "AuthorSearch", authorId: a2.id })
|
|
14326
|
+
},
|
|
14327
|
+
{
|
|
14328
|
+
name: "delete",
|
|
14329
|
+
description: "Delete an author",
|
|
14330
|
+
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
14331
|
+
confirmMessage: "Are you sure you want to delete this author?",
|
|
14332
|
+
run: (c3, a2) => c3.deleteAuthor(a2.id)
|
|
14333
|
+
}
|
|
14334
|
+
]
|
|
14335
|
+
},
|
|
14336
|
+
{
|
|
14337
|
+
name: "book",
|
|
14338
|
+
description: "Manage books",
|
|
14339
|
+
actions: [
|
|
14340
|
+
{
|
|
14341
|
+
name: "list",
|
|
14342
|
+
description: "List all books",
|
|
14343
|
+
columns: ["id", "authorName", "title", "monitored"],
|
|
14344
|
+
run: async (c3) => {
|
|
14345
|
+
const books = unwrapData4(await c3.getBooks());
|
|
14346
|
+
return books.map(formatBookListItem);
|
|
14347
|
+
}
|
|
14348
|
+
},
|
|
14349
|
+
{
|
|
14350
|
+
name: "get",
|
|
14351
|
+
description: "Get a book by ID",
|
|
14352
|
+
args: [{ name: "id", description: "Book ID", required: true, type: "number" }],
|
|
14353
|
+
run: async (c3, a2) => {
|
|
14354
|
+
const book = unwrapData4(await c3.getBook(a2.id));
|
|
14355
|
+
return formatBookListItem(book);
|
|
14356
|
+
}
|
|
14357
|
+
},
|
|
14358
|
+
{
|
|
14359
|
+
name: "search",
|
|
14360
|
+
description: "Search for books",
|
|
14361
|
+
args: [{ name: "term", description: "Search term", required: true }],
|
|
14362
|
+
columns: ["foreignBookId", "authorName", "title", "monitored"],
|
|
14363
|
+
idField: "foreignBookId",
|
|
14364
|
+
run: async (c3, a2) => {
|
|
14365
|
+
const books = unwrapData4(await c3.searchBooks(a2.term));
|
|
14366
|
+
return books.map(formatBookListItem);
|
|
14367
|
+
}
|
|
14368
|
+
},
|
|
14369
|
+
{
|
|
14370
|
+
name: "add",
|
|
14371
|
+
description: "Add a book from JSON file or stdin",
|
|
14372
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
14373
|
+
run: async (c3, a2) => c3.addBook(readJsonInput4(a2.file))
|
|
14374
|
+
},
|
|
14375
|
+
{
|
|
14376
|
+
name: "edit",
|
|
14377
|
+
description: "Edit a book (merges JSON with existing)",
|
|
14378
|
+
args: [
|
|
14379
|
+
{ name: "id", description: "Book ID", required: true, type: "number" },
|
|
14380
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
14381
|
+
],
|
|
14382
|
+
run: async (c3, a2) => {
|
|
14383
|
+
const existing = unwrapData4(await c3.getBook(a2.id));
|
|
14384
|
+
return c3.updateBook(a2.id, { ...existing, ...readJsonInput4(a2.file) });
|
|
14385
|
+
}
|
|
14386
|
+
},
|
|
14387
|
+
{
|
|
14388
|
+
name: "delete",
|
|
14389
|
+
description: "Delete a book",
|
|
14390
|
+
args: [{ name: "id", description: "Book ID", required: true, type: "number" }],
|
|
14391
|
+
confirmMessage: "Are you sure you want to delete this book?",
|
|
14392
|
+
run: (c3, a2) => c3.deleteBook(a2.id)
|
|
14393
|
+
}
|
|
14394
|
+
]
|
|
14395
|
+
},
|
|
14396
|
+
{
|
|
14397
|
+
name: "profile",
|
|
14398
|
+
description: "Manage quality profiles",
|
|
14399
|
+
actions: [
|
|
14400
|
+
{
|
|
14401
|
+
name: "list",
|
|
14402
|
+
description: "List quality profiles",
|
|
14403
|
+
columns: ["id", "name"],
|
|
14404
|
+
run: (c3) => c3.getQualityProfiles()
|
|
14405
|
+
},
|
|
14406
|
+
{
|
|
14407
|
+
name: "get",
|
|
14408
|
+
description: "Get a quality profile by ID",
|
|
14409
|
+
args: [{ name: "id", description: "Profile ID", required: true, type: "number" }],
|
|
14410
|
+
run: (c3, a2) => c3.getQualityProfile(a2.id)
|
|
14411
|
+
}
|
|
14412
|
+
]
|
|
14413
|
+
},
|
|
14414
|
+
{
|
|
14415
|
+
name: "tag",
|
|
14416
|
+
description: "Manage tags",
|
|
14417
|
+
actions: [
|
|
14418
|
+
{
|
|
14419
|
+
name: "create",
|
|
14420
|
+
description: "Create a tag",
|
|
14421
|
+
args: [{ name: "label", description: "Tag label", required: true }],
|
|
14422
|
+
run: (c3, a2) => c3.addTag({ label: a2.label })
|
|
14423
|
+
},
|
|
14424
|
+
{
|
|
14425
|
+
name: "delete",
|
|
14426
|
+
description: "Delete a tag",
|
|
14427
|
+
args: [{ name: "id", description: "Tag ID", required: true, type: "number" }],
|
|
14428
|
+
confirmMessage: "Are you sure you want to delete this tag?",
|
|
14429
|
+
run: async (c3, a2) => {
|
|
14430
|
+
const tagResult = await c3.getTag(a2.id);
|
|
14431
|
+
if (tagResult?.error)
|
|
14432
|
+
return tagResult;
|
|
14433
|
+
const tag = unwrapData4(tagResult);
|
|
14434
|
+
const deleteResult = await c3.deleteTag(a2.id);
|
|
14435
|
+
if (deleteResult?.error)
|
|
14436
|
+
return deleteResult;
|
|
14437
|
+
return { message: `Deleted tag: ${tag.label} (ID: ${tag.id})` };
|
|
14438
|
+
}
|
|
14439
|
+
},
|
|
14440
|
+
{
|
|
14441
|
+
name: "list",
|
|
14442
|
+
description: "List all tags",
|
|
14443
|
+
columns: ["id", "label"],
|
|
14444
|
+
run: (c3) => c3.getTags()
|
|
14445
|
+
}
|
|
14446
|
+
]
|
|
14447
|
+
},
|
|
14448
|
+
{
|
|
14449
|
+
name: "queue",
|
|
14450
|
+
description: "Manage download queue",
|
|
14451
|
+
actions: [
|
|
14452
|
+
{
|
|
14453
|
+
name: "list",
|
|
14454
|
+
description: "List queue items",
|
|
14455
|
+
columns: ["id", "authorName", "title", "status", "sizeleft", "timeleft"],
|
|
14456
|
+
run: async (c3) => {
|
|
14457
|
+
const items = unwrapData4(await c3.getQueue());
|
|
14458
|
+
return items.map(formatQueueListItem2);
|
|
14459
|
+
}
|
|
14460
|
+
},
|
|
14461
|
+
{
|
|
14462
|
+
name: "status",
|
|
14463
|
+
description: "Get queue status",
|
|
14464
|
+
run: (c3) => c3.getQueueStatus()
|
|
14465
|
+
},
|
|
14466
|
+
{
|
|
14467
|
+
name: "delete",
|
|
14468
|
+
description: "Remove an item from the queue",
|
|
14469
|
+
args: [
|
|
14470
|
+
{ name: "id", description: "Queue item ID", required: true, type: "number" },
|
|
14471
|
+
{ name: "blocklist", description: "Add to blocklist", type: "boolean" },
|
|
14472
|
+
{
|
|
14473
|
+
name: "remove-from-client",
|
|
14474
|
+
description: "Remove from download client",
|
|
14475
|
+
type: "boolean"
|
|
14476
|
+
}
|
|
14477
|
+
],
|
|
14478
|
+
confirmMessage: "Are you sure you want to remove this queue item?",
|
|
14479
|
+
run: (c3, a2) => c3.removeQueueItem(a2.id, a2["remove-from-client"], a2.blocklist)
|
|
14480
|
+
},
|
|
14481
|
+
{
|
|
14482
|
+
name: "grab",
|
|
14483
|
+
description: "Force download a queue item",
|
|
14484
|
+
args: [{ name: "id", description: "Queue item ID", required: true, type: "number" }],
|
|
14485
|
+
run: (c3, a2) => c3.grabQueueItem(a2.id)
|
|
14486
|
+
}
|
|
14487
|
+
]
|
|
14488
|
+
},
|
|
14489
|
+
{
|
|
14490
|
+
name: "history",
|
|
14491
|
+
description: "View history",
|
|
14492
|
+
actions: [
|
|
14493
|
+
{
|
|
14494
|
+
name: "list",
|
|
14495
|
+
description: "List recent history",
|
|
14496
|
+
args: [
|
|
14497
|
+
{ name: "since", description: "Start date (ISO 8601, e.g. 2024-01-01)" },
|
|
14498
|
+
{ name: "until", description: "End date (ISO 8601, e.g. 2024-12-31)" }
|
|
14499
|
+
],
|
|
14500
|
+
columns: ["id", "authorName", "sourceTitle", "eventType", "date"],
|
|
14501
|
+
run: async (c3, a2) => {
|
|
14502
|
+
const items = a2.since ? unwrapData4(await c3.getHistorySince(a2.since)) : unwrapData4(await c3.getHistory());
|
|
14503
|
+
const filtered = a2.until ? items.filter((item) => new Date(item.date) <= new Date(a2.until)) : items;
|
|
14504
|
+
return filtered.map(formatHistoryListItem2);
|
|
14505
|
+
}
|
|
14506
|
+
}
|
|
14507
|
+
]
|
|
14508
|
+
},
|
|
14509
|
+
{
|
|
14510
|
+
name: "calendar",
|
|
14511
|
+
description: "View upcoming releases",
|
|
13756
14512
|
actions: [
|
|
13757
14513
|
{
|
|
13758
14514
|
name: "list",
|
|
13759
|
-
description: "List
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
14515
|
+
description: "List upcoming book releases",
|
|
14516
|
+
args: [
|
|
14517
|
+
{ name: "start", description: "Start date (ISO 8601)" },
|
|
14518
|
+
{ name: "end", description: "End date (ISO 8601)" },
|
|
14519
|
+
{ name: "unmonitored", description: "Include unmonitored", type: "boolean" }
|
|
14520
|
+
],
|
|
14521
|
+
columns: ["id", "authorName", "title", "releaseDate"],
|
|
14522
|
+
run: async (c3, a2) => {
|
|
14523
|
+
const books = unwrapData4(await c3.getCalendar(a2.start, a2.end, a2.unmonitored));
|
|
14524
|
+
return books.map(formatBookListItem);
|
|
14525
|
+
}
|
|
14526
|
+
}
|
|
14527
|
+
]
|
|
14528
|
+
},
|
|
14529
|
+
{
|
|
14530
|
+
name: "notification",
|
|
14531
|
+
description: "Manage notifications",
|
|
14532
|
+
actions: [
|
|
13763
14533
|
{
|
|
13764
|
-
name: "
|
|
13765
|
-
description: "
|
|
13766
|
-
|
|
13767
|
-
run: (c3
|
|
14534
|
+
name: "list",
|
|
14535
|
+
description: "List notification providers",
|
|
14536
|
+
columns: ["id", "name", "implementation"],
|
|
14537
|
+
run: (c3) => c3.getNotifications()
|
|
13768
14538
|
},
|
|
13769
14539
|
{
|
|
13770
|
-
name: "
|
|
13771
|
-
description: "
|
|
13772
|
-
args: [{ name: "
|
|
13773
|
-
|
|
13774
|
-
run: (c3, a2) => c3.searchAuthors(a2.term)
|
|
14540
|
+
name: "get",
|
|
14541
|
+
description: "Get a notification by ID",
|
|
14542
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
14543
|
+
run: (c3, a2) => c3.getNotification(a2.id)
|
|
13775
14544
|
},
|
|
13776
14545
|
{
|
|
13777
14546
|
name: "add",
|
|
13778
|
-
description: "
|
|
13779
|
-
args: [{ name: "
|
|
13780
|
-
run: async (c3, a2) =>
|
|
13781
|
-
const searchResult = await c3.searchAuthors(a2.term);
|
|
13782
|
-
const results = searchResult?.data ?? searchResult;
|
|
13783
|
-
if (!Array.isArray(results) || results.length === 0) {
|
|
13784
|
-
throw new Error("No authors found.");
|
|
13785
|
-
}
|
|
13786
|
-
const authorId = await promptSelect("Select an author:", results.map((au) => ({
|
|
13787
|
-
label: au.authorName,
|
|
13788
|
-
value: String(au.foreignAuthorId)
|
|
13789
|
-
})));
|
|
13790
|
-
const author = results.find((au) => String(au.foreignAuthorId) === authorId);
|
|
13791
|
-
const profilesResult = await c3.getQualityProfiles();
|
|
13792
|
-
const profiles = profilesResult?.data ?? profilesResult;
|
|
13793
|
-
if (!Array.isArray(profiles) || profiles.length === 0) {
|
|
13794
|
-
throw new Error("No quality profiles found. Configure one in Readarr first.");
|
|
13795
|
-
}
|
|
13796
|
-
const profileId = await promptSelect("Select quality profile:", profiles.map((p) => ({ label: p.name, value: String(p.id) })));
|
|
13797
|
-
const foldersResult = await c3.getRootFolders();
|
|
13798
|
-
const folders = foldersResult?.data ?? foldersResult;
|
|
13799
|
-
if (!Array.isArray(folders) || folders.length === 0) {
|
|
13800
|
-
throw new Error("No root folders found. Configure one in Readarr first.");
|
|
13801
|
-
}
|
|
13802
|
-
const rootFolderPath = await promptSelect("Select root folder:", folders.map((f3) => ({ label: f3.path, value: f3.path })));
|
|
13803
|
-
const confirmed = await promptConfirm(`Add "${author.authorName}"?`, !!a2.yes);
|
|
13804
|
-
if (!confirmed)
|
|
13805
|
-
throw new Error("Cancelled.");
|
|
13806
|
-
return c3.addAuthor({
|
|
13807
|
-
...author,
|
|
13808
|
-
qualityProfileId: Number(profileId),
|
|
13809
|
-
rootFolderPath,
|
|
13810
|
-
monitored: true,
|
|
13811
|
-
addOptions: { searchForMissingBooks: true }
|
|
13812
|
-
});
|
|
13813
|
-
}
|
|
14547
|
+
description: "Add a notification from JSON file or stdin",
|
|
14548
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
14549
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput4(a2.file))
|
|
13814
14550
|
},
|
|
13815
14551
|
{
|
|
13816
14552
|
name: "edit",
|
|
13817
|
-
description: "Edit
|
|
14553
|
+
description: "Edit a notification (merges JSON with existing)",
|
|
13818
14554
|
args: [
|
|
13819
|
-
{ name: "id", description: "
|
|
13820
|
-
{ name: "
|
|
13821
|
-
{ name: "quality-profile-id", description: "Quality profile ID", type: "number" },
|
|
13822
|
-
{ name: "tags", description: "Comma-separated tag IDs" }
|
|
14555
|
+
{ name: "id", description: "Notification ID", required: true, type: "number" },
|
|
14556
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
13823
14557
|
],
|
|
13824
14558
|
run: async (c3, a2) => {
|
|
13825
|
-
const
|
|
13826
|
-
|
|
13827
|
-
const updates = { ...author };
|
|
13828
|
-
if (a2.monitored !== undefined)
|
|
13829
|
-
updates.monitored = a2.monitored === "true";
|
|
13830
|
-
if (a2["quality-profile-id"] !== undefined)
|
|
13831
|
-
updates.qualityProfileId = Number(a2["quality-profile-id"]);
|
|
13832
|
-
if (a2.tags !== undefined)
|
|
13833
|
-
updates.tags = a2.tags.split(",").map((t2) => Number(t2.trim()));
|
|
13834
|
-
return c3.updateAuthor(a2.id, updates);
|
|
14559
|
+
const existing = unwrapData4(await c3.getNotification(a2.id));
|
|
14560
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput4(a2.file) });
|
|
13835
14561
|
}
|
|
13836
14562
|
},
|
|
13837
14563
|
{
|
|
13838
|
-
name: "
|
|
13839
|
-
description: "
|
|
13840
|
-
args: [{ name: "id", description: "
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
{
|
|
13844
|
-
name: "manual-search",
|
|
13845
|
-
description: "Trigger a manual search for releases",
|
|
13846
|
-
args: [{ name: "id", description: "Author ID", required: true, type: "number" }],
|
|
13847
|
-
run: (c3, a2) => c3.runCommand({ name: "AuthorSearch", authorId: a2.id })
|
|
14564
|
+
name: "delete",
|
|
14565
|
+
description: "Delete a notification",
|
|
14566
|
+
args: [{ name: "id", description: "Notification ID", required: true, type: "number" }],
|
|
14567
|
+
confirmMessage: "Are you sure you want to delete this notification?",
|
|
14568
|
+
run: (c3, a2) => c3.deleteNotification(a2.id)
|
|
13848
14569
|
},
|
|
13849
14570
|
{
|
|
13850
|
-
name: "
|
|
13851
|
-
description: "
|
|
13852
|
-
|
|
13853
|
-
confirmMessage: "Are you sure you want to delete this author?",
|
|
13854
|
-
run: (c3, a2) => c3.deleteAuthor(a2.id)
|
|
14571
|
+
name: "test",
|
|
14572
|
+
description: "Test all notifications",
|
|
14573
|
+
run: (c3) => c3.testAllNotifications()
|
|
13855
14574
|
}
|
|
13856
14575
|
]
|
|
13857
14576
|
},
|
|
13858
14577
|
{
|
|
13859
|
-
name: "
|
|
13860
|
-
description: "Manage
|
|
14578
|
+
name: "downloadclient",
|
|
14579
|
+
description: "Manage download clients",
|
|
13861
14580
|
actions: [
|
|
13862
14581
|
{
|
|
13863
14582
|
name: "list",
|
|
13864
|
-
description: "List
|
|
13865
|
-
columns: ["id", "
|
|
13866
|
-
run: (c3) => c3.
|
|
14583
|
+
description: "List download clients",
|
|
14584
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
14585
|
+
run: (c3) => c3.getDownloadClients()
|
|
13867
14586
|
},
|
|
13868
14587
|
{
|
|
13869
14588
|
name: "get",
|
|
13870
|
-
description: "Get a
|
|
13871
|
-
args: [{ name: "id", description: "
|
|
13872
|
-
run: (c3, a2) => c3.
|
|
14589
|
+
description: "Get a download client by ID",
|
|
14590
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
14591
|
+
run: (c3, a2) => c3.getDownloadClient(a2.id)
|
|
13873
14592
|
},
|
|
13874
14593
|
{
|
|
13875
|
-
name: "
|
|
13876
|
-
description: "
|
|
13877
|
-
args: [{ name: "
|
|
13878
|
-
|
|
13879
|
-
|
|
14594
|
+
name: "add",
|
|
14595
|
+
description: "Add a download client from JSON file or stdin",
|
|
14596
|
+
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
14597
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput4(a2.file))
|
|
14598
|
+
},
|
|
14599
|
+
{
|
|
14600
|
+
name: "edit",
|
|
14601
|
+
description: "Edit a download client (merges JSON with existing)",
|
|
14602
|
+
args: [
|
|
14603
|
+
{ name: "id", description: "Download client ID", required: true, type: "number" },
|
|
14604
|
+
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
14605
|
+
],
|
|
14606
|
+
run: async (c3, a2) => {
|
|
14607
|
+
const existing = unwrapData4(await c3.getDownloadClient(a2.id));
|
|
14608
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput4(a2.file) });
|
|
14609
|
+
}
|
|
14610
|
+
},
|
|
14611
|
+
{
|
|
14612
|
+
name: "delete",
|
|
14613
|
+
description: "Delete a download client",
|
|
14614
|
+
args: [{ name: "id", description: "Download client ID", required: true, type: "number" }],
|
|
14615
|
+
confirmMessage: "Are you sure you want to delete this download client?",
|
|
14616
|
+
run: (c3, a2) => c3.deleteDownloadClient(a2.id)
|
|
14617
|
+
},
|
|
14618
|
+
{
|
|
14619
|
+
name: "test",
|
|
14620
|
+
description: "Test all download clients",
|
|
14621
|
+
run: (c3) => c3.testAllDownloadClients()
|
|
13880
14622
|
}
|
|
13881
14623
|
]
|
|
13882
14624
|
},
|
|
13883
14625
|
{
|
|
13884
|
-
name: "
|
|
13885
|
-
description: "
|
|
14626
|
+
name: "blocklist",
|
|
14627
|
+
description: "View blocked releases",
|
|
13886
14628
|
actions: [
|
|
13887
14629
|
{
|
|
13888
14630
|
name: "list",
|
|
13889
|
-
description: "List
|
|
13890
|
-
columns: ["id", "
|
|
13891
|
-
run: (c3) =>
|
|
14631
|
+
description: "List blocked releases",
|
|
14632
|
+
columns: ["id", "authorName", "sourceTitle", "date"],
|
|
14633
|
+
run: async (c3) => {
|
|
14634
|
+
const items = unwrapData4(await c3.getBlocklist());
|
|
14635
|
+
return items.map(formatBlocklistItem2);
|
|
14636
|
+
}
|
|
14637
|
+
},
|
|
14638
|
+
{
|
|
14639
|
+
name: "delete",
|
|
14640
|
+
description: "Remove a release from the blocklist",
|
|
14641
|
+
args: [{ name: "id", description: "Blocklist item ID", required: true, type: "number" }],
|
|
14642
|
+
confirmMessage: "Are you sure you want to remove this blocklist entry?",
|
|
14643
|
+
run: (c3, a2) => c3.removeBlocklistItem(a2.id)
|
|
13892
14644
|
}
|
|
13893
14645
|
]
|
|
13894
14646
|
},
|
|
13895
14647
|
{
|
|
13896
|
-
name: "
|
|
13897
|
-
description: "
|
|
14648
|
+
name: "wanted",
|
|
14649
|
+
description: "View missing and cutoff unmet books",
|
|
13898
14650
|
actions: [
|
|
13899
14651
|
{
|
|
13900
|
-
name: "
|
|
13901
|
-
description: "
|
|
13902
|
-
|
|
13903
|
-
run: (c3
|
|
14652
|
+
name: "missing",
|
|
14653
|
+
description: "List books with missing files",
|
|
14654
|
+
columns: ["id", "authorName", "title", "releaseDate"],
|
|
14655
|
+
run: async (c3) => {
|
|
14656
|
+
const books = unwrapData4(await c3.getWantedMissing());
|
|
14657
|
+
return books.map(formatBookListItem);
|
|
14658
|
+
}
|
|
13904
14659
|
},
|
|
13905
14660
|
{
|
|
13906
|
-
name: "
|
|
13907
|
-
description: "
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
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})` };
|
|
14661
|
+
name: "cutoff",
|
|
14662
|
+
description: "List books below quality cutoff",
|
|
14663
|
+
columns: ["id", "authorName", "title", "releaseDate"],
|
|
14664
|
+
run: async (c3) => {
|
|
14665
|
+
const books = unwrapData4(await c3.getWantedCutoff());
|
|
14666
|
+
return books.map(formatBookListItem);
|
|
13919
14667
|
}
|
|
13920
|
-
}
|
|
14668
|
+
}
|
|
14669
|
+
]
|
|
14670
|
+
},
|
|
14671
|
+
{
|
|
14672
|
+
name: "importlist",
|
|
14673
|
+
description: "Manage import lists",
|
|
14674
|
+
actions: [
|
|
13921
14675
|
{
|
|
13922
14676
|
name: "list",
|
|
13923
|
-
description: "List
|
|
13924
|
-
columns: ["id", "
|
|
13925
|
-
run: (c3) => c3.
|
|
14677
|
+
description: "List import lists",
|
|
14678
|
+
columns: ["id", "name", "implementation", "enable"],
|
|
14679
|
+
run: (c3) => c3.getImportLists()
|
|
14680
|
+
},
|
|
14681
|
+
{
|
|
14682
|
+
name: "get",
|
|
14683
|
+
description: "Get an import list by ID",
|
|
14684
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
14685
|
+
run: (c3, a2) => c3.getImportList(a2.id)
|
|
14686
|
+
},
|
|
14687
|
+
{
|
|
14688
|
+
name: "delete",
|
|
14689
|
+
description: "Delete an import list",
|
|
14690
|
+
args: [{ name: "id", description: "Import list ID", required: true, type: "number" }],
|
|
14691
|
+
confirmMessage: "Are you sure you want to delete this import list?",
|
|
14692
|
+
run: (c3, a2) => c3.deleteImportList(a2.id)
|
|
13926
14693
|
}
|
|
13927
14694
|
]
|
|
13928
14695
|
},
|
|
@@ -15592,14 +16359,53 @@ var exports_prowlarr3 = {};
|
|
|
15592
16359
|
__export(exports_prowlarr3, {
|
|
15593
16360
|
prowlarr: () => prowlarr
|
|
15594
16361
|
});
|
|
15595
|
-
import { readFileSync as
|
|
15596
|
-
function
|
|
16362
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
16363
|
+
function unwrapData5(result) {
|
|
15597
16364
|
return result?.data ?? result;
|
|
15598
16365
|
}
|
|
15599
|
-
function
|
|
15600
|
-
const raw = filePath === "-" ?
|
|
16366
|
+
function readJsonInput5(filePath) {
|
|
16367
|
+
const raw = filePath === "-" ? readFileSync6(0, "utf-8") : readFileSync6(filePath, "utf-8");
|
|
15601
16368
|
return JSON.parse(raw);
|
|
15602
16369
|
}
|
|
16370
|
+
async function runIndexerTest(client6, indexer) {
|
|
16371
|
+
const result = await client6.testIndexer(indexer);
|
|
16372
|
+
if (result?.error) {
|
|
16373
|
+
const error = result.error;
|
|
16374
|
+
const response = result.response;
|
|
16375
|
+
const status = error?.status ?? response?.status;
|
|
16376
|
+
return {
|
|
16377
|
+
id: indexer?.id,
|
|
16378
|
+
name: indexer?.name ?? "Unknown indexer",
|
|
16379
|
+
status: "fail",
|
|
16380
|
+
message: error?.title ?? error?.message ?? `API error (${status ?? "unknown"})`
|
|
16381
|
+
};
|
|
16382
|
+
}
|
|
16383
|
+
const data = unwrapData5(result);
|
|
16384
|
+
return {
|
|
16385
|
+
id: indexer?.id,
|
|
16386
|
+
name: indexer?.name ?? "Unknown indexer",
|
|
16387
|
+
status: "ok",
|
|
16388
|
+
message: extractIndexerTestMessage(data)
|
|
16389
|
+
};
|
|
16390
|
+
}
|
|
16391
|
+
function extractIndexerTestMessage(data) {
|
|
16392
|
+
if (typeof data === "string" && data.trim() !== "") {
|
|
16393
|
+
return data;
|
|
16394
|
+
}
|
|
16395
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
16396
|
+
const first = data[0];
|
|
16397
|
+
if (typeof first === "string" && first.trim() !== "") {
|
|
16398
|
+
return first;
|
|
16399
|
+
}
|
|
16400
|
+
if (typeof first?.message === "string" && first.message.trim() !== "") {
|
|
16401
|
+
return first.message;
|
|
16402
|
+
}
|
|
16403
|
+
}
|
|
16404
|
+
if (typeof data?.message === "string" && data.message.trim() !== "") {
|
|
16405
|
+
return data.message;
|
|
16406
|
+
}
|
|
16407
|
+
return "Test completed";
|
|
16408
|
+
}
|
|
15603
16409
|
var resources5, prowlarr;
|
|
15604
16410
|
var init_prowlarr3 = __esm(() => {
|
|
15605
16411
|
init_prowlarr2();
|
|
@@ -15627,7 +16433,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15627
16433
|
description: "Add an indexer from JSON file or stdin",
|
|
15628
16434
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15629
16435
|
run: async (c3, a2) => {
|
|
15630
|
-
const body =
|
|
16436
|
+
const body = readJsonInput5(a2.file);
|
|
15631
16437
|
return c3.addIndexer(body);
|
|
15632
16438
|
}
|
|
15633
16439
|
},
|
|
@@ -15639,8 +16445,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15639
16445
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15640
16446
|
],
|
|
15641
16447
|
run: async (c3, a2) => {
|
|
15642
|
-
const existing =
|
|
15643
|
-
const updates =
|
|
16448
|
+
const existing = unwrapData5(await c3.getIndexer(a2.id));
|
|
16449
|
+
const updates = readJsonInput5(a2.file);
|
|
15644
16450
|
return c3.updateIndexer(a2.id, { ...existing, ...updates });
|
|
15645
16451
|
}
|
|
15646
16452
|
},
|
|
@@ -15653,8 +16459,17 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15653
16459
|
},
|
|
15654
16460
|
{
|
|
15655
16461
|
name: "test",
|
|
15656
|
-
description: "Test all indexers",
|
|
15657
|
-
|
|
16462
|
+
description: "Test one indexer or all configured indexers",
|
|
16463
|
+
args: [{ name: "id", description: "Indexer ID", type: "number" }],
|
|
16464
|
+
columns: ["id", "name", "status", "message"],
|
|
16465
|
+
run: async (c3, a2) => {
|
|
16466
|
+
const indexers = a2.id ? [unwrapData5(await c3.getIndexer(a2.id))] : unwrapData5(await c3.getIndexers());
|
|
16467
|
+
const results = [];
|
|
16468
|
+
for (const indexer of indexers) {
|
|
16469
|
+
results.push(await runIndexerTest(c3, indexer));
|
|
16470
|
+
}
|
|
16471
|
+
return a2.id ? results[0] : results;
|
|
16472
|
+
}
|
|
15658
16473
|
}
|
|
15659
16474
|
]
|
|
15660
16475
|
},
|
|
@@ -15695,7 +16510,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15695
16510
|
description: "Add an application from JSON file or stdin",
|
|
15696
16511
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15697
16512
|
run: async (c3, a2) => {
|
|
15698
|
-
const body =
|
|
16513
|
+
const body = readJsonInput5(a2.file);
|
|
15699
16514
|
return c3.addApplication(body);
|
|
15700
16515
|
}
|
|
15701
16516
|
},
|
|
@@ -15707,8 +16522,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15707
16522
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15708
16523
|
],
|
|
15709
16524
|
run: async (c3, a2) => {
|
|
15710
|
-
const existing =
|
|
15711
|
-
const updates =
|
|
16525
|
+
const existing = unwrapData5(await c3.getApplication(a2.id));
|
|
16526
|
+
const updates = readJsonInput5(a2.file);
|
|
15712
16527
|
return c3.updateApplication(a2.id, { ...existing, ...updates });
|
|
15713
16528
|
}
|
|
15714
16529
|
},
|
|
@@ -15775,7 +16590,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15775
16590
|
"averageResponseTime"
|
|
15776
16591
|
],
|
|
15777
16592
|
run: async (c3) => {
|
|
15778
|
-
const result =
|
|
16593
|
+
const result = unwrapData5(await c3.getIndexerStats());
|
|
15779
16594
|
return result?.indexers ?? result;
|
|
15780
16595
|
}
|
|
15781
16596
|
}
|
|
@@ -15801,7 +16616,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15801
16616
|
name: "add",
|
|
15802
16617
|
description: "Add a notification from JSON file or stdin",
|
|
15803
16618
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15804
|
-
run: async (c3, a2) => c3.addNotification(
|
|
16619
|
+
run: async (c3, a2) => c3.addNotification(readJsonInput5(a2.file))
|
|
15805
16620
|
},
|
|
15806
16621
|
{
|
|
15807
16622
|
name: "edit",
|
|
@@ -15811,8 +16626,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15811
16626
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15812
16627
|
],
|
|
15813
16628
|
run: async (c3, a2) => {
|
|
15814
|
-
const existing =
|
|
15815
|
-
return c3.updateNotification(a2.id, { ...existing, ...
|
|
16629
|
+
const existing = unwrapData5(await c3.getNotification(a2.id));
|
|
16630
|
+
return c3.updateNotification(a2.id, { ...existing, ...readJsonInput5(a2.file) });
|
|
15816
16631
|
}
|
|
15817
16632
|
},
|
|
15818
16633
|
{
|
|
@@ -15849,7 +16664,7 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15849
16664
|
name: "add",
|
|
15850
16665
|
description: "Add a download client from JSON file or stdin",
|
|
15851
16666
|
args: [{ name: "file", description: "JSON file path (use - for stdin)", required: true }],
|
|
15852
|
-
run: async (c3, a2) => c3.addDownloadClient(
|
|
16667
|
+
run: async (c3, a2) => c3.addDownloadClient(readJsonInput5(a2.file))
|
|
15853
16668
|
},
|
|
15854
16669
|
{
|
|
15855
16670
|
name: "edit",
|
|
@@ -15859,8 +16674,8 @@ var init_prowlarr3 = __esm(() => {
|
|
|
15859
16674
|
{ name: "file", description: "JSON file with fields to update", required: true }
|
|
15860
16675
|
],
|
|
15861
16676
|
run: async (c3, a2) => {
|
|
15862
|
-
const existing =
|
|
15863
|
-
return c3.updateDownloadClient(a2.id, { ...existing, ...
|
|
16677
|
+
const existing = unwrapData5(await c3.getDownloadClient(a2.id));
|
|
16678
|
+
return c3.updateDownloadClient(a2.id, { ...existing, ...readJsonInput5(a2.file) });
|
|
15864
16679
|
}
|
|
15865
16680
|
},
|
|
15866
16681
|
{
|
|
@@ -17006,6 +17821,12 @@ function getBazarrApiBaseUrl(baseUrl) {
|
|
|
17006
17821
|
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
17007
17822
|
return normalizedBaseUrl.endsWith("/api") ? normalizedBaseUrl : `${normalizedBaseUrl}/api`;
|
|
17008
17823
|
}
|
|
17824
|
+
function getBazarrHeaders(config) {
|
|
17825
|
+
return {
|
|
17826
|
+
"Content-Type": "application/json",
|
|
17827
|
+
...config.config.headers ?? {}
|
|
17828
|
+
};
|
|
17829
|
+
}
|
|
17009
17830
|
|
|
17010
17831
|
class BazarrClient {
|
|
17011
17832
|
clientConfig;
|
|
@@ -17013,7 +17834,8 @@ class BazarrClient {
|
|
|
17013
17834
|
this.clientConfig = createServarrClient(config);
|
|
17014
17835
|
client6.setConfig({
|
|
17015
17836
|
baseUrl: getBazarrApiBaseUrl(this.clientConfig.getBaseUrl()),
|
|
17016
|
-
headers: this.clientConfig
|
|
17837
|
+
headers: getBazarrHeaders(this.clientConfig),
|
|
17838
|
+
auth: this.clientConfig.config.apiKey
|
|
17017
17839
|
});
|
|
17018
17840
|
}
|
|
17019
17841
|
async getSystemStatus() {
|
|
@@ -17353,7 +18175,8 @@ class BazarrClient {
|
|
|
17353
18175
|
this.clientConfig = createServarrClient(updatedConfig);
|
|
17354
18176
|
client6.setConfig({
|
|
17355
18177
|
baseUrl: getBazarrApiBaseUrl(this.clientConfig.getBaseUrl()),
|
|
17356
|
-
headers: this.clientConfig
|
|
18178
|
+
headers: getBazarrHeaders(this.clientConfig),
|
|
18179
|
+
auth: this.clientConfig.config.apiKey
|
|
17357
18180
|
});
|
|
17358
18181
|
return this.clientConfig.config;
|
|
17359
18182
|
}
|
|
@@ -17995,8 +18818,8 @@ var init_completions = __esm(() => {
|
|
|
17995
18818
|
|
|
17996
18819
|
// src/cli/index.ts
|
|
17997
18820
|
init_dist();
|
|
17998
|
-
import { readFileSync as
|
|
17999
|
-
var { version } = JSON.parse(
|
|
18821
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
18822
|
+
var { version } = JSON.parse(readFileSync7(new URL("../../package.json", import.meta.url), "utf-8"));
|
|
18000
18823
|
var main = defineCommand({
|
|
18001
18824
|
meta: {
|
|
18002
18825
|
name: "tsarr",
|