Skip to main content

Media Management

Open Genie indexes, catalogs, and serves media files (video, audio, images, documents) from the local file system. It supports automatic metadata extraction, thumbnail generation, playlists, and playback position tracking.

Architecture

File System Changes ──→ Chokidar Watcher ──→ Indexer ──→ Database

Metadata Extraction

Thumbnail Generation

File Watcher (lib/media/watcher.ts)

Uses chokidar to monitor the storage directory for file changes.

Behavior

  • Watched events: add, change, unlink
  • Debounce: 2 seconds — rapid changes are batched
  • Ignored: dotfiles, node_modules, .thumbnails, .cache
  • On add/change: Re-index the file (extract metadata, generate thumbnail)
  • On unlink: Remove the file record from the database

Start/Stop

import { startMediaWatcher, stopMediaWatcher } from "@/lib/media/watcher";

startMediaWatcher(); // Called at boot
stopMediaWatcher(); // Called at shutdown

Indexer (lib/media/indexer.ts)

Scans storage directories and syncs the database with the file system.

fullScan()

Performs a complete scan at boot:

  1. Walk all files in the storage directory
  2. For each file, check if it exists in the database
  3. New files: Extract metadata, generate thumbnail, insert record
  4. Changed files: Re-extract metadata, update record
  5. Missing files: Remove database records for deleted files

Returns a summary:

const result = await fullScan();
// { added: 12, updated: 3, removed: 1, errors: [] }

Media Type Detection

Files are classified by MIME type:

TypeExtensions
video.mp4, .mkv, .avi, .mov, .webm, etc.
audio.mp3, .flac, .m4a, .wav, .ogg, etc.
image.jpg, .png, .gif, .webp, .svg, etc.
document.pdf, .txt, .doc, .docx, etc.

Metadata Extraction (lib/media/metadata.ts)

Different metadata is extracted based on file type:

Video

  • Duration, resolution (width/height)
  • Codec, bitrate
  • Container format

Audio

  • Title, artist, album, year, genre
  • Track number, disc number
  • Duration, bitrate, sample rate

Image

  • Dimensions (width/height)
  • EXIF data: date taken, GPS coordinates, camera model
  • Color space, orientation

Document

  • File size and MIME type only

Thumbnail Generation (lib/media/thumbnails.ts)

Thumbnails are generated using Sharp and FFmpeg.

Source TypeMethod
VideoExtract frame at 10% of duration via FFmpeg
AudioExtract embedded album art (if available)
ImageResize to 300px width, JPEG quality 80
DocumentNo thumbnail

Thumbnails are stored in data/files/.thumbnails/{fileId}.jpg.

Playlists (lib/media/playlists.ts)

Playlists organize media files into ordered collections.

Operations

// Create a playlist
createPlaylist(name: string, description?: string): Promise<Playlist>

// Add a media file to a playlist
addToPlaylist(playlistId: string, mediaFileId: string, position?: number): Promise<void>

// Remove from playlist
removeFromPlaylist(playlistId: string, itemId: string): Promise<void>

// Reorder items (auto-shifts positions)
reorderPlaylistItem(playlistId: string, itemId: string, newPosition: number): Promise<void>

// Get playlist with items
getPlaylistWithItems(playlistId: string): Promise<PlaylistWithItems>

Position Management

Items have a position integer for ordering. When inserting at a specific position, existing items shift up automatically.

Playback Position Tracking

The lastPosition field on mediaFiles tracks where the user left off in video/audio playback:

POST /api/media/{id}/position
Body: { "position": 1234.5 }

This enables resume-from-where-you-left-off across devices.

REST API

MethodPathDescription
GET/api/mediaList media (paginated, filterable, sortable)
POST/api/media/uploadUpload a file
GET/api/media/scanTrigger a full rescan
GET/api/media/[id]Get file details + metadata
GET/api/media/[id]/thumbnailServe thumbnail image
POST/api/media/[id]/positionUpdate playback position
GET/api/media/photosList image files
GET/api/media/libraryLibrary statistics
GET/api/playlistsList playlists
POST/api/playlistsCreate playlist
GET/api/playlists/[id]Get playlist with items
PUT/api/playlists/[id]Update playlist
DELETE/api/playlists/[id]Delete playlist
POST/api/playlists/[id]/itemsAdd item to playlist
DELETE/api/playlists/[id]/items/[itemId]Remove item

Query Parameters for GET /api/media

ParameterTypeDescription
typestringFilter by media type (video, audio, image, document)
searchstringSearch by filename
sortstringSort field (name, size, createdAt, type)
orderstringasc or desc
pagenumberPage number (1-based)
limitnumberItems per page (default: 50)

Key Files

FilePurpose
lib/media/watcher.tsFile system change monitoring
lib/media/indexer.tsFull directory scan and sync
lib/media/metadata.tsMetadata extraction (EXIF, music tags, video info)
lib/media/thumbnails.tsThumbnail generation
lib/media/playlists.tsPlaylist CRUD and ordering