@mottosports/motto-video-player
Version:
React video player component for the Motto platform, powered by Shaka Player
656 lines (642 loc) • 16.3 kB
TypeScript
import React, { HTMLAttributes } from 'react';
import { QueryClient } from '@tanstack/react-query';
interface VideoData {
id: string;
name?: string;
description?: string;
playlists?: Playlist[];
error?: string;
ad?: {
adTagUrl?: string;
};
}
interface DVRSettings {
window_size_seconds: number;
}
interface Widevine {
playlistUrl: string;
licenseUrl: string;
}
interface Fairplay {
certificateUrl: string;
licenseUrl: string;
playlistUrl: string;
}
interface Playready {
playlistUrl: string;
licenseUrl: string;
}
interface DRM {
token?: string;
licenseCacheKey?: string;
widevine?: Widevine;
fairplay?: Fairplay;
playready?: Playready;
}
interface Playlist {
id: string;
url: string;
format: string;
dvr_settings?: DVRSettings;
drm: DRM;
}
interface EventData {
id: string;
title: string;
description?: string;
startTime: string;
endTime?: string;
posterUrl?: string;
videoIds?: string[];
error?: string;
}
declare enum EventsSortDirection {
ASC = "asc",
DESC = "desc"
}
interface CreativeWorkData {
id: string;
title: string;
description?: string;
releaseTime: string;
endTime?: string;
posterUrl?: string;
videoIds?: string[];
error?: string;
}
declare enum CreativeWorksSortDirection {
ASC = "asc",
DESC = "desc"
}
/**
* Unified events interface for both Player and Video wrapper
*/
interface PlayerEvents {
/**
* Callback when video starts playing
*/
onPlay?: () => void;
/**
* Callback when video is paused
*/
onPause?: () => void;
/**
* Callback when video ends
*/
onEnded?: () => void;
/**
* Callback when video loading starts
*/
onLoadStart?: () => void;
/**
* Callback when video has loaded enough to start playback
*/
onCanPlay?: () => void;
/**
* Callback when an error occurs
*/
onError?: (error: Error) => void;
/**
* Callback when Shaka Player is ready
*/
onPlayerReady?: (player: any) => void;
/**
* Callback when quality changes
*/
onQualityChange?: (quality: {
height: number;
bandwidth: number;
}) => void;
/**
* Callback when ads start
*/
onAdStart?: () => void;
/**
* Callback when ads complete
*/
onAdComplete?: () => void;
/**
* Callback when ad error occurs
*/
onAdError?: (error: any) => void;
/**
* Callback when ad is skipped
*/
onAdSkipped?: () => void;
/**
* Callback when ad is paused
*/
onAdPaused?: () => void;
/**
* Callback when ad is resumed
*/
onAdResumed?: () => void;
/**
* Callback when ad progress updates
*/
onAdProgress?: (adProgressData: any) => void;
/**
* Callback when all ads are completed
*/
onAllAdsCompleted?: () => void;
/**
* Callback when Chromecast state changes
*/
onCastStateChange?: (isCasting: boolean) => void;
/**
* Callback when skip back is triggered
*/
onSkipBack?: (newTime: number) => void;
/**
* Callback when skip forward is triggered
*/
onSkipForward?: (newTime: number) => void;
/**
* Callback when Mux analytics is ready
*/
onMuxReady?: () => void;
/**
* Callback when Mux analytics updates data
*/
onMuxDataUpdate?: (data: MuxDataUpdatePayload) => void;
/**
* Callback when live state changes
*/
onLiveStateChange?: (isLive: boolean) => void;
}
/**
* Seekbar color configuration
*/
interface SeekbarConfig {
/**
* Color for the unbuffered track
*/
base?: string;
/**
* Color for the buffered but not played portion
*/
buffered?: string;
/**
* Color for the played/progress portion
*/
played?: string;
}
/**
* Icon size configuration
*/
interface IconSizes {
/**
* Size for skip back/forward buttons (in pixels)
*/
skipButtons?: number;
/**
* Size for the big play button (in pixels)
*/
bigPlayButton?: number;
}
interface PlayerProps extends Omit<HTMLAttributes<HTMLVideoElement>, 'src' | 'onError'> {
/**
* The source URL of the video (DASH, HLS, or regular MP4) or playlist object with DRM info
*/
src: Playlist;
/**
* When true, player only reinitializes based on playlist presence rather than src changes.
* Used internally by Event, CreativeWork, and Video wrappers to optimize reinitialization.
*/
managedMode?: boolean;
/**
* Whether the video should autoplay
*/
autoPlay?: boolean;
/**
* Whether the video should loop
*/
loop?: boolean;
/**
* Whether the video should be muted
*/
muted?: boolean;
/**
* Whether to show video controls
*/
controls?: boolean;
/**
* Poster image to show before video plays
*/
poster?: string;
/**
* Video width
*/
width?: number | string;
/**
* Video height
*/
height?: number | string;
/**
* Aspect ratio for responsive sizing (e.g., 16/9, 4/3)
* If not provided, defaults to 16/9
* Only used when width/height are not specified
*/
aspectRatio?: number;
/**
* Shaka Player configuration options
*/
shakaConfig?: any;
/**
* DRM configuration for protected content (deprecated - now derived from src playlist)
*/
drmConfig?: {
clearKeys?: {
[keyId: string]: string;
};
servers?: {
[keySystem: string]: string;
};
};
/**
* Mux Analytics configuration
*/
muxConfig?: MuxAnalyticsConfig;
/**
* System73 SDK configuration
*/
system73Config?: System73Config;
/**
* IMA (Interactive Media Ads) configuration
*/
imaConfig?: {
/**
* Ad tag URL for client-side ads
*/
adTagUrl?: string;
/**
* Whether to enable server-side ad insertion (DAI)
*/
enableServerSideAds?: boolean;
/**
* Custom ads rendering settings
*/
adsRenderingSettings?: any;
/**
* Linear ad slot dimensions
*/
linearAdSlotWidth?: number;
linearAdSlotHeight?: number;
/**
* Non-linear ad slot dimensions
*/
nonLinearAdSlotWidth?: number;
nonLinearAdSlotHeight?: number;
};
/**
* Chromecast configuration (optional)
* Chromecast is always enabled by default. This config allows customization.
*/
chromecastConfig?: {
/**
* Custom receiver application ID
* Defaults to 'CC1AD845' (Google's default media receiver)
*/
receiverApplicationId?: string;
};
/**
* Quality selection configuration
*/
qualityConfig?: {
/**
* Whether to enable adaptive quality selection
*/
enableAdaptation?: boolean;
/**
* Manual quality selection (height in pixels, 0 for auto)
*/
selectedQuality?: number;
/**
* Available quality levels override
*/
availableQualities?: Array<{
height: number;
bandwidth: number;
label: string;
}>;
};
/**
* Seekbar color configuration
*/
seekbarConfig?: SeekbarConfig;
/**
* Icon size configuration
*/
iconSizes?: IconSizes;
/**
* Event callbacks
*/
events?: PlayerEvents;
/**
* Locale for Shaka Player UI localization (e.g., 'en', 'ar', 'es')
* Defaults to 'en' if not provided
*/
locale?: string;
containerClassName?: string;
/**
* Motto public key used for authenticated requests
*/
publicKey?: string;
/**
* Authentication context for player operations
*/
auth?: {
mottoToken?: string;
userId?: string;
};
}
/**
* Mux Analytics type definitions
*/
interface MuxMetadata {
viewer_user_id?: string;
experiment_name?: string;
sub_property_id?: string;
player_name?: string;
player_version?: string;
player_init_time?: number;
video_id?: string;
video_title?: string;
video_series?: string;
video_duration?: number;
video_stream_type?: 'live' | 'on-demand';
video_cdn?: string;
video_encoding_variant?: string;
video_content_type?: string;
video_language_code?: string;
video_variant_name?: string;
video_variant_id?: string;
custom_1?: string;
custom_2?: string;
custom_3?: string;
custom_4?: string;
custom_5?: string;
custom_6?: string;
custom_7?: string;
custom_8?: string;
custom_9?: string;
custom_10?: string;
custom_11?: string;
custom_12?: string;
custom_13?: string;
custom_14?: string;
custom_15?: string;
custom_16?: string;
custom_17?: string;
custom_18?: string;
custom_19?: string;
custom_20?: string;
}
interface MuxErrorTranslator {
(error: any): any | false;
}
interface MuxDataUpdatePayload {
player_error_code?: string;
player_error_message?: string;
video_bitrate?: number;
video_resolution_height?: number;
video_resolution_width?: number;
video_framerate?: number;
audio_bitrate?: number;
video_startup_time?: number;
page_load_time?: number;
player_load_time?: number;
[key: string]: any;
}
interface MuxAnalyticsConfig {
/**
* Mux environment key (required for analytics)
*/
envKey: string;
/**
* Whether to enable debug logging
*/
debug?: boolean;
/**
* Whether to disable cookies for privacy compliance
*/
disableCookies?: boolean;
/**
* Whether to respect "Do Not Track" browser setting
*/
respectDoNotTrack?: boolean;
/**
* Custom domain for beacon collection
*/
beaconCollectionDomain?: string;
/**
* Whether to disable automatic error tracking
*/
automaticErrorTracking?: boolean;
/**
* Custom error translator function
*/
errorTranslator?: MuxErrorTranslator;
/**
* Metadata for tracking (see Mux docs for all available fields)
*/
metadata?: MuxMetadata;
}
/**
* System73 SDK configuration
*/
interface System73Config {
/**
* System73 API key (required for authentication)
*/
apiKey: string;
/**
* Content steering endpoint URI (optional)
*/
contentSteeringEndpoint?: string;
/**
* Channel identifier (optional)
*/
channelId?: string;
}
/**
* System73 SDK wrapper interface
*/
declare global {
interface Window {
S73ShakaPlayerWrapper?: (config: System73Config, shakaInstance: {
shaka: any;
}) => {
wrapPlayerConfig: (config: any) => void;
wrapPlayer: (player: any) => void;
};
}
}
declare global {
namespace google {
namespace ima {
class AdsRequest {
adTagUrl: string;
}
}
}
}
declare const Player: React.ForwardRefExoticComponent<PlayerProps & React.RefAttributes<HTMLVideoElement>>;
interface VideoProps extends Omit<PlayerProps, 'src'> {
videoId?: string;
publicKey?: string;
videoData?: VideoData;
refetchInterval?: number;
playerName?: string;
locale?: string;
events?: {
onVideoData?: (video: VideoData) => void;
onEmptyPlaylists?: () => void;
onError?: (error: Error) => void;
onPlay?: () => void;
onPause?: () => void;
onEnded?: () => void;
onLoadStart?: () => void;
onCanPlay?: () => void;
onPlayerReady?: () => void;
onAdStart?: () => void;
onAdComplete?: () => void;
onAdError?: (error: any) => void;
onAdSkipped?: () => void;
onAdPaused?: () => void;
onAdResumed?: () => void;
onAdProgress?: (adProgressData: any) => void;
onAllAdsCompleted?: () => void;
};
children?: React.ReactNode;
className?: string;
auth?: {
mottoToken?: string;
userId?: string;
};
settings?: {
backgroundImageUrl?: string;
};
queryOptions?: {
enabled?: boolean;
staleTime?: number;
cacheTime?: number;
retry?: number;
retryDelay?: number;
};
adsEnabled?: boolean;
}
declare const Video: React.FC<VideoProps>;
interface EventProps extends Omit<PlayerProps, 'src' | 'drmConfig'> {
publicKey: string;
eventId: string;
hideTitle?: boolean;
locale?: string;
filter?: string;
order?: EventsSortDirection;
events?: {
onEventData?: (event: EventData) => void;
onVideoData?: (video: VideoData) => void;
onEmptyPlaylists?: () => void;
onError?: (error: Error) => void;
onPlay?: () => void;
onPause?: () => void;
onEnded?: () => void;
onLoadStart?: () => void;
onCanPlay?: () => void;
onPlayerReady?: () => void;
onAdStart?: () => void;
onAdComplete?: () => void;
onAdError?: (error: any) => void;
onAdSkipped?: () => void;
onAdPaused?: () => void;
onAdResumed?: () => void;
onAdProgress?: (adProgressData: any) => void;
onAllAdsCompleted?: () => void;
};
className?: string;
settings?: {
backgroundImageUrl?: string;
showCountdownAnimation?: boolean;
};
auth?: {
mottoToken?: string;
userId?: string;
};
queryOptions?: {
enabled?: boolean;
staleTime?: number;
cacheTime?: number;
retry?: number;
retryDelay?: number;
};
adsEnabled?: boolean;
}
declare const Event: React.FC<EventProps>;
interface CreativeWorkProps extends Omit<PlayerProps, 'src'> {
publicKey: string;
creativeWorkId: string;
hideTitle?: boolean;
locale?: string;
filter?: string;
order?: CreativeWorksSortDirection;
events?: {
onCreativeWorkData?: (creativeWork: CreativeWorkData) => void;
onVideoData?: (video: VideoData) => void;
onEmptyPlaylists?: () => void;
onError?: (error: Error) => void;
onPlay?: () => void;
onPause?: () => void;
onEnded?: () => void;
onLoadStart?: () => void;
onCanPlay?: () => void;
onPlayerReady?: () => void;
onAdStart?: () => void;
onAdComplete?: () => void;
onAdError?: (error: any) => void;
onAdSkipped?: () => void;
onAdPaused?: () => void;
onAdResumed?: () => void;
onAdProgress?: (adProgressData: any) => void;
onAllAdsCompleted?: () => void;
};
className?: string;
settings?: {
backgroundImageUrl?: string;
showCountdownAnimation?: boolean;
};
auth?: {
mottoToken?: string;
userId?: string;
};
queryOptions?: {
enabled?: boolean;
staleTime?: number;
cacheTime?: number;
retry?: number;
retryDelay?: number;
};
adsEnabled?: boolean;
}
declare const CreativeWork: React.FC<CreativeWorkProps>;
declare const queryClient: QueryClient;
interface QueryProviderProps {
children: React.ReactNode;
}
declare const QueryProvider: React.FC<QueryProviderProps>;
interface SkipBackIconProps {
size?: number;
className?: string;
}
declare const SkipBackIcon: React.FC<SkipBackIconProps>;
interface SkipForwardIconProps {
size?: number;
className?: string;
}
declare const SkipForwardIcon: React.FC<SkipForwardIconProps>;
interface BigPlayIconProps {
size?: number;
className?: string;
}
declare const BigPlayIcon: React.FC<BigPlayIconProps>;
export { BigPlayIcon, CreativeWork, type CreativeWorkData, type CreativeWorkProps, CreativeWorksSortDirection, Event, type EventData, type EventProps, EventsSortDirection, type IconSizes, Player, type PlayerEvents, type PlayerProps, QueryProvider, SkipBackIcon, SkipForwardIcon, Video, type VideoData, type VideoProps, queryClient };