Files
songs2vid/lib/types.ts
T
Atakan Doğan ÖzbanandCursor 925aadae75 Strip Songs2VID to a payment-free self-hosted OSS core.
Remove Stripe/billing/pricing/marketing, simplify schema and entitlements for unlimited self-host use, and keep auth, encode, and YouTube upload.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 06:52:00 +02:00

108 lines
2.8 KiB
TypeScript

import { Privacy } from "@prisma/client";
import type { LayoutSettings } from "./layout";
import type { WatermarkSettings } from "./watermark";
export type ItemMetadata = {
title: string;
description: string;
tags: string;
privacy: Privacy;
categoryId: string;
resolution: string;
notifySubscribers: boolean;
madeForKids: boolean;
embeddable: boolean;
creativeCommons: boolean;
/** Legacy toggle — default Songs2VID branding when watermark.mode is omitted. */
includeWatermark: boolean;
/** YouTube playlist ID. Video is added after upload. */
playlistId?: string | null;
/**
* Optional per-item cover image path.
* When omitted, the job-level shared imagePath is used.
*/
imagePath?: string | null;
/** Custom branding watermark settings. */
watermark?: Partial<WatermarkSettings> | null;
/** Artist line for art-track layouts (on-video only). */
artist?: string | null;
/** Song / track title burned into art-track layouts (on-video only). */
songTitle?: string | null;
/**
* Art-track layout. Prefer camelCase; snake_case aliases accepted:
* layout_template, blur_amount, text_padding.
*/
layout?: Partial<LayoutSettings> & {
layoutTemplate?: string | null;
layout_template?: string | null;
blur_amount?: number;
blur_opacity?: number;
text_padding?: number;
title_artist_gap?: number;
text_offset_x?: number;
text_offset_y?: number;
} | null;
/** Flat aliases (also accepted). */
layoutTemplate?: string | null;
layout_template?: string | null;
blurAmount?: number;
blur_amount?: number;
blurOpacity?: number;
blur_opacity?: number;
textPadding?: number;
text_padding?: number;
titleArtistGap?: number;
title_artist_gap?: number;
textOffsetX?: number;
text_offset_x?: number;
textOffsetY?: number;
text_offset_y?: number;
};
export type UploadedAudio = {
path: string;
filename: string;
metadata: ItemMetadata;
};
export type CreatePlaylistRequest = {
title: string;
description?: string;
privacy?: "public" | "unlisted" | "private";
};
export type CreateJobPayload = {
/** Shared cover for Free / default when items omit imagePath. */
imagePath: string;
items: Array<{
audioPath: string;
audioFilename: string;
metadata: ItemMetadata;
}>;
/** Create a new playlist and attach its ID to every item (Pro). */
createPlaylist?: CreatePlaylistRequest | null;
};
export type JobItemResponse = {
id: string;
audioFilename: string;
title: string;
status: string;
youtubeVideoId: string | null;
error: string | null;
};
export type JobResponse = {
id: string;
status: string;
createdAt: string;
completedAt: string | null;
items: JobItemResponse[];
};
export type VideoJobData = {
jobItemId: string;
userId: string;
jobId: string;
};