fix: Tdarr widget empty statistics tab (#2883)

Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
This commit is contained in:
rezstje
2025-04-16 20:34:06 +02:00
committed by GitHub
parent 00053bda7b
commit 2d12c1e641
4 changed files with 60 additions and 78 deletions

View File

@@ -4,6 +4,7 @@ export interface TdarrPieSegment {
}
export interface TdarrStatistics {
libraryName: string;
totalFileCount: number;
totalTranscodeCount: number;
totalHealthCheckCount: number;
@@ -11,19 +12,12 @@ export interface TdarrStatistics {
failedHealthCheckCount: number;
stagedTranscodeCount: number;
stagedHealthCheckCount: number;
pies: {
libraryName: string;
libraryId: string;
totalFiles: number;
totalTranscodes: number;
savedSpace: number;
totalHealthChecks: number;
transcodeStatus: TdarrPieSegment[];
healthCheckStatus: TdarrPieSegment[];
videoCodecs: TdarrPieSegment[];
videoContainers: TdarrPieSegment[];
videoResolutions: TdarrPieSegment[];
audioCodecs: TdarrPieSegment[];
audioContainers: TdarrPieSegment[];
}[];
totalSavedSpace: number;
transcodeStatus: TdarrPieSegment[];
healthCheckStatus: TdarrPieSegment[];
videoCodecs: TdarrPieSegment[];
videoContainers: TdarrPieSegment[];
videoResolutions: TdarrPieSegment[];
audioCodecs: TdarrPieSegment[];
audioContainers: TdarrPieSegment[];
}

View File

@@ -20,15 +20,13 @@ export class TdarrIntegration extends Integration {
}
public async getStatisticsAsync(): Promise<TdarrStatistics> {
const url = this.url("/api/v2/cruddb");
const url = this.url("/api/v2/stats/get-pies");
const response = await fetchWithTrustedCertificatesAsync(url, {
method: "POST",
headers: { "content-type": "application/json" },
headers: { accept: "application/json", "Content-Type": "application/json" },
body: JSON.stringify({
data: {
collection: "StatisticsJSONDB",
mode: "getById",
docID: "statistics",
libraryId: "", // empty string to get all libraries
},
}),
});
@@ -36,28 +34,29 @@ export class TdarrIntegration extends Integration {
const statisticsData = await getStatisticsSchema.parseAsync(await response.json());
return {
totalFileCount: statisticsData.totalFileCount,
totalTranscodeCount: statisticsData.totalTranscodeCount,
totalHealthCheckCount: statisticsData.totalHealthCheckCount,
failedTranscodeCount: statisticsData.table3Count,
failedHealthCheckCount: statisticsData.table6Count,
stagedTranscodeCount: statisticsData.table1Count,
stagedHealthCheckCount: statisticsData.table4Count,
pies: statisticsData.pies.map((pie) => ({
libraryName: pie[0],
libraryId: pie[1],
totalFiles: pie[2],
totalTranscodes: pie[3],
savedSpace: pie[4] * 1_000_000_000, // file_size is in GB, convert to bytes,
totalHealthChecks: pie[5],
transcodeStatus: pie[6],
healthCheckStatus: pie[7],
videoCodecs: pie[8],
videoContainers: pie[9],
videoResolutions: pie[10],
audioCodecs: pie[11],
audioContainers: pie[12],
})),
libraryName: "All",
totalFileCount: statisticsData.pieStats.totalFiles,
totalTranscodeCount: statisticsData.pieStats.totalTranscodeCount,
totalHealthCheckCount: statisticsData.pieStats.totalHealthCheckCount,
// The Tdarr API only returns a category if there is at least one item in it
failedTranscodeCount:
statisticsData.pieStats.status.transcode.find((transcode) => transcode.name === "Transcode error")?.value ?? 0,
failedHealthCheckCount:
statisticsData.pieStats.status.healthcheck.find((healthcheck) => healthcheck.name === "Error")?.value ?? 0,
stagedTranscodeCount:
statisticsData.pieStats.status.transcode.find((transcode) => transcode.name === "Transcode success")?.value ??
0,
stagedHealthCheckCount:
statisticsData.pieStats.status.healthcheck.find((healthcheck) => healthcheck.name === "Queued")?.value ?? 0,
totalSavedSpace: statisticsData.pieStats.sizeDiff * 1_000_000_000, // sizeDiff is in GB, convert to bytes
transcodeStatus: statisticsData.pieStats.status.transcode,
healthCheckStatus: statisticsData.pieStats.status.healthcheck,
videoCodecs: statisticsData.pieStats.video.codecs,
videoContainers: statisticsData.pieStats.video.containers,
videoResolutions: statisticsData.pieStats.video.resolutions,
audioCodecs: statisticsData.pieStats.audio.codecs,
audioContainers: statisticsData.pieStats.audio.containers,
};
}
@@ -124,7 +123,7 @@ export class TdarrIntegration extends Integration {
healthCheck: item.HealthCheck,
transcode: item.TranscodeDecisionMaker,
filePath: item.file,
fileSize: item.file_size * 1_000_000, // file_size is in MB, convert to bytes
fileSize: Math.floor(item.file_size * 1_000_000), // file_size is in MB, convert to bytes, floor because it returns as float
container: item.container,
codec: item.video_codec_name,
resolution: item.video_resolution,
@@ -162,7 +161,7 @@ export class TdarrIntegration extends Integration {
healthCheck: item.HealthCheck,
transcode: item.TranscodeDecisionMaker,
filePath: item.file,
fileSize: item.file_size * 1_000_000, // file_size is in MB, convert to bytes
fileSize: Math.floor(item.file_size * 1_000_000), // file_size is in MB, convert to bytes, floor because it returns as float
container: item.container,
codec: item.video_codec_name,
resolution: item.video_resolution,

View File

@@ -1,72 +1,60 @@
import { z } from "zod";
export const getStatisticsSchema = z.object({
totalFileCount: z.number(),
totalTranscodeCount: z.number(),
totalHealthCheckCount: z.number(),
table3Count: z.number(),
table6Count: z.number(),
table1Count: z.number(),
table4Count: z.number(),
pies: z.array(
z.tuple([
z.string(), // Library Name
z.string(), // Library ID
z.number(), // File count
z.number(), // Number of transcodes
z.number(), // Space saved (in GB)
z.number(), // Number of health checks
z.array(
pieStats: z.object({
totalFiles: z.number(),
totalTranscodeCount: z.number(),
sizeDiff: z.number(),
totalHealthCheckCount: z.number(),
status: z.object({
transcode: z.array(
z.object({
// Transcode Status (Pie segments)
name: z.string(),
value: z.number(),
}),
),
z.array(
healthcheck: z.array(
z.object({
// Health Status (Pie segments)
name: z.string(),
value: z.number(),
}),
),
z.array(
}),
video: z.object({
codecs: z.array(
z.object({
// Video files - Codecs (Pie segments)
name: z.string(),
value: z.number(),
}),
),
z.array(
containers: z.array(
z.object({
// Video files - Containers (Pie segments)
name: z.string(),
value: z.number(),
}),
),
z.array(
resolutions: z.array(
z.object({
// Video files - Resolutions (Pie segments)
name: z.string(),
value: z.number(),
}),
),
z.array(
}),
audio: z.object({
codecs: z.array(
z.object({
// Audio files - Codecs (Pie segments)
name: z.string(),
value: z.number(),
}),
),
z.array(
containers: z.array(
z.object({
// Audio files - Containers (Pie segments)
name: z.string(),
value: z.number(),
}),
),
]),
),
}),
}),
});
export const getNodesResponseSchema = z.record(

View File

@@ -17,9 +17,10 @@ interface StatisticsPanelProps {
export function StatisticsPanel(props: StatisticsPanelProps) {
const t = useI18n("widget.mediaTranscoding.panel.statistics");
const allLibs = props.statistics.pies.find((pie) => pie.libraryName === "All");
const allLibs = props.statistics;
if (!allLibs) {
// Check if Tdarr hs any Files
if (!(allLibs.totalFileCount > 0)) {
return (
<Center style={{ flex: "1" }}>
<Title order={6}>{t("empty")}</Title>
@@ -40,7 +41,7 @@ export function StatisticsPanel(props: StatisticsPanelProps) {
<StatisticItem
icon={IconDatabaseHeart}
label={t("savedSpace")}
value={humanFileSize(Math.floor(allLibs.savedSpace))}
value={humanFileSize(Math.floor(allLibs.totalSavedSpace))}
/>
</Group>
<Group justify="center" wrap="wrap" grow>