fix: Tdarr widget empty statistics tab (#2883)
Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@ export interface TdarrPieSegment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TdarrStatistics {
|
export interface TdarrStatistics {
|
||||||
|
libraryName: string;
|
||||||
totalFileCount: number;
|
totalFileCount: number;
|
||||||
totalTranscodeCount: number;
|
totalTranscodeCount: number;
|
||||||
totalHealthCheckCount: number;
|
totalHealthCheckCount: number;
|
||||||
@@ -11,19 +12,12 @@ export interface TdarrStatistics {
|
|||||||
failedHealthCheckCount: number;
|
failedHealthCheckCount: number;
|
||||||
stagedTranscodeCount: number;
|
stagedTranscodeCount: number;
|
||||||
stagedHealthCheckCount: number;
|
stagedHealthCheckCount: number;
|
||||||
pies: {
|
totalSavedSpace: number;
|
||||||
libraryName: string;
|
transcodeStatus: TdarrPieSegment[];
|
||||||
libraryId: string;
|
healthCheckStatus: TdarrPieSegment[];
|
||||||
totalFiles: number;
|
videoCodecs: TdarrPieSegment[];
|
||||||
totalTranscodes: number;
|
videoContainers: TdarrPieSegment[];
|
||||||
savedSpace: number;
|
videoResolutions: TdarrPieSegment[];
|
||||||
totalHealthChecks: number;
|
audioCodecs: TdarrPieSegment[];
|
||||||
transcodeStatus: TdarrPieSegment[];
|
audioContainers: TdarrPieSegment[];
|
||||||
healthCheckStatus: TdarrPieSegment[];
|
|
||||||
videoCodecs: TdarrPieSegment[];
|
|
||||||
videoContainers: TdarrPieSegment[];
|
|
||||||
videoResolutions: TdarrPieSegment[];
|
|
||||||
audioCodecs: TdarrPieSegment[];
|
|
||||||
audioContainers: TdarrPieSegment[];
|
|
||||||
}[];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,13 @@ export class TdarrIntegration extends Integration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getStatisticsAsync(): Promise<TdarrStatistics> {
|
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, {
|
const response = await fetchWithTrustedCertificatesAsync(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "content-type": "application/json" },
|
headers: { accept: "application/json", "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
data: {
|
data: {
|
||||||
collection: "StatisticsJSONDB",
|
libraryId: "", // empty string to get all libraries
|
||||||
mode: "getById",
|
|
||||||
docID: "statistics",
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -36,28 +34,29 @@ export class TdarrIntegration extends Integration {
|
|||||||
const statisticsData = await getStatisticsSchema.parseAsync(await response.json());
|
const statisticsData = await getStatisticsSchema.parseAsync(await response.json());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalFileCount: statisticsData.totalFileCount,
|
libraryName: "All",
|
||||||
totalTranscodeCount: statisticsData.totalTranscodeCount,
|
totalFileCount: statisticsData.pieStats.totalFiles,
|
||||||
totalHealthCheckCount: statisticsData.totalHealthCheckCount,
|
totalTranscodeCount: statisticsData.pieStats.totalTranscodeCount,
|
||||||
failedTranscodeCount: statisticsData.table3Count,
|
totalHealthCheckCount: statisticsData.pieStats.totalHealthCheckCount,
|
||||||
failedHealthCheckCount: statisticsData.table6Count,
|
// The Tdarr API only returns a category if there is at least one item in it
|
||||||
stagedTranscodeCount: statisticsData.table1Count,
|
failedTranscodeCount:
|
||||||
stagedHealthCheckCount: statisticsData.table4Count,
|
statisticsData.pieStats.status.transcode.find((transcode) => transcode.name === "Transcode error")?.value ?? 0,
|
||||||
pies: statisticsData.pies.map((pie) => ({
|
failedHealthCheckCount:
|
||||||
libraryName: pie[0],
|
statisticsData.pieStats.status.healthcheck.find((healthcheck) => healthcheck.name === "Error")?.value ?? 0,
|
||||||
libraryId: pie[1],
|
stagedTranscodeCount:
|
||||||
totalFiles: pie[2],
|
statisticsData.pieStats.status.transcode.find((transcode) => transcode.name === "Transcode success")?.value ??
|
||||||
totalTranscodes: pie[3],
|
0,
|
||||||
savedSpace: pie[4] * 1_000_000_000, // file_size is in GB, convert to bytes,
|
stagedHealthCheckCount:
|
||||||
totalHealthChecks: pie[5],
|
statisticsData.pieStats.status.healthcheck.find((healthcheck) => healthcheck.name === "Queued")?.value ?? 0,
|
||||||
transcodeStatus: pie[6],
|
|
||||||
healthCheckStatus: pie[7],
|
totalSavedSpace: statisticsData.pieStats.sizeDiff * 1_000_000_000, // sizeDiff is in GB, convert to bytes
|
||||||
videoCodecs: pie[8],
|
transcodeStatus: statisticsData.pieStats.status.transcode,
|
||||||
videoContainers: pie[9],
|
healthCheckStatus: statisticsData.pieStats.status.healthcheck,
|
||||||
videoResolutions: pie[10],
|
videoCodecs: statisticsData.pieStats.video.codecs,
|
||||||
audioCodecs: pie[11],
|
videoContainers: statisticsData.pieStats.video.containers,
|
||||||
audioContainers: pie[12],
|
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,
|
healthCheck: item.HealthCheck,
|
||||||
transcode: item.TranscodeDecisionMaker,
|
transcode: item.TranscodeDecisionMaker,
|
||||||
filePath: item.file,
|
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,
|
container: item.container,
|
||||||
codec: item.video_codec_name,
|
codec: item.video_codec_name,
|
||||||
resolution: item.video_resolution,
|
resolution: item.video_resolution,
|
||||||
@@ -162,7 +161,7 @@ export class TdarrIntegration extends Integration {
|
|||||||
healthCheck: item.HealthCheck,
|
healthCheck: item.HealthCheck,
|
||||||
transcode: item.TranscodeDecisionMaker,
|
transcode: item.TranscodeDecisionMaker,
|
||||||
filePath: item.file,
|
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,
|
container: item.container,
|
||||||
codec: item.video_codec_name,
|
codec: item.video_codec_name,
|
||||||
resolution: item.video_resolution,
|
resolution: item.video_resolution,
|
||||||
|
|||||||
@@ -1,72 +1,60 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const getStatisticsSchema = z.object({
|
export const getStatisticsSchema = z.object({
|
||||||
totalFileCount: z.number(),
|
pieStats: z.object({
|
||||||
totalTranscodeCount: z.number(),
|
totalFiles: z.number(),
|
||||||
totalHealthCheckCount: z.number(),
|
totalTranscodeCount: z.number(),
|
||||||
table3Count: z.number(),
|
sizeDiff: z.number(),
|
||||||
table6Count: z.number(),
|
totalHealthCheckCount: z.number(),
|
||||||
table1Count: z.number(),
|
status: z.object({
|
||||||
table4Count: z.number(),
|
transcode: z.array(
|
||||||
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(
|
|
||||||
z.object({
|
z.object({
|
||||||
// Transcode Status (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
z.array(
|
healthcheck: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
// Health Status (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
z.array(
|
}),
|
||||||
|
video: z.object({
|
||||||
|
codecs: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
// Video files - Codecs (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
z.array(
|
containers: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
// Video files - Containers (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
z.array(
|
resolutions: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
// Video files - Resolutions (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
z.array(
|
}),
|
||||||
|
audio: z.object({
|
||||||
|
codecs: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
// Audio files - Codecs (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
z.array(
|
containers: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
// Audio files - Containers (Pie segments)
|
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
]),
|
}),
|
||||||
),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getNodesResponseSchema = z.record(
|
export const getNodesResponseSchema = z.record(
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ interface StatisticsPanelProps {
|
|||||||
export function StatisticsPanel(props: StatisticsPanelProps) {
|
export function StatisticsPanel(props: StatisticsPanelProps) {
|
||||||
const t = useI18n("widget.mediaTranscoding.panel.statistics");
|
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 (
|
return (
|
||||||
<Center style={{ flex: "1" }}>
|
<Center style={{ flex: "1" }}>
|
||||||
<Title order={6}>{t("empty")}</Title>
|
<Title order={6}>{t("empty")}</Title>
|
||||||
@@ -40,7 +41,7 @@ export function StatisticsPanel(props: StatisticsPanelProps) {
|
|||||||
<StatisticItem
|
<StatisticItem
|
||||||
icon={IconDatabaseHeart}
|
icon={IconDatabaseHeart}
|
||||||
label={t("savedSpace")}
|
label={t("savedSpace")}
|
||||||
value={humanFileSize(Math.floor(allLibs.savedSpace))}
|
value={humanFileSize(Math.floor(allLibs.totalSavedSpace))}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group justify="center" wrap="wrap" grow>
|
<Group justify="center" wrap="wrap" grow>
|
||||||
|
|||||||
Reference in New Issue
Block a user