UNPKG

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
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;