Limeplay - Open Source Video Player UI ComponentsLimeplay

use-asset

Asset playback orchestration for player, playlist, preloading, and source resolution.

Installation

npx shadcn add @limeplay/use-asset

Register the feature after playerFeature, playlistFeature, and playbackFeature:

lib/media.ts
"use client"

import { assetFeature } from "@/hooks/limeplay/use-asset"
import { playbackFeature } from "@/hooks/limeplay/use-playback"
import { playerFeature } from "@/hooks/limeplay/use-player"
import { playlistFeature } from "@/hooks/limeplay/use-playlist"
import { createMediaKit } from "@/components/limeplay/media-provider"

createMediaKit({
  features: [
    playerFeature(),
    playlistFeature(),
    playbackFeature(),
    assetFeature(),
  ] as const,
})

Usage

import { useAsset, type TAsset } from "@/hooks/limeplay/use-asset"
import { usePlaylist } from "@/hooks/limeplay/use-playlist"

interface VideoAsset extends TAsset {
  playbackUrl: string
  slug: string
}

export function PlaylistController({ assets }: { assets: VideoAsset[] }) {
  const { currentItem, loadSource } = useAsset<VideoAsset>()
  const { next, previous } = usePlaylist<VideoAsset>()

  return (
    <div>
      <button
        onClick={() =>
          loadSource(assets, {
            loading: {
              getAssetId: (asset) => asset.slug,
              resolveSource: ({ asset }) => ({
                config: asset.config,
                src: asset.playbackUrl,
              }),
            },
          })
        }
      >
        Load playlist
      </button>
      <button onClick={previous}>Previous</button>
      <button onClick={next}>Next</button>
      <span>{currentItem?.properties.title}</span>
    </div>
  )
}

Use loadSource for the public source contract: a URL string, one asset, or an asset array. Use loadAsset and loadPlaylist when you are building lower-level controls that already know which asset or queue should be loaded.

useAsset() does not accept options. Loading configuration is session-local and belongs to loadSource, loadPlaylist, or the loading prop on a block. The latest explicit load session wins.

sourceType reports the active loading mode as "asset", "playlist", or null before a source has been selected. Use it to render mode-specific controls:

const { sourceType } = useAsset()

const showPlaylistControls = sourceType === "playlist"

Base Asset Interface

FieldTypeRequiredDescription
idstringNoStable identifier for the asset.
srcstringNoMedia source URL.
configshaka.extern.PlayerConfigurationNoPer-asset Shaka config.

TAsset is intentionally small. Blocks and apps should extend it with their own optional metadata, such as title, description, poster, or provider-specific fields.

If id is omitted, useAsset derives one from getAssetId or src. Assets without src should provide resolveSource.

Source Resolution

Use resolveSource when the playable source is not stored directly on asset.src.

const { loadSource } = useAsset()

loadSource(
  { id: "movie-123" },
  {
    loading: {
      resolveSource: async ({ asset, signal }) => {
        const response = await fetch(`/api/assets/${asset.id}/source`, {
          signal,
        })
        const source = await response.json()

        return {
          config: source.config,
          src: source.url,
        }
      },
    },
  }
)

resolveSource is used by the default load and preload paths. Use loader.load or loader.preload when loading and preloading need different behavior.

Recovery

Use recover.loadError and recover.playbackError to decide how Limeplay should recover from failures.

import { AssetRecoveryAction, useAsset } from "@/hooks/limeplay/use-asset"

const { loadSource } = useAsset()

loadSource(playlist, {
  loading: {
    maxRetries: 2,
    recover: {
      loadError: (_asset, _error, { hasNext, retryCount }) => {
        if (retryCount < 2) return AssetRecoveryAction.Retry
        return hasNext ? AssetRecoveryAction.Skip : AssetRecoveryAction.Stop
      },
      playbackError: async (_asset, _error, { currentTime }) => ({
        action: AssetRecoveryAction.Reload,
        startTime: currentTime,
      }),
    },
  },
})

Lifecycle notifications are media events, not UseAssetOptions callbacks.

import { useEffect } from "react"

import { useMediaEvents } from "@/components/limeplay/media-provider"

export function AssetEventsLogger() {
  const events = useMediaEvents()

  useEffect(() => {
    return events.on("assetloaderror", ({ asset, error }) => {
      console.error("Asset failed", asset.id, error)
    })
  }, [events])

  return null
}

Options

Prop

Type

Returns

Prop

Type

Store

assetFeature adds a store slice that tracks the active load session, source type, load cancellation, retry state, and preload cancellation.

State

Prop

Type

Actions

Prop

Type

Events

useAsset emits asset lifecycle events through the shared media event emitter.

Prop

Type

useAsset orchestrates usePlayer and usePlaylist. It owns load cancellation, playlist-driven loading, preloading, auto-advance on playback end, and error recovery. Queue mutation methods still live on usePlaylist.

On this page