8.7 KiB
8.7 KiB
Media Manager
The Media Manager provides a complete video library system with upload, metadata extraction, public gallery, reaction system, and job queue monitoring. Built as a separate Fastify microservice with Drizzle ORM.
Overview
The Media Manager consists of four integrated components:
- Video Library - Admin video management
- Upload System - Video upload with metadata extraction
- Public Gallery - Public video sharing
- Job Queue - Background job monitoring
Features
Video Library
- Video CRUD operations
- Metadata editing (title, description, tags)
- Lock/unlock videos
- Bulk operations (delete, lock, share)
- Search and filtering
- Thumbnail generation (future)
Upload System
- Drag-and-drop upload
- Single and batch upload
- Progress tracking
- Automatic metadata extraction (FFprobe)
- Duration
- Dimensions (width x height)
- Orientation (landscape/portrait/square)
- Quality (resolution-based: 4K, 1080p, 720p, etc.)
- Audio detection
- File validation (type, size)
- Supported formats: MP4, MOV, AVI, MKV, WebM, M4V, FLV
- Max file size: 10GB
Public Gallery
- Shared videos display
- Category filtering
- Reaction system (6 emojis)
- Video cards with thumbnails
- Lock/unlock control
- Visitor reactions
Reaction System
Six emoji reactions:
- Like (👍)
- Love (❤️)
- Laugh (😂)
- Wow (😮)
- Sad (😢)
- Angry (😡)
Architecture
Dual API Design
Express API (Port 4000)
- Main V2 features
- Prisma ORM
- PostgreSQL
Fastify Media API (Port 4100)
- Media-specific operations
- Drizzle ORM
- Same PostgreSQL database
- Optimized for file uploads
Backend Components
Media API:
api/src/media-server.ts- Fastify entry pointapi/src/modules/media/routes/- Video, upload, shared, reactions, jobsapi/src/modules/media/services/- FFprobe, video serviceapi/src/modules/media/db/schema.ts- Drizzle schema
Database Tables:
videos- Video metadata (Drizzle)shared_media- Public gallery (Drizzle)media_reactions- Reaction tracking (Drizzle)media_jobs- Job queue (Drizzle)
Frontend Components
Admin Pages:
admin/src/pages/media/LibraryPage.tsx- Video library managementadmin/src/pages/media/SharedMediaPage.tsx- Public gallery adminadmin/src/pages/media/MediaJobsPage.tsx- Job queue monitoring
Public Pages:
admin/src/pages/public/MediaGalleryPage.tsx- Public video galleryadmin/src/pages/public/MediaViewerPage.tsx- Video detail page
Components:
admin/src/components/media/VideoCard.tsx- Video display cardadmin/src/components/media/BulkActions.tsx- Batch operationsadmin/src/components/media/UploadVideoModal.tsx- Upload interface
API Clients:
admin/src/lib/media-api.ts- Authenticated media API clientadmin/src/lib/media-public-api.ts- Public media API client
Configuration
Environment Variables
# Enable media features
ENABLE_MEDIA_FEATURES=true
# Media API port
MEDIA_API_PORT=4100
# Media storage
MEDIA_LIBRARY_PATH=/media/local/library # Read-only library
MEDIA_INBOX_PATH=/media/local/inbox # Read-write inbox
Docker Volumes
volumes:
# Library (read-only)
- /path/to/library:/media/local/library:ro
# Inbox (read-write for uploads)
- /path/to/inbox:/media/local/inbox:rw
Upload System
Upload Flow
-
Select Files
- Drag-and-drop or file picker
- Multiple file selection
- File type validation
-
Upload to Inbox
- Stream to
/media/local/inbox - UUID filename (prevents conflicts)
- Progress tracking
- Stream to
-
Extract Metadata
- FFprobe analysis (30s timeout)
- Duration, dimensions, orientation
- Quality calculation
- Audio detection
-
Create Database Record
- Store metadata
- Set initial status
- Link to user
-
Process Video (Future)
- Generate thumbnail
- Transcode formats
- Move to library
FFprobe Metadata Extraction
Automatically extracts:
interface VideoMetadata {
duration: number; // Seconds (e.g., 125.5)
width: number; // Pixels (e.g., 1920)
height: number; // Pixels (e.g., 1080)
orientation: string; // 'landscape' | 'portrait' | 'square'
quality: string; // '4K' | '1080p' | '720p' | 'SD'
hasAudio: boolean; // Audio stream detected
}
Quality Calculation:
- 4K: ≥2160p (3840x2160)
- 1080p: ≥1080p (1920x1080)
- 720p: ≥720p (1280x720)
- SD: <720p
Orientation:
- Landscape: width > height
- Portrait: height > width
- Square: width ≈ height (within 10%)
Supported Formats
- MP4 - H.264/H.265 video
- MOV - QuickTime
- AVI - Audio Video Interleave
- MKV - Matroska
- WebM - Web-optimized
- M4V - iTunes video
- FLV - Flash video
Public Gallery
Sharing System
Videos can be shared publicly:
- Lock/Unlock - Control public visibility
- Category Assignment - Organize by category
- Public Access - View at
/media - Reactions - Emoji reactions from visitors
Categories
Predefined categories:
- Events
- Testimonials
- Tutorials
- Announcements
- Behind the Scenes
- Custom categories
Reaction System
Reaction Tracking
interface MediaReaction {
id: number;
videoId: number;
reactionType: string; // 'like' | 'love' | 'laugh' | 'wow' | 'sad' | 'angry'
sessionId: string; // Unique session identifier
createdAt: Date;
}
Session-Based Reactions
- One reaction per video per session
- Session ID in localStorage
- Update reaction (change type)
- Remove reaction (click again)
Job Queue
Background jobs for:
- Video processing
- Thumbnail generation
- Format transcoding
- Metadata extraction
- File cleanup
Job Monitoring
Admin can:
- View job status
- Monitor progress
- Retry failed jobs
- View error logs
Database Schema (Drizzle)
Videos Table
export const videos = pgTable('videos', {
id: serial('id').primaryKey(),
title: varchar('title', { length: 255 }).notNull(),
description: text('description'),
filename: varchar('filename', { length: 255 }).notNull(),
filepath: varchar('filepath', { length: 500 }).notNull(),
duration: integer('duration'), // Seconds
width: integer('width'), // Pixels
height: integer('height'), // Pixels
orientation: varchar('orientation', { length: 20 }), // 'landscape' | 'portrait' | 'square'
quality: varchar('quality', { length: 20 }), // '4K' | '1080p' | '720p' | 'SD'
hasAudio: boolean('has_audio'),
tags: json('tags').$type<string[]>(),
locked: boolean('locked').default(false),
uploadedBy: integer('uploaded_by'),
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
});
API Endpoints
Admin Endpoints (Media API - Port 4100)
GET /media-api/videos # List videos
POST /media-api/videos # Create video (manual)
GET /media-api/videos/:id # Get video
PATCH /media-api/videos/:id # Update video
DELETE /media-api/videos/:id # Delete video
POST /media-api/upload # Upload single video
POST /media-api/upload/batch # Upload multiple videos
GET /media-api/shared # List shared videos
POST /media-api/shared # Share video
DELETE /media-api/shared/:id # Unshare video
GET /media-api/jobs # List jobs
Public Endpoints
GET /media-api/public/videos # List public videos
GET /media-api/public/videos/:id # Get public video
POST /media-api/reactions # Add/update reaction
DELETE /media-api/reactions/:id # Remove reaction
Security
File Validation
- MIME type checking
- File extension validation
- File size limits (10GB max)
- Path traversal prevention
- Null byte detection
Access Control
- Admin-only uploads
- Lock/unlock controls
- Public visibility flags
- Session-based reactions
Performance
Upload Optimization
- Streaming uploads (no memory buffering)
- UUID filenames (no collisions)
- Async metadata extraction
- Progress tracking
Gallery Optimization
- Lazy loading
- Thumbnail caching (future)
- Paginated results
- Infinite scroll