Files
k-tv/k-tv-frontend/lib/schemas.ts

89 lines
2.7 KiB
TypeScript

import { z } from "zod";
import { WEEKDAYS } from "@/lib/types";
import type { Weekday } from "@/lib/types";
const weekdaySchema = z.enum([
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
]);
export const mediaFilterSchema = z.object({
content_type: z.enum(["movie", "episode", "short"]).nullable().optional(),
genres: z.array(z.string()),
decade: z
.number()
.int()
.min(1900, "Decade must be ≥ 1900")
.max(2099, "Decade must be ≤ 2090")
.nullable()
.optional(),
tags: z.array(z.string()),
min_duration_secs: z.number().min(0, "Must be ≥ 0").nullable().optional(),
max_duration_secs: z.number().min(0, "Must be ≥ 0").nullable().optional(),
collections: z.array(z.string()),
series_names: z.array(z.string()),
search_term: z.string().nullable().optional(),
});
export const accessModeSchema = z.enum([
"public",
"password_protected",
"account_required",
"owner_only",
]);
export const blockSchema = z.object({
id: z.string(),
name: z.string().min(1, "Block name is required"),
start_time: z.string(),
duration_mins: z.number().int().min(1, "Must be at least 1 minute"),
content: z.discriminatedUnion("type", [
z.object({
type: z.literal("algorithmic"),
filter: mediaFilterSchema,
strategy: z.enum(["best_fit", "sequential", "random"]),
provider_id: z.string().optional(),
}),
z.object({
type: z.literal("manual"),
items: z.array(z.string()),
provider_id: z.string().optional(),
}),
]),
loop_on_finish: z.boolean().optional(),
ignore_recycle_policy: z.boolean().optional(),
access_mode: accessModeSchema.optional(),
access_password: z.string().optional(),
});
export const channelFormSchema = z.object({
name: z.string().min(1, "Name is required"),
timezone: z.string().min(1, "Timezone is required"),
description: z.string().optional(),
day_blocks: z.record(weekdaySchema, z.array(blockSchema))
.default(() =>
Object.fromEntries(WEEKDAYS.map(d => [d, []])) as unknown as Record<Weekday, z.infer<typeof blockSchema>[]>
),
recycle_policy: z.object({
cooldown_days: z.number().int().min(0).nullable().optional(),
cooldown_generations: z.number().int().min(0).nullable().optional(),
min_available_ratio: z
.number()
.min(0, "Must be ≥ 0")
.max(1, "Must be ≤ 1"),
}),
auto_schedule: z.boolean(),
access_mode: accessModeSchema.optional(),
access_password: z.string().optional(),
});
export type FieldErrors = Record<string, string | undefined>;
export function extractErrors(err: z.ZodError): FieldErrors {
const map: FieldErrors = {};
for (const issue of err.issues) {
const key = issue.path.join(".");
if (!map[key]) map[key] = issue.message;
}
return map;
}