ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
281 lines (280 loc) • 12.4 kB
TypeScript
import { SyncHook } from 'ranuts/utils';
import type { RaceGuard } from 'ranuts/utils';
import type { Progress } from '../progress';
import '@/components/select';
import { type PlayerControllerElements, type PlayerControllerHandlers } from './core/controller';
import { type PlaybackSnapshot } from './core/playback';
import { type PlayerMediaHandlers } from './core/media';
import type { EngineAdapter, EngineQualityLevel } from './core/adapters/types';
import { type PlayerRuntimeState } from './core/state';
import { type PlayerVisualSignals } from './core/store';
import { type PlayerVisualEffectRefs } from './core/effects';
import { type PlayerErrorModalController, type PlayerErrorModalDeps } from './core/error-modal';
import { type PlayerSeekDeps, type PlayerSeekHandlers } from './core/seek';
import { type PlayerChromeDeps, type PlayerChromeHandlers } from './core/chrome';
import { type PlayerMediaDispatchDeps } from './core/media-dispatch';
import { type PlayerClarityDeps, type PlayerClarityHandlers } from './core/clarity';
import { type PlayerSubtitleDeps, type PlayerSubtitleHandlers } from './core/subtitles';
import { type PlayerMetrics, type PlayerMetricsController } from './core/metrics';
import { type PlayerGestureController, type PlayerGestureDeps } from './core/gestures';
import { type ThumbnailCue } from './core/thumbnails';
import { type PlayerTrackConfig } from './core/tracks';
import { EventManager } from '../../utils/builder';
import { RanElement } from '../../utils';
type Callback = (...args: unknown[]) => unknown;
type EventName = string | symbol;
type EventItem = {
name?: string | symbol;
callback: Callback;
initialCallback?: Callback;
};
export declare class SHook {
private _events;
constructor();
tap: (eventName: EventName, eventItem: EventItem | Callback) => void;
call: (eventName: EventName, ...args: Array<unknown>) => void;
callSync: (eventName: EventName, ...args: Array<unknown>) => Promise<void>;
once: (eventName: EventName, eventItem: EventItem | Callback) => void;
off: (eventName: EventName, eventItem: EventItem | Callback) => void;
}
export interface Context {
action: SyncHook;
currentState: string;
duration: number;
currentTime: number;
/** 0-100, matches the `volume` attribute and `setVolume`/`getVolume` — not the native `<video>.volume` 0-1 scale. */
volume: number;
playbackRate: number;
fullScreen: boolean;
levels: EngineQualityLevel[];
url: string;
levelMap: Map<string, string>;
clarity: string;
}
export declare class RanPlayer extends RanElement {
ctx: Context;
_events: EventManager;
_visualSignals: PlayerVisualSignals;
_effectDisposers: Array<() => void>;
_player: HTMLDivElement;
_container: HTMLDivElement;
_playerController: HTMLDivElement;
_playerBtn: HTMLDivElement;
_progress: HTMLDivElement;
_progressDot: HTMLDivElement;
_progressWrap: HTMLDivElement;
_progressWrapBuffer: HTMLDivElement;
_progressWrapValue: HTMLDivElement;
/** Single source of truth for transient interaction state — see accessors below. */
_runtimeState: PlayerRuntimeState<PlaybackSnapshot>;
_playerControllerBottom: HTMLDivElement;
_playerControllerBottomRight: HTMLDivElement;
_playerControllerBottomLeft: HTMLDivElement;
_playerControllerBottomPlayBtn: HTMLDivElement;
_playerControllerBottomPlayBtnIcon: HTMLElement;
_playerControllerBottomTimeCurrent: HTMLDivElement;
_playerControllerBottomTimeDuration: HTMLDivElement;
_playerControllerBottomTimeDivide: HTMLDivElement;
_playControllerBottomClarity: HTMLElement;
_playControllerBottomSpeed: HTMLDivElement;
_playControllerBottomVolumeIcon: HTMLDivElement;
_playControllerBottomVolumeIconGlyph: HTMLElement;
_playControllerBottomVolumeProgress: Progress;
_playControllerBottomSubtitle: HTMLElement;
_playControllerBottomPip: HTMLDivElement;
_playControllerBottomRemote: HTMLDivElement;
_gestureFlash: HTMLDivElement;
_playControllerBottomRightFullScreen: HTMLDivElement;
_playControllerBottomVolume: HTMLDivElement;
_playControllerBottomSpeedPopover: HTMLElement;
_playerTip: HTMLDivElement;
_playerTipThumbnail: HTMLDivElement;
_playerTipTime: HTMLDivElement;
_playerTipText: HTMLDivElement;
_shadowDom: ShadowRoot;
_volume?: number;
_video?: HTMLVideoElement;
_engine?: EngineAdapter;
/** Set once `connectedCallback` has run for the first time — see its use in
* `attributeChangedCallback` below for why this exists. */
_didInitialConnect: boolean;
_tracks: PlayerTrackConfig[];
_thumbnailCues: ThumbnailCue[];
_thumbnailLoadGuard: RaceGuard;
/** Domain modules — each built once in the constructor from a narrow `getXxxDeps()` slice. */
_errorModal: PlayerErrorModalController;
_mediaHandlers: PlayerMediaHandlers;
_seek: PlayerSeekHandlers;
_chrome: PlayerChromeHandlers;
_clarity: PlayerClarityHandlers<EngineQualityLevel>;
_subtitles: PlayerSubtitleHandlers;
_metrics: PlayerMetricsController;
_gestures?: PlayerGestureController;
static get observedAttributes(): string[];
/**
* @description: 初始化 view 和 video 的全局上下文
* @return {*}
*/
constructor();
getVisualEffectRefs: () => PlayerVisualEffectRefs;
setupEffects: () => void;
disposeEffects: () => void;
getErrorModalDeps: () => PlayerErrorModalDeps;
getMediaDispatchDeps: () => PlayerMediaDispatchDeps;
getSeekDeps: () => PlayerSeekDeps;
getChromeDeps: () => PlayerChromeDeps;
getClarityDeps: () => PlayerClarityDeps<EngineQualityLevel>;
getGestureDeps: () => PlayerGestureDeps;
getSubtitleDeps: () => PlayerSubtitleDeps;
get src(): string;
set src(value: string);
get debug(): string;
set debug(value: string);
get volume(): string;
set volume(value: string);
get currentTime(): string;
set currentTime(value: string);
get playbackRate(): string;
set playbackRate(value: string);
get poster(): string;
set poster(value: string);
/**
* URL of a WebVTT sprite-sheet manifest (cues whose text is
* `spritesheet.jpg#xywh=x,y,w,h`, the YouTube/Video.js convention) — shows a
* cropped thumbnail above the seek-bar hover tip. Independent of `src`: not
* reset on a source reload, only refetched when this attribute itself changes.
*/
get thumbnails(): string;
set thumbnails(value: string);
/**
* @description: 强制指定引擎(`hls`/`dash`/`flv`/`webrtc`/`native`),给拿不到扩展名的
* 加签/无后缀流地址用;缺省时按 `src` 扩展名自动探测(见 `core/adapters/detect.ts`)。
* `webrtc`(WHEP 端点 URL)没有扩展名可探测,必须显式指定这个值。
*/
get format(): string;
set format(value: string);
get autoplay(): boolean;
set autoplay(value: boolean);
get loop(): boolean;
set loop(value: boolean);
get muted(): boolean;
set muted(value: boolean);
get disableErrorModal(): boolean;
set disableErrorModal(value: boolean);
get rememberPosition(): boolean;
set rememberPosition(value: boolean);
/**
* @description: 字幕/CC 轨道配置,imperative 属性而不是 attribute——player 会在每次
* `updatePlayer()` 时清空 light DOM,不能指望用户塞 `<track>` 子标签进去。
*/
get tracks(): PlayerTrackConfig[];
set tracks(value: PlayerTrackConfig[]);
get sheet(): string;
set sheet(value: string);
handlerExternalCss: () => void;
get moveProgress(): {
percentage: number;
mouseDown: boolean;
};
get _isSeeking(): boolean;
set _isSeeking(v: boolean);
get _wasPlayingBeforeSeek(): boolean;
set _wasPlayingBeforeSeek(v: boolean);
get _isSwitchingSource(): boolean;
set _isSwitchingSource(v: boolean);
get _pendingPlaybackRestore(): PlaybackSnapshot | undefined;
set _pendingPlaybackRestore(v: PlaybackSnapshot | undefined);
get controllerBarTimeId(): ReturnType<typeof setTimeout> | undefined;
set controllerBarTimeId(v: ReturnType<typeof setTimeout> | undefined);
get _isShowingErrorModal(): boolean;
resetTransientState: () => void;
capturePlaybackSnapshot: () => PlaybackSnapshot;
restorePlaybackSnapshot: (snapshot: PlaybackSnapshot) => void;
changeClarity: (e: Event) => void;
createClaritySelect: () => void;
manifestLoaded: (levels: EngineQualityLevel[]) => void;
hlsError: (payload: {
fatal: boolean;
detail: unknown;
}) => void;
applyTracks: () => void;
setSubtitleLanguage: (lang: string) => void;
changeSubtitleTrack: (e: Event) => void;
createSubtitleSelect: () => void;
/**
* QoE snapshot derived from the `change()` event stream since the current
* `src` started loading — see `core/metrics.ts`.
*/
getMetrics: () => PlayerMetrics;
/**
* Guarded by `_thumbnailLoadGuard` (`ranuts/utils`'s `createRaceGuard` —
* the same bump-and-compare pattern `r-loading`'s async variant loading
* uses) — if `thumbnails` changes again before this fetch resolves, the
* stale response is dropped instead of overwriting the newer manifest's cues.
*/
loadThumbnails: () => Promise<void>;
updatePlayer: () => void;
showErrorModal: (message: string) => void;
change: (name: string, value: unknown) => void;
getMediaHandlers: () => PlayerMediaHandlers;
clearListenerEvent: () => void;
listenEvent: () => void;
showControllerBar: (e?: MouseEvent) => void;
setLoadingState: (loading: boolean) => void;
dispatchClickPlayerContainerAction: (e: Event) => void;
SpaceKeyDown: (e: KeyboardEvent) => void;
dispatchClickPlayerBtnAction: (e: Event) => void;
onPlayBtnKeydown: (e: KeyboardEvent) => void;
onFullScreenKeydown: (e: KeyboardEvent) => void;
changeVolumeProgress: (e: Event) => void;
customRequestFullscreen: () => Promise<void>;
customExitFullscreen: () => Promise<void>;
openFullScreen: () => void;
syncPipButtonVisibility: () => void;
togglePip: () => void;
syncRemoteButtonVisibility: () => void;
showRemotePlaybackPicker: () => void;
changeSpeed: (e: Event) => void;
changePlayerVolume: () => void;
resize: () => void;
onVisibilityChange: () => void;
fullScreenChange: () => void;
updateBufferedProgress: () => void;
syncProgressByPercentage: (percentage: number) => void;
seekToPercentage: (percentage: number) => void;
progressClick: (e: MouseEvent) => void;
onProgressKeydown: (e: KeyboardEvent) => void;
progressDotPointerDown: (e: PointerEvent) => void;
progressDotMouseMove: (e: MouseEvent) => void;
progressDotPointerMove: (e: PointerEvent) => void;
progressDotPointerUp: () => void;
progressDotPointerCancel: () => void;
requestAnimationFrame: (fn: Function) => void;
cancelAnimationFrame: () => void;
updateCurrentProgress: () => void;
progressMouseEnter: (e: MouseEvent) => void;
progressMouseLeave: (e: MouseEvent) => void;
progressMouseMove: (e: MouseEvent) => void;
getPlaybackRate: () => number;
setPlaybackRate: (n: number) => number;
/**
* @description: 0-100 制,和 `volume` 属性、音量滑块一致;`<video>.volume` 是原生 0-1 制,只在这里做换算。
* 顺带把原生 `<video>.muted` 和"音量是否为 0"绑在一起——这样 `volume=0` 才会真正满足浏览器的
* "muted autoplay" 免打扰策略(单纯把 volume 设成 0 不等于 `.muted === true`,某些浏览器的
* autoplay 判定只认后者),而不用再维护一个独立于音量的"是否静音"状态。
*/
setVolume: (n: number) => number;
getVolume: () => number;
setCurrentTime: (n: number) => number;
getCurrentTime: () => number;
getTotalTime: () => number;
safePlay: (showLoading: boolean) => void;
play: (n?: number) => void;
pause: () => void;
getControllerElements: () => PlayerControllerElements;
getControllerHandlers: () => PlayerControllerHandlers;
connectedCallback(): void;
disconnectedCallback(): void;
attributeChangedCallback(k: string, o: string, n: string): void;
}
export default RanPlayer;