UNPKG

unified-video-framework

Version:

Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more

543 lines (504 loc) 14.2 kB
// Core TypeScript interfaces for the unified video framework export enum PlatformType { IOS = 'ios', ANDROID = 'android', TIZEN = 'tizen', WEBOS = 'webos', ROKU = 'roku', ANDROID_TV = 'androidtv', APPLE_TV = 'appletv', WEB = 'web', WINDOWS = 'windows' } export enum PlayerStateEnum { IDLE = 'idle', LOADING = 'loading', READY = 'ready', PLAYING = 'playing', PAUSED = 'paused', BUFFERING = 'buffering', ENDED = 'ended', ERROR = 'error' } // Legacy enum export for compatibility export { PlayerStateEnum as PlayerState }; export enum DRMType { FAIRPLAY = 'fairplay', WIDEVINE = 'widevine', PLAYREADY = 'playready', CLEARKEY = 'clearkey' } export interface VideoSource { url: string; type?: string; title?: string; description?: string; thumbnail?: string; duration?: number; drm?: DRMConfig; subtitles?: SubtitleTrack[]; metadata?: Record<string, any>; } export interface DRMConfig { type: DRMType; licenseUrl: string; certificateUrl?: string; headers?: Record<string, string>; customData?: string; fairplayOptions?: { certificateUrl: string; licenseUrl: string; }; widevineOptions?: { licenseUrl: string; serverCertificate?: ArrayBuffer; }; playreadyOptions?: { licenseUrl: string; customData?: string; }; } export interface SubtitleTrack { id: string; label: string; language: string; url?: string; kind?: 'subtitles' | 'captions' | 'descriptions'; default?: boolean; } export interface AudioTrack { id: string; label: string; language: string; channels?: number; bitrate?: number; codec?: string; } export interface Quality { id: string; label: string; height: number; width: number; bitrate: number; frameRate?: number; codec?: string; } export interface AdaptiveBitrateConfig { minBitrate?: number; maxBitrate?: number; startBitrate?: number; autoLevelEnabled?: boolean; startLevel?: number; } export interface NavigationConfig { backButton?: { enabled?: boolean; position?: 'top-left' | 'top-right'; icon?: 'arrow' | 'chevron' | 'custom'; customIcon?: string; // SVG string or URL title?: string; ariaLabel?: string; onClick?: () => void | Promise<void>; href?: string; // Navigate to URL replace?: boolean; // Use history.replaceState instead of pushState }; closeButton?: { enabled?: boolean; position?: 'top-left' | 'top-right'; icon?: 'x' | 'close' | 'custom'; customIcon?: string; // SVG string or URL title?: string; ariaLabel?: string; onClick?: () => void | Promise<void>; exitFullscreen?: boolean; // Exit fullscreen when clicked closeModal?: boolean; // Close modal/overlay when clicked }; } export interface ShareConfig { enabled?: boolean; // Enable/disable share button (default: true) url?: string; // Custom share URL (default: window.location.href) title?: string; // Custom share title (default: video metadata title) text?: string; // Custom share description (default: video metadata description) generateUrl?: (videoData: { videoId?: string; metadata?: any }) => string; // Dynamic URL generator } export interface VideoPlayerConfig { autoPlay?: boolean; muted?: boolean; controls?: boolean; loop?: boolean; preload?: 'none' | 'metadata' | 'auto'; crossOrigin?: 'anonymous' | 'use-credentials'; playsInline?: boolean; pictureInPicture?: boolean; showFrameworkBranding?: boolean; // Show/hide flicknexs framework branding (default: true) navigation?: NavigationConfig; // Navigation buttons configuration watermark?: WatermarkConfig; // Watermark configuration share?: ShareConfig; // Share button configuration adaptiveBitrate?: AdaptiveBitrateConfig; drm?: DRMConfig; analytics?: AnalyticsConfig; ads?: AdsConfig; cast?: CastConfig; offline?: OfflineConfig; } export interface AnalyticsConfig { enabled: boolean; providers: AnalyticsProvider[]; trackingInterval?: number; customDimensions?: Record<string, any>; } export interface AnalyticsProvider { name: string; config: Record<string, any>; track: (event: string, data: any) => void; } export interface AdsConfig { enabled: boolean; adTagUrl?: string; adsManager?: any; midrollPositions?: number[]; companionAds?: { width: number; height: number; container: HTMLElement; }; } export interface CastConfig { enabled: boolean; receiverApplicationId?: string; autoJoinPolicy?: 'ORIGIN_SCOPED' | 'TAB_AND_ORIGIN_SCOPED' | 'PAGE_SCOPED'; } export interface OfflineConfig { enabled: boolean; storageLimit?: number; downloadQuality?: 'auto' | 'high' | 'medium' | 'low'; } // Chapter-related interfaces export interface Chapter { id: string; title: string; startTime: number; // in seconds endTime: number; // in seconds thumbnail?: string; description?: string; metadata?: Record<string, any>; } export interface ChapterSegment { id: string; startTime: number; // in seconds endTime: number; // in seconds category?: string; action?: 'skip' | 'mute' | 'warn'; title?: string; description?: string; } export interface ChapterConfig { enabled?: boolean; chapters?: Chapter[]; segments?: ChapterSegment[]; // For sponsor segments, intros, etc. dataUrl?: string; // URL to fetch chapter data from autoSkip?: boolean; // Auto-skip segments with action: 'skip' showSkipButton?: boolean; // Show skip button for segments skipButtonText?: string; onChapterChange?: (chapter: Chapter | null) => void; onSegmentEntered?: (segment: ChapterSegment) => void; onSegmentExited?: (segment: ChapterSegment) => void; onSegmentSkipped?: (segment: ChapterSegment) => void; } export interface WatermarkConfig { enabled?: boolean; // Enable/disable watermark (default: true) text?: string; // Custom watermark text (default: "PREMIUM") showTime?: boolean; // Show current time with watermark (default: true) updateInterval?: number; // Update frequency in milliseconds (default: 5000) randomPosition?: boolean; // Random position on each update (default: true) position?: { x?: number | 'left' | 'center' | 'right' | 'random'; y?: number | 'top' | 'center' | 'bottom' | 'random'; }; style?: { fontSize?: number; // Font size in pixels (default: 14) fontFamily?: string; // Font family (default: "Arial") opacity?: number; // Opacity 0-1 (default: 0.3) color?: string; // Custom color (overrides gradient) gradientColors?: [string, string]; // Custom gradient colors }; } export interface PlayerMetrics { sessionId: string; playbackStarted?: number; totalPlayTime: number; bufferingCount: number; bufferingDuration: number; averageBitrate: number; qualityChanges: number; errors: PlayerError[]; bandwidth?: number; droppedFrames?: number; decodedFrames?: number; } export interface PlayerError { code: string; message: string; timestamp: number; fatal: boolean; data?: any; } export interface ProgressEvent { currentTime: number; duration: number; buffered: TimeRanges; seekable: TimeRanges; played: TimeRanges; } export interface TimeRanges { length: number; start(index: number): number; end(index: number): number; } export interface PlatformInfo { type: PlatformType; os: string; version: string; isTV: boolean; isMobile: boolean; isDesktop?: boolean; hasTouch?: boolean; screenSize?: { width: number; height: number; }; } export type PlayerEvent = | 'onReady' | 'onPlay' | 'onPause' | 'onEnded' | 'onError' | 'onLoadstart' | 'onLoadedMetadata' | 'onTimeUpdate' | 'onProgress' | 'onSeeking' | 'onSeeked' | 'onWaiting' | 'onCanplay' | 'onCanplaythrough' | 'onVolumeChanged' | 'onBuffering' | 'onRatechange' | 'onQualityChanged' | 'onSubtitlechange' | 'onAudiotrackchange' | 'onFullscreenChanged' | 'onPictureInPicturechange' | 'castStateChanged' | 'onAdstart' | 'onAdend' | 'onAderror' | 'onChapterchange' | 'segmententered' | 'segmentexited' | 'segmentskipped' | 'chapterSegmentEntered' | 'chapterSegmentSkipped' | 'chapterSkipButtonShown' | 'chapterSkipButtonHidden' | 'chaptersLoaded' | 'chaptersLoadError' | 'epgToggle' | 'epgDataSet' | 'frameworkBrandingClick' | 'onFreePreviewEnded' | 'statechange' | 'navigationBackClicked' | 'navigationCloseClicked' | 'creditsWatched' | 'nextEpisodeClicked' | 'creditsAutoRedirect' | 'creditsFullyWatched'; export type EventHandler = (data?: any) => void; export interface EventEmitter { on(event: PlayerEvent, handler: EventHandler): void; off(event: PlayerEvent, handler: EventHandler): void; once(event: PlayerEvent, handler: EventHandler): void; emit(event: PlayerEvent, data?: any): void; removeAllListeners(event?: PlayerEvent): void; } // Legacy alias for PlayerEvent - used by some implementations export type PlayerEvents = { [K in PlayerEvent]: K; }; // Video player interface for backwards compatibility export interface VideoPlayerInterface { load(source: VideoSource): Promise<void>; play(): Promise<void>; pause(): void; seek(position: number): void; setVolume(volume: number): void; getCurrentTime(): number; getDuration(): number; getVolume(): number; isMuted(): boolean; mute(): void; unmute(): void; setPlaybackRate(rate: number): void; getPlaybackRate(): number; enterFullscreen(): void; exitFullscreen(): void; enterPictureInPicture(): void; exitPictureInPicture(): void; on(event: string, handler: Function): void; off(event: string, handler: Function): void; destroy(): void; getState(): VideoPlayerState; } // Legacy state type export type VideoPlayerState = 'idle' | 'loading' | 'ready' | 'playing' | 'paused' | 'buffering' | 'ended' | 'error'; // Main player interface export interface IVideoPlayer { initialize(container: any, config?: PlayerConfig): Promise<void>; destroy(): Promise<void>; load(videoSource: VideoSource): Promise<void>; play(): Promise<void>; pause(): void; stop(): void; seek(time: number): void; setVolume(level: number): void; mute(): void; unmute(): void; toggleMute(): void; getQualities(): Quality[]; getCurrentQuality(): Quality | null; setQuality(index: number): void; setAutoQuality(enabled: boolean): void; setPlaybackRate(rate: number): void; getPlaybackRate(): number; getCurrentTime(): number; getDuration(): number; getBufferedPercentage(): number; getState(): PlayerStateInterface; isPlaying(): boolean; isPaused(): boolean; isEnded(): boolean; enterFullscreen(): Promise<void>; exitFullscreen(): Promise<void>; toggleFullscreen(): Promise<void>; enterPictureInPicture(): Promise<void>; exitPictureInPicture(): Promise<void>; on(event: PlayerEvent, handler: EventHandler): void; off(event: PlayerEvent, handler?: EventHandler): void; once(event: PlayerEvent, handler: EventHandler): void; getSubtitles(): SubtitleTrack[]; setSubtitleTrack(index: number): void; disableSubtitles(): void; } // Player state interface export interface PlayerStateInterface { isPlaying: boolean; isPaused: boolean; isBuffering: boolean; isEnded: boolean; isError: boolean; currentTime: number; duration: number; bufferedPercentage: number; volume: number; isMuted: boolean; playbackRate: number; currentQuality: Quality | null; availableQualities: Quality[]; } export interface PaywallConfig { enabled?: boolean; apiBase?: string; userId?: string; videoId?: string; gateways?: (string | PaywallGateway)[]; pricing?: { amount?: number; currency?: string; title?: string; description?: string; }; branding?: { title?: string; description?: string; brandColor?: string; paymentTitle?: string; }; popup?: { width?: number; height?: number; }; metadata?: { slug?: string; [key: string]: any; }; // Payment Link Configuration for generic payment gateways paymentLink?: { endpoint: string; method?: 'POST' | 'GET'; headers?: Record<string, string>; mapRequest?: (paymentData: any) => any; mapResponse?: (response: any) => { url: string; orderId?: string; }; popup?: { width?: number; height?: number; features?: string; }; }; emailAuth?: { enabled?: boolean; skipIfAuthenticated?: boolean; api?: { requestOtp?: string; verifyOtp?: string; refreshToken?: string; logout?: string; }; sessionStorage?: { tokenKey?: string; refreshTokenKey?: string; userIdKey?: string; emailKey?: string; }; requestPayload?: { [key: string]: any; }; ui?: { title?: string; description?: string; emailPlaceholder?: string; otpPlaceholder?: string; submitButtonText?: string; resendButtonText?: string; resendCooldown?: number; verifyButtonText?: string; brandColor?: string; allowBackdropClose?: boolean; showCancelButton?: boolean; placeholderColor?: string; }; validation?: { otpLength?: number; otpTimeout?: number; rateLimiting?: { maxAttempts?: number; windowMinutes?: number; }; }; }; } export interface PaywallGateway { id: string; name: string; description?: string; icon?: string; color?: string; } export interface PlayerConfig extends VideoPlayerConfig { freeDuration?: number; paywall?: PaywallConfig; volume?: number; chapters?: ChapterConfig; }