feat: add api-key support for tdarr (#2890)

Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
Jacob Hemming
2025-04-18 20:11:51 +02:00
committed by GitHub
parent cfca0ba583
commit 3d68f4d128
3 changed files with 51 additions and 18 deletions

View File

@@ -101,6 +101,18 @@ const getSecretKindOption = (kind: IntegrationKind, sourcedSecrets: SourcedInteg
); );
if (onlyFormSecretsKindOptions.length >= 1) { if (onlyFormSecretsKindOptions.length >= 1) {
// If the first option is no secret it would always be selected even if we want to have a secret
if (
onlyFormSecretsKindOptions.length >= 2 &&
onlyFormSecretsKindOptions.some((secretKinds) => secretKinds.length === 0)
) {
return (
// Will never be undefined because of the check above
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
onlyFormSecretsKindOptions.find((secretKinds) => secretKinds.length >= 1) ?? onlyFormSecretsKindOptions[0]!
);
}
// Will never be undefined because of the check above // Will never be undefined because of the check above
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return onlyFormSecretsKindOptions[0]!; return onlyFormSecretsKindOptions[0]!;

View File

@@ -142,26 +142,26 @@ export const integrationDefs = {
dashDot: { dashDot: {
name: "Dash.", name: "Dash.",
secretKinds: [[]], secretKinds: [[]],
category: ["healthMonitoring"],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/dashdot.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/dashdot.png",
category: ["healthMonitoring"],
}, },
tdarr: { tdarr: {
name: "Tdarr", name: "Tdarr",
secretKinds: [[]], secretKinds: [[], ["apiKey"]],
category: ["mediaTranscoding"],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/tdarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/tdarr.png",
category: ["mediaTranscoding"],
}, },
proxmox: { proxmox: {
name: "Proxmox", name: "Proxmox",
secretKinds: [["username", "tokenId", "apiKey", "realm"]], secretKinds: [["username", "tokenId", "apiKey", "realm"]],
category: ["healthMonitoring"],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/proxmox.svg", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/proxmox.svg",
category: ["healthMonitoring"],
}, },
nextcloud: { nextcloud: {
name: "Nextcloud", name: "Nextcloud",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
category: ["calendar"],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/nextcloud.svg", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/nextcloud.svg",
category: ["calendar"],
}, },
unifiController: { unifiController: {
name: "Unifi Controller", name: "Unifi Controller",

View File

@@ -1,5 +1,3 @@
import { z } from "zod";
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
import { Integration } from "../base/integration"; import { Integration } from "../base/integration";
@@ -10,20 +8,31 @@ import { getNodesResponseSchema, getStatisticsSchema, getStatusTableSchema } fro
export class TdarrIntegration extends Integration { export class TdarrIntegration extends Integration {
public async testConnectionAsync(): Promise<void> { public async testConnectionAsync(): Promise<void> {
const url = this.url("/api/v2/status"); await super.handleTestConnectionResponseAsync({
const response = await fetchWithTrustedCertificatesAsync(url); queryFunctionAsync: async () => {
if (response.status !== 200) { return await fetchWithTrustedCertificatesAsync(this.url("/api/v2/is-server-alive"), {
throw new Error(`Unexpected status code: ${response.status}`); method: "POST",
} headers: {
accept: "application/json",
await z.object({ status: z.string() }).parseAsync(await response.json()); "X-Api-Key": super.hasSecretValue("apiKey") ? super.getSecretValue("apiKey") : "",
},
});
},
});
} }
public async getStatisticsAsync(): Promise<TdarrStatistics> { public async getStatisticsAsync(): Promise<TdarrStatistics> {
const url = this.url("/api/v2/stats/get-pies"); const url = this.url("/api/v2/stats/get-pies");
const headerParams = {
accept: "application/json",
"Content-Type": "application/json",
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
};
const response = await fetchWithTrustedCertificatesAsync(url, { const response = await fetchWithTrustedCertificatesAsync(url, {
method: "POST", method: "POST",
headers: { accept: "application/json", "Content-Type": "application/json" }, headers: headerParams,
body: JSON.stringify({ body: JSON.stringify({
data: { data: {
libraryId: "", // empty string to get all libraries libraryId: "", // empty string to get all libraries
@@ -62,9 +71,13 @@ export class TdarrIntegration extends Integration {
public async getWorkersAsync(): Promise<TdarrWorker[]> { public async getWorkersAsync(): Promise<TdarrWorker[]> {
const url = this.url("/api/v2/get-nodes"); const url = this.url("/api/v2/get-nodes");
const headerParams = {
"Content-Type": "application/json",
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
};
const response = await fetchWithTrustedCertificatesAsync(url, { const response = await fetchWithTrustedCertificatesAsync(url, {
method: "GET", method: "GET",
headers: { "content-type": "application/json" }, headers: headerParams,
}); });
const nodesData = await getNodesResponseSchema.parseAsync(await response.json()); const nodesData = await getNodesResponseSchema.parseAsync(await response.json());
@@ -102,9 +115,13 @@ export class TdarrIntegration extends Integration {
private async getTranscodingQueueAsync(firstItemIndex: number, pageSize: number) { private async getTranscodingQueueAsync(firstItemIndex: number, pageSize: number) {
const url = this.url("/api/v2/client/status-tables"); const url = this.url("/api/v2/client/status-tables");
const headerParams = {
"Content-Type": "application/json",
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
};
const response = await fetchWithTrustedCertificatesAsync(url, { const response = await fetchWithTrustedCertificatesAsync(url, {
method: "POST", method: "POST",
headers: { "content-type": "application/json" }, headers: headerParams,
body: JSON.stringify({ body: JSON.stringify({
data: { data: {
start: firstItemIndex, start: firstItemIndex,
@@ -137,9 +154,13 @@ export class TdarrIntegration extends Integration {
private async getHealthCheckDataAsync(firstItemIndex: number, pageSize: number, totalQueueCount: number) { private async getHealthCheckDataAsync(firstItemIndex: number, pageSize: number, totalQueueCount: number) {
const url = this.url("/api/v2/client/status-tables"); const url = this.url("/api/v2/client/status-tables");
const headerParams = {
"Content-Type": "application/json",
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
};
const response = await fetchWithTrustedCertificatesAsync(url, { const response = await fetchWithTrustedCertificatesAsync(url, {
method: "POST", method: "POST",
headers: { "content-type": "application/json" }, headers: headerParams,
body: JSON.stringify({ body: JSON.stringify({
data: { data: {
start: Math.max(firstItemIndex - totalQueueCount, 0), start: Math.max(firstItemIndex - totalQueueCount, 0),