Files
erika/db/schema/video.ts

118 lines
2.9 KiB
TypeScript

import {
index,
bigint,
integer,
jsonb,
pgTable,
text,
timestamp,
} from "drizzle-orm/pg-core";
import { uuidv7 } from "uuidv7";
export type VideoUploadStatus =
| "draft"
| "scheduled"
| "processing"
| "completed"
| "partial"
| "failed";
export type VideoPlatform = "youtube" | "tiktok";
export type VideoJobStatus = "pending" | "processing" | "completed" | "failed";
export const videoUploads = pgTable(
"video_upload",
{
id: text("id")
.primaryKey()
.$defaultFn(() => uuidv7()),
title: text("title").notNull(),
description: text("description").notNull().default(""),
videoPath: text("video_path").notNull(),
thumbnailPath: text("thumbnail_path"),
originalFilename: text("original_filename").notNull(),
mimeType: text("mime_type").notNull(),
size: bigint("size", { mode: "number" }).notNull(),
scheduledAt: timestamp("scheduled_at", {
mode: "date",
withTimezone: true,
}),
status: text("status")
.$type<VideoUploadStatus>()
.notNull()
.default("draft"),
youtubeSettings: jsonb("youtube_settings")
.$type<YoutubeSettings>()
.notNull()
.default({}),
tiktokSettings: jsonb("tiktok_settings")
.$type<TiktokSettings>()
.notNull()
.default({}),
createdByDiscordId: text("created_by_discord_id").notNull(),
createdAt: timestamp("created_at", { mode: "date", withTimezone: true })
.defaultNow()
.notNull(),
updatedAt: timestamp("updated_at", { mode: "date", withTimezone: true })
.defaultNow()
.notNull(),
},
(table) => [
index("video_upload_status_scheduled_idx").on(
table.status,
table.scheduledAt,
),
],
);
export const videoUploadJobs = pgTable(
"video_upload_job",
{
id: text("id")
.primaryKey()
.$defaultFn(() => uuidv7()),
uploadId: text("upload_id")
.notNull()
.references(() => videoUploads.id, { onDelete: "cascade" }),
platform: text("platform").$type<VideoPlatform>().notNull(),
status: text("status").$type<VideoJobStatus>().notNull().default("pending"),
externalId: text("external_id"),
externalUrl: text("external_url"),
error: text("error"),
attempts: integer("attempts").notNull().default(0),
startedAt: timestamp("started_at", { mode: "date", withTimezone: true }),
completedAt: timestamp("completed_at", {
mode: "date",
withTimezone: true,
}),
createdAt: timestamp("created_at", { mode: "date", withTimezone: true })
.defaultNow()
.notNull(),
},
(table) => [
index("video_upload_job_upload_platform_idx").on(
table.uploadId,
table.platform,
),
],
);
export type YoutubeSettings = {
tags?: string[];
categoryId?: string;
privacyStatus?: "public" | "private" | "unlisted";
license?: "youtube" | "creativeCommon";
madeForKids?: boolean;
containsSyntheticMedia?: boolean;
};
export type TiktokSettings = {
privacyLevel?: string;
disableComment?: boolean;
disableDuet?: boolean;
disableStitch?: boolean;
coverTimestampMs?: number;
brandContentToggle?: boolean;
brandOrganicToggle?: boolean;
isAigc?: boolean;
};