Skip to main content

LocalClient

LocalClient extends MediaClient to provide integration with local file systems using the browser’s File System Access API. It creates in-memory video records from File objects and uses Blob URLs for playback.

Overview

LocalClient is designed for browser-based local folder access without requiring a server. It:
  • Works with browser File System Access API or file input
  • Creates Blob URLs for video playback
  • Stores favorites in localStorage
  • Filters videos by supported extensions
  • Manages memory by revoking old Blob URLs

Constructor

constructor(config: ServerConfig, files: File[] = [])
config
ServerConfig
required
Server configuration with serverType: 'local'
files
File[]
default:"[]"
Array of File objects from file input or File System Access API

Implementation

From LocalClient.ts:45-51:
constructor(config: ServerConfig, files: File[] = []) {
  super(config);
  const { records, urls } = this.buildRecords(files);
  this.records = records;
  this.videoUrlMap = new Map(records.map((record) => [record.item.Id, record.objectUrl]));
  this.replaceObjectUrls(urls);
}

Methods

authenticate

async authenticate(username: string): Promise<ServerConfig>
Returns a local server configuration. No actual authentication is performed.
username
string
Display name for local user (defaults to “Local User”)
Returns: Promise resolving to ServerConfig with serverType: 'local' Example:
const config = await localClient.authenticate('My Videos');
// {
//   url: 'local://folder',
//   username: 'My Videos',
//   token: '',
//   userId: 'local-user',
//   serverType: 'local'
// }

getLibraries

async getLibraries(): Promise<EmbyLibrary[]>
Returns a single library representing local videos. Returns: Array with one library: { Id: 'local-library', Name: '本地视频' } Example:
const libraries = await localClient.getLibraries();
// [{ Id: 'local-library', Name: '本地视频' }]

getVideos

async getVideos(
  parentId: string | undefined,
  libraryName: string,
  feedType: FeedType,
  skip: number,
  limit: number,
  orientationMode: OrientationMode
): Promise<VideoResponse>
Retrieves videos from local file records with filtering and pagination.
feedType
FeedType
  • latest - Videos sorted by file modification time (newest first)
  • random - Shuffled selection of videos
  • favorites - Only favorited videos from localStorage
orientationMode
OrientationMode
Filter by video dimensions (vertical/horizontal/both)
skip
number
Number of items to skip (for pagination)
limit
number
Maximum number of items to return
Returns: VideoResponse with filtered and paginated items Implementation details: From LocalClient.ts:67-103:
  • Filters by favorites if feedType === 'favorites'
  • Filters by orientation mode
  • Shuffles for random mode
  • Sorts by lastModified for latest mode

getVideoUrl

getVideoUrl(item: EmbyItem): string
Returns the Blob URL for a video item.
item
EmbyItem
required
Video item to get URL for
Returns: Blob URL string (e.g., blob:http://localhost:5173/abc-123) Example:
const url = localClient.getVideoUrl(videoItem);
// "blob:http://localhost:5173/550e8400-e29b-41d4-a716-446655440000"

getImageUrl

getImageUrl(itemId: string, tag?: string, type?: 'Primary' | 'Backdrop'): string
Returns empty string as local mode doesn’t support thumbnails. Returns: Empty string

getFavorites

async getFavorites(libraryName: string): Promise<Set<string>>
Reads favorites from localStorage. Returns: Set of video item IDs marked as favorite Storage key: embytokLocalFavorites (from LocalClient.ts:22)

toggleFavorite

async toggleFavorite(
  itemId: string,
  isFavorite: boolean,
  libraryName: string
): Promise<void>
Adds or removes a video from localStorage favorites.
itemId
string
required
ID of the video to toggle
isFavorite
boolean
required
Current favorite state (true = remove, false = add)

Supported Video Formats

From LocalClient.ts:24-36:
const VIDEO_EXTENSIONS = new Set([
  'mp4', 'mkv', 'avi', 'mov', 'webm',
  'm4v', 'flv', 'wmv', 'ts', 'm2ts', '3gp'
]);
Special handling:
  • .ts files must be ≥5MB to avoid false positives with TypeScript files

Memory Management

LocalClient manages Blob URLs to prevent memory leaks: From LocalClient.ts:167-172:
private replaceObjectUrls(nextUrls: string[]): void {
  LocalClient.activeObjectUrls.forEach((url) => {
    URL.revokeObjectURL(url);
  });
  LocalClient.activeObjectUrls = new Set(nextUrls);
}
When switching folders or reloading, old Blob URLs are revoked and replaced with new ones.

Item ID Generation

Each local video gets a unique ID based on: From LocalClient.ts:179-181:
private buildItemId(relativePath: string, file: File): string {
  return `local:${encodeURIComponent(relativePath)}:${file.size}:${file.lastModified}`;
}
This ensures stable IDs across sessions if the same files are loaded.

Usage Example

import { ClientFactory } from './services/clientFactory';

// Get files from File System Access API
const dirHandle = await window.showDirectoryPicker();
const files = await loadVideoFilesFromDirectory(dirHandle);

// Create local client
const config = {
  url: 'local://folder',
  username: 'Local User',
  token: '',
  userId: 'local-user',
  serverType: 'local'
};

const client = ClientFactory.create(config, { localFiles: files });

// Browse videos
const { items, totalCount } = await client.getVideos(
  undefined,
  '本地视频',
  'latest',
  0,
  20,
  'vertical'
);

// Get playback URL
const videoUrl = client.getVideoUrl(items[0]);
// Use videoUrl in <video> element

Build docs developers (and LLMs) love