147 lines
4.2 KiB
Markdown

# Media Models (Drizzle ORM)
## Overview
The Media module uses **Drizzle ORM** (separate from Prisma) to manage video library, compilations, and job queue.
**Models (3):**
- videos — Video library with metadata
- compilations — Video compilation tracking
- jobs — Job queue with resource management
**ORM:** Drizzle (not Prisma)
**API:** Fastify (port 4100, separate from Express main API)
**Migration:** `npx drizzle-kit push` (no migration files)
**Key Features:**
- FFprobe metadata extraction (duration, dimensions, orientation, quality, audio)
- Directory type enum (9 types: studios, gifs, private, inbox, curated, playback, compilations, videos, highlights)
- Public media engagement stats (historical)
- Job queue with GPU/CPU resource categories
- Video upload with automatic metadata extraction
See [Schema Reference](../schema.md#media-drizzle-orm) for complete field listings.
---
## Directory Types
```typescript
export const DIRECTORY_TYPES = [
'studios',
'gifs',
'private',
'inbox',
'curated',
'playback',
'compilations',
'videos',
'highlights'
] as const;
```
**Usage:**
- Efficient filtering (indexed)
- Replaces LIKE patterns (e.g., `path LIKE '%/studios/%'`)
---
## Video Metadata (FFprobe)
**Extracted Fields:**
- `durationSeconds` — Video duration in seconds
- `width` / `height` — Video dimensions (pixels)
- `orientation` — portrait, landscape, square
- `quality` — 1080p, 720p, 480p, etc.
- `hasAudio` — Audio track present flag
**Extraction Service:** `api/src/modules/media/services/ffprobe.service.ts`
**Timeout:** 30 seconds for metadata extraction
**Validation:** Decodes 5 frames with 60s timeout
---
## Job Queue
**Resource Categories:**
```typescript
export type ResourceCategory = 'gpu_ai' | 'gpu_encode' | 'cpu';
```
**Job Status:**
```typescript
export type JobStatus = 'pending' | 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
```
**Job Types (21 total):**
- compilation, scan, public_scan, organize, organize_studio
- reencode_streaming, compile_random, compile_quad, compile_quad_horizontal
- compile_triple_vertical, compile_mega, compile_gif, generate_gif
- fetch, digest, digest_generate, clip_generate, highlight_generate
- tag_generation, scene_extract, clip_extract_only, auto_organize_publish
**Queue Processing:**
- Ordered by: status (pending first), priority (lower = higher), createdAt (FIFO)
- Uses composite index: `[status, priority, createdAt]`
---
## Video Upload Flow
```mermaid
sequenceDiagram
participant Client
participant API
participant FFprobe
participant DB
Client->>API: POST /api/media/upload (multipart/form-data)
API->>API: Stream file to /media/local/inbox
API->>FFprobe: Extract metadata (duration, width, height, etc.)
FFprobe-->>API: metadata
API->>DB: INSERT INTO videos (path, filename, durationSeconds, ...)
DB-->>API: video record
API-->>Client: { id, path, metadata }
```
**Volume Mount:** `/media/local/inbox:rw` (read-write), library remains `:ro`
---
## Drizzle Schema Example
```typescript
export const videos = pgTable('videos', {
id: serial('id').primaryKey(),
path: text('path').notNull().unique(),
filename: text('filename').notNull(),
durationSeconds: integer('duration_seconds'),
quality: text('quality'),
orientation: text('orientation'),
hasAudio: boolean('has_audio').default(true),
width: integer('width'),
height: integer('height'),
directoryType: text('directory_type').$type<DirectoryType>(),
tags: jsonb('tags').$type<string[]>(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
directoryTypeIdx: index('idx_directory_type').on(table.directoryType),
fingerprintIdx: index('idx_videos_fingerprint').on(
table.durationSeconds,
table.fileSize,
table.width,
table.height
),
}));
```
---
## Related Documentation
- [Schema Reference](../schema.md#media-drizzle-orm) — Complete field listings
- [Migration Workflow](../migrations.md) — Drizzle Kit push
- [API Media Routes](../../api/media.md) — REST endpoints
- [Admin Media Library](../../admin/media-library.md) — Video management UI
- [Public Media Gallery](../../admin/public-media.md) — Public video gallery