Align preview typography with FFmpeg output, add video/song title split, and ship OSS updates.
Separate YouTube video titles from on-video song/artist fields with Pro gating, serve curated fonts and watermark assets for 1:1 preview parity, and include billing/API/docs/deploy stack for self-hosted release. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
682020ff5a
commit
c8015937f9
+108
-10
@@ -34,17 +34,82 @@ enum JobItemStatus {
|
||||
FAILED
|
||||
}
|
||||
|
||||
enum QuotaExtensionRequestStatus {
|
||||
PENDING
|
||||
APPROVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
enum QuotaExtensionKind {
|
||||
VIDEO_QUOTA
|
||||
API_RATE_LIMIT
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
name String?
|
||||
image String?
|
||||
plan Plan @default(FREE)
|
||||
videosUsed Int @default(0)
|
||||
quotaResetAt DateTime
|
||||
youtubeConnection YouTubeConnection?
|
||||
jobs Job[]
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
name String?
|
||||
image String?
|
||||
/// FREE = free tier; PREMIUM = Pro (€5/mo, formerly starter_5eur)
|
||||
plan Plan @default(FREE)
|
||||
/// Credits consumed in the current billing cycle (credits_used)
|
||||
videosUsed Int @default(0)
|
||||
/// Monthly allocation for the current cycle (10 free / 50 pro)
|
||||
monthlyCredits Int @default(10)
|
||||
quotaResetAt DateTime
|
||||
cardLast4 String?
|
||||
subscribedAt DateTime?
|
||||
bonusQuota Int @default(0)
|
||||
apiRateLimitBonus Int @default(0)
|
||||
/// Purchased extras that never expire (maps to legacy "videoCredits" column)
|
||||
extraCredits Int @default(0) @map("videoCredits")
|
||||
/// Free-tier one-time +15 top-up already purchased
|
||||
freeTopUpPurchased Boolean @default(false)
|
||||
stripeCustomerId String?
|
||||
stripeSubscriptionId String?
|
||||
apiKeyHash String? @unique
|
||||
apiKeyPrefix String?
|
||||
youtubeConnection YouTubeConnection?
|
||||
jobs Job[]
|
||||
quotaExtensionRequests QuotaExtensionRequest[]
|
||||
creditPurchases CreditPurchase[]
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
enum CreditPurchaseStatus {
|
||||
PENDING
|
||||
COMPLETED
|
||||
FAILED
|
||||
}
|
||||
|
||||
model CreditPurchase {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
credits Int
|
||||
amountCents Int
|
||||
status CreditPurchaseStatus @default(PENDING)
|
||||
stripeSessionId String? @unique
|
||||
stripePaymentIntentId String?
|
||||
createdAt DateTime @default(now())
|
||||
completedAt DateTime?
|
||||
}
|
||||
|
||||
enum JobItemBilling {
|
||||
QUOTA
|
||||
CREDIT
|
||||
}
|
||||
|
||||
model QuotaExtensionRequest {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
kind QuotaExtensionKind @default(VIDEO_QUOTA)
|
||||
status QuotaExtensionRequestStatus @default(PENDING)
|
||||
message String @default("")
|
||||
requestedAt DateTime @default(now())
|
||||
processedAt DateTime?
|
||||
adminNote String?
|
||||
}
|
||||
|
||||
model YouTubeConnection {
|
||||
@@ -86,6 +151,39 @@ model JobItem {
|
||||
embeddable Boolean @default(true)
|
||||
creativeCommons Boolean @default(false)
|
||||
includeWatermark Boolean @default(true)
|
||||
/// Optional per-item cover (Pro). Falls back to Job.imagePath when null.
|
||||
itemImagePath String?
|
||||
/// none | default | text | logo custom modes require Pro
|
||||
watermarkMode String @default("default")
|
||||
watermarkText String?
|
||||
watermarkLogoPath String?
|
||||
/// curated key | custom | system
|
||||
watermarkFontKey String?
|
||||
/// uploaded .ttf/.otf when fontKey=custom
|
||||
watermarkFontPath String?
|
||||
/// top-left | top-right | bottom-left | bottom-right | center
|
||||
watermarkPosition String @default("bottom-right")
|
||||
watermarkOffsetX Int @default(20)
|
||||
watermarkOffsetY Int @default(20)
|
||||
/// Optional artist line for art-track layouts (Pro, on-video only)
|
||||
artist String?
|
||||
/// Song title burned into art-track layouts (Pro, on-video only)
|
||||
songTitle String?
|
||||
/// COVER_LEFT_TEXT_RIGHT | COVER_TOP_TEXT_BOTTOM | COVER_RIGHT_TEXT_LEFT | CENTERED_COMPACT | null=classic
|
||||
layoutTemplate String?
|
||||
/// 0–100 Gaussian / boxblur intensity (Pro art-track)
|
||||
blurAmount Int @default(55)
|
||||
/// 0–100 visibility of blurred fill vs black
|
||||
blurOpacity Int @default(100)
|
||||
/// Padding around cover + text in art-track layouts
|
||||
textPadding Int @default(48)
|
||||
/// Extra gap between title and artist lines (px)
|
||||
titleArtistGap Int @default(10)
|
||||
/// Fine-tune text block within template (-120..120)
|
||||
textOffsetX Int @default(0)
|
||||
textOffsetY Int @default(0)
|
||||
playlistId String?
|
||||
billingSource JobItemBilling @default(QUOTA)
|
||||
status JobItemStatus @default(PENDING)
|
||||
outputPath String?
|
||||
youtubeVideoId String?
|
||||
|
||||
Reference in New Issue
Block a user