Each gains _lookup (the metadata source, by title or by id), _add (by TMDb, TVDb or MusicBrainz id, with the first quality/metadata profile and root folder unless named, monitored, searching only when asked) and _remove (by the app's id, files kept unless asked).
116 lines
4.9 KiB
TypeScript
116 lines
4.9 KiB
TypeScript
// lidarr's tools — ported from the shared hal sdk (novox/hq ADR 0039), importing lidarr's own
|
|
// client. They return structured data (not pre-formatted text as hal did); the mesh serves them
|
|
// through the sdk's tool harness.
|
|
|
|
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
|
|
import { LidarrClient } from "../client.js";
|
|
|
|
export function getLidarrTools(lidarr: LidarrClient): ToolDefinition[] {
|
|
return [
|
|
{
|
|
name: "lidarr_status",
|
|
description: "Lidarr status overview: version, artist count, monitored count, queue size.",
|
|
input: {},
|
|
run: async () => {
|
|
const [status, content, queue] = await Promise.all([
|
|
lidarr.getStatus(),
|
|
lidarr.getContent(),
|
|
lidarr.getQueue(),
|
|
]);
|
|
return {
|
|
app: status.appName,
|
|
version: status.version,
|
|
artists: content.length,
|
|
monitored: content.filter((c) => c.monitored).length,
|
|
queue: queue.totalRecords,
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: "lidarr_library",
|
|
description: "List artists from the Lidarr library.",
|
|
input: { limit: { type: "number", description: "max items to return (default 50)" } },
|
|
run: async (args) => {
|
|
const items = await lidarr.getContent(args.limit ? Number(args.limit) : 50);
|
|
return { count: items.length, artists: items };
|
|
},
|
|
},
|
|
{
|
|
name: "lidarr_search",
|
|
description: "Search the Lidarr library for artists by name (filters existing content, not indexers).",
|
|
input: { query: { type: "string", description: "the search term" } },
|
|
run: async (args) => {
|
|
const query = String(args.query);
|
|
return { query, results: await lidarr.searchContent(query) };
|
|
},
|
|
},
|
|
{
|
|
name: "lidarr_queue",
|
|
description: "Show the Lidarr download queue — what is downloading and how far along.",
|
|
input: {},
|
|
run: async () => {
|
|
const queue = await lidarr.getQueue();
|
|
return { count: queue.totalRecords, items: queue.items };
|
|
},
|
|
},
|
|
{
|
|
name: "lidarr_calendar",
|
|
description: "Upcoming album releases from the Lidarr calendar.",
|
|
input: { days: { type: "number", description: "how many days to look ahead (default 7)" } },
|
|
run: async (args) => {
|
|
const days = args.days ? Number(args.days) : 7;
|
|
const items = await lidarr.getCalendar(days);
|
|
items.sort((a, b) => a.date.localeCompare(b.date));
|
|
return { days, count: items.length, items };
|
|
},
|
|
},
|
|
{
|
|
name: "lidarr_lookup",
|
|
description: "Look a artist up outside the library, on Lidarr's metadata source: title, year, MusicBrainz artist id and whether it is already in the library.",
|
|
input: { query: { type: "string", description: "a title, or `lidarr:<id>`" } },
|
|
run: async (args) => {
|
|
const query = String(args.query);
|
|
return { query, results: await lidarr.lookup(query) };
|
|
},
|
|
},
|
|
{
|
|
name: "lidarr_add",
|
|
description: "Add a artist to Lidarr by its MusicBrainz artist id (from lidarr_lookup). Uses the first quality and metadata profile and root folder unless named. Does not search the indexers unless `search` is true.",
|
|
input: {
|
|
id: { type: "string", description: "the MusicBrainz artist id" },
|
|
qualityProfile: { type: "string", description: "a quality profile's name (default: the first)" },
|
|
metadataProfile: { type: "string", description: "a metadata profile's name (default: the first)" },
|
|
rootFolder: { type: "string", description: "a root folder path (default: the first)" },
|
|
monitored: { type: "boolean", description: "monitor it (default true)" },
|
|
search: { type: "boolean", description: "search the indexers right away (default false)" },
|
|
},
|
|
run: async (args) => lidarr.add(String(args.id), {
|
|
qualityProfile: args.qualityProfile ? String(args.qualityProfile) : undefined,
|
|
metadataProfile: args.metadataProfile ? String(args.metadataProfile) : undefined,
|
|
rootFolder: args.rootFolder ? String(args.rootFolder) : undefined,
|
|
monitored: args.monitored === undefined ? undefined : Boolean(args.monitored),
|
|
search: Boolean(args.search),
|
|
}),
|
|
},
|
|
{
|
|
name: "lidarr_remove",
|
|
description: "Remove a artist from Lidarr's library by its Lidarr id. Files stay on disk unless `deleteFiles` is true.",
|
|
input: {
|
|
id: { type: "number", description: "the Lidarr id of the artist" },
|
|
deleteFiles: { type: "boolean", description: "also delete its files (default false)" },
|
|
},
|
|
run: async (args) => lidarr.remove(Number(args.id), Boolean(args.deleteFiles)),
|
|
},
|
|
];
|
|
}
|
|
|
|
// The tools exist only when Lidarr is configured; without a URL and key, lidarr contributes none
|
|
// rather than failing the whole runtime.
|
|
registerModuleTools("lidarr", (env) => {
|
|
try {
|
|
return getLidarrTools(LidarrClient.fromEnv(env));
|
|
} catch {
|
|
return [];
|
|
}
|
|
});
|