Skip to content

Cast Sender

CastSenderPlugin is the Chromecast sender for nomercy-video-player. Register it when you want a Cast button in your player UI. It manages the full CAF session lifecycle, mirrors RemotePlayer events back to the local event bus so currentTime, play state, and volume stay accurate while casting, and resumes local playback automatically when the Cast session ends.

Plugin id

'cast-sender'

Import

TypeScript
import { CastSenderPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';
import type {
CastSenderOptions,
CastSenderEvents,
} from '@nomercy-entertainment/nomercy-video-player/plugins';

Prerequisites

The Google Cast SDK script must be loaded before the plugin’s use() runs:

HTML
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

What it does

CastSenderPlugin is a thin video-specific override of the player core’s shared CastSenderPlugin. The shared base handles the SDK probe, session lifecycle, RemotePlayer event mirroring, and the resume-on-disconnect path. The video subclass adds:

  • 'video/mp4' as the default content type for video items
  • buildMetadata() override that picks TvShowMediaMetadata (when item.show is set) or GenericMediaMetadata, reading title, show, season, episode, and poster from the VideoPlaylistItem shape
  • Poster URL resolution via this.resolveUrl(item.poster, 'poster'), so auth tokens and baseImageUrl are applied

Player events (play, pause, stop, seek) are forwarded to the active Cast session via RemotePlayerController only when the event payload does not carry source: 'cast'. volume and mute events are forwarded without a source check - they are suppressed only while the bridge is applying a receiver update internally. In environments without the Cast SDK (Firefox, JSDOM, every non-Chromium browser) the bridge stays passive. connect() raises a BrowserPolicyError and all forwarders no-op gracefully. Listeners are still attached so consumer UI can wire cast:* events before the SDK loads.

Options

OptionTypeDefaultDescription
chromecastAppIdstringundefinedChromecast receiver app ID. Leave unset to use the built-in NoMercy receiver.
enableAirPlaybooleanundefinedAllow AirPlay sender on Safari.
customReceiverNamespacestringundefinedCustom CAF namespace for receiver messages.
resumeLocalOnDisconnectbooleantrueResume local playback after Cast disconnects, restoring the receiver’s last position.
defaultContentTypestringundefinedOverride the MIME type used when the playlist item has no mime field. When omitted, the subclass defaultContentType() hook supplies the value ('video/mp4' for the video player).
livebooleanfalseTreat the stream as a live (unbounded) source.

Events

EventPayloadDescription
'cast:connected'{ deviceName: string }Session established.
'cast:disconnected'voidSession ended.
'cast:remote-state'{ time: number; state: 'playing' | 'paused' | 'buffering' }Receiver playback state mirrored to local bus.
'cast:media-changed'{ contentId: string }Active media item changed on the receiver.
'cast:error'{ error: Error }Cast SDK or session error.
'unsupported'{ reason: string }Cast SDK not available in this environment.

Consumer listeners use the plugin:<id>:<event> string form:

TypeScript
player.on('plugin:cast-sender:cast:connected', ({ deviceName }) => {
showCastingBanner(deviceName);
});

player.on('plugin:cast-sender:cast:disconnected', () => {
hideCastingBanner();
});

player.on('plugin:cast-sender:unsupported', ({ reason }) => {
hideCastButton();
});

Methods

TypeScript
import { CastSenderPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';

const castPlugin = player.getPlugin(CastSenderPlugin)!;

// Open the Cast device picker and establish a session.
// Throws BrowserPolicyError when the Cast SDK is absent.
await castPlugin.connect();

// End the current session. Idempotent, safe to call when not connected.
// Emits cast:disconnected on success.
// Emits unsupported (and returns without casting) when the Cast SDK is absent.
castPlugin.disconnect();

// True while a Cast session is active.
const active = castPlugin.isConnected();

Registration

TypeScript
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { CastSenderPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';

const player = nmplayer('player')
.addPlugin(CastSenderPlugin, { chromecastAppId: 'CC1AD845' })
.setup({
baseUrl: 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Films',
playlist: [
{
id: 1,
title: 'Tears of Steel',
url: '/Tears.of.Steel.(2012)/Tears.of.Steel.(2012).NoMercy.m3u8',
},
],
});

Custom receiver

If you have a custom Cast receiver app, pass its application ID:

TypeScript
player.addPlugin(CastSenderPlugin, {
chromecastAppId: 'ABCD1234',
});

The receiver must support the same playlist item shape (url, title, subtitles, etc.) or a mapped equivalent.

Metadata building

The video CastSenderPlugin overrides buildMetadata() to pick the right metadata type:

  • When item.show is a non-empty string, it uses TvShowMediaMetadata with seriesTitle, season, and episode populated.
  • Otherwise it uses GenericMediaMetadata with title and an optional subtitle from item.show.

Poster artwork is resolved via this.resolveUrl(item.poster, 'poster'), so the player core’s auth pipeline applies.

nomercy-cast-player

The NoMercy cast receiver (nomercy-cast-player) is a Vue 3 app designed to pair with this plugin. It is slated for a full rewrite to v2 in a future release.

See also