mirror of
https://github.com/zoriya/v10.git
synced 2026-08-11 08:29:47 +00:00
refactor(core): centralize feature state types (#448)
This commit is contained in:
@@ -34,3 +34,104 @@ export interface PlaybackState {
|
||||
*/
|
||||
pause(): void;
|
||||
}
|
||||
|
||||
/** Indicates whether a feature can be programmatically controlled on this platform. */
|
||||
export type FeatureAvailability = 'available' | 'unavailable' | 'unsupported';
|
||||
|
||||
export interface VolumeState {
|
||||
/**
|
||||
* Volume level from 0 (silent) to 1 (max).
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume
|
||||
*/
|
||||
volume: number;
|
||||
/**
|
||||
* Whether audio is muted.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/muted
|
||||
*/
|
||||
muted: boolean;
|
||||
/**
|
||||
* Whether volume can be programmatically set on this platform.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume
|
||||
*/
|
||||
volumeAvailability: FeatureAvailability;
|
||||
/**
|
||||
* Set volume (clamped 0-1). Returns the clamped value.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume
|
||||
*/
|
||||
changeVolume(volume: number): number;
|
||||
/**
|
||||
* Toggle mute state. Returns the new muted value.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/muted
|
||||
*/
|
||||
toggleMute(): boolean;
|
||||
}
|
||||
|
||||
export interface TimeState {
|
||||
/**
|
||||
* Current playback position in seconds.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime
|
||||
*/
|
||||
currentTime: number;
|
||||
/**
|
||||
* Total duration in seconds (0 if unknown).
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration
|
||||
*/
|
||||
duration: number;
|
||||
/**
|
||||
* Whether a seek operation is in progress.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeking
|
||||
*/
|
||||
seeking: boolean;
|
||||
/**
|
||||
* Seek to a time in seconds. Returns the actual position after seek.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime
|
||||
*/
|
||||
seek(time: number): Promise<number>;
|
||||
}
|
||||
|
||||
export interface SourceState {
|
||||
/**
|
||||
* Current media source URL (null if none).
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentSrc
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/src
|
||||
*/
|
||||
source: string | null;
|
||||
/**
|
||||
* Whether enough data is loaded to begin playback.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
|
||||
*/
|
||||
canPlay: boolean;
|
||||
/**
|
||||
* Load a new media source. Returns the new source URL.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/src
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/load
|
||||
*/
|
||||
loadSource(src: string): string;
|
||||
}
|
||||
|
||||
export interface BufferState {
|
||||
/**
|
||||
* Buffered time ranges as [start, end] tuples.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered
|
||||
*/
|
||||
buffered: [number, number][];
|
||||
/**
|
||||
* Seekable time ranges as [start, end] tuples.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seekable
|
||||
*/
|
||||
seekable: [number, number][];
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface PlayerTarget {
|
||||
container: MediaContainer | null;
|
||||
}
|
||||
|
||||
export type FeatureAvailability = 'available' | 'unavailable' | 'unsupported';
|
||||
export type { FeatureAvailability } from '../../core/media/state';
|
||||
|
||||
export type PlayerFeature<State> = Slice<PlayerTarget, State>;
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import type { InferSliceState } from '@videojs/store';
|
||||
import { listen, serializeTimeRanges } from '@videojs/utils/dom';
|
||||
|
||||
import type { BufferState } from '../../../core/media/state';
|
||||
import { definePlayerFeature } from '../../feature';
|
||||
|
||||
export const bufferFeature = definePlayerFeature({
|
||||
state: () => ({
|
||||
/** Buffered time ranges as [start, end] tuples. */
|
||||
buffered: [] as [number, number][],
|
||||
/** Seekable time ranges as [start, end] tuples. */
|
||||
seekable: [] as [number, number][],
|
||||
state: (): BufferState => ({
|
||||
buffered: [],
|
||||
seekable: [],
|
||||
}),
|
||||
|
||||
attach({ target, signal, set }) {
|
||||
@@ -26,5 +24,3 @@ export const bufferFeature = definePlayerFeature({
|
||||
listen(media, 'emptied', sync, { signal });
|
||||
},
|
||||
});
|
||||
|
||||
export type BufferState = InferSliceState<typeof bufferFeature>;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import type { InferSliceState } from '@videojs/store';
|
||||
import { listen } from '@videojs/utils/dom';
|
||||
|
||||
import type { SourceState } from '../../../core/media/state';
|
||||
import { definePlayerFeature } from '../../feature';
|
||||
|
||||
export const sourceFeature = definePlayerFeature({
|
||||
state: ({ target, abort }) => ({
|
||||
/** Current media source URL (null if none). */
|
||||
source: null as string | null,
|
||||
/** Whether enough data is loaded to begin playback. */
|
||||
state: ({ target, abort }): SourceState => ({
|
||||
source: null,
|
||||
canPlay: false,
|
||||
/** Load a new media source. Returns the new source URL. */
|
||||
loadSource(src: string) {
|
||||
abort(); // Cancel pending operations (e.g., seek)
|
||||
|
||||
@@ -38,5 +35,3 @@ export const sourceFeature = definePlayerFeature({
|
||||
listen(media, 'emptied', sync, { signal });
|
||||
},
|
||||
});
|
||||
|
||||
export type SourceState = InferSliceState<typeof sourceFeature>;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { InferSliceState } from '@videojs/store';
|
||||
import { listen, onEvent } from '@videojs/utils/dom';
|
||||
import { noop } from '@videojs/utils/function';
|
||||
import type { TimeState } from '../../../core/media/state';
|
||||
import { definePlayerFeature } from '../../feature';
|
||||
import { hasMetadata } from '../../media/predicate';
|
||||
|
||||
export const timeFeature = definePlayerFeature({
|
||||
state: ({ target, signal }) => {
|
||||
state: ({ target, signal }): TimeState => {
|
||||
let abort: AbortController | null = null;
|
||||
|
||||
const supersede = () => {
|
||||
@@ -15,13 +15,9 @@ export const timeFeature = definePlayerFeature({
|
||||
};
|
||||
|
||||
return {
|
||||
/** Current playback position in seconds. */
|
||||
currentTime: 0,
|
||||
/** Total duration in seconds (0 if unknown). */
|
||||
duration: 0,
|
||||
/** Whether a seek operation is in progress. */
|
||||
seeking: false,
|
||||
/** Seek to a time in seconds. Returns the actual position after seek. */
|
||||
async seek(time: number) {
|
||||
const { media } = target(),
|
||||
signal = supersede();
|
||||
@@ -62,5 +58,3 @@ export const timeFeature = definePlayerFeature({
|
||||
listen(media, 'emptied', sync, { signal });
|
||||
},
|
||||
});
|
||||
|
||||
export type TimeState = InferSliceState<typeof timeFeature>;
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
import type { InferSliceState } from '@videojs/store';
|
||||
import { listen } from '@videojs/utils/dom';
|
||||
|
||||
import type { FeatureAvailability, VolumeState } from '../../../core/media/state';
|
||||
import { definePlayerFeature } from '../../feature';
|
||||
import type { FeatureAvailability } from '../../media/types';
|
||||
|
||||
export const volumeFeature = definePlayerFeature({
|
||||
state: ({ target }) => ({
|
||||
/** Volume level from 0 (silent) to 1 (max). */
|
||||
state: ({ target }): VolumeState => ({
|
||||
volume: 1,
|
||||
/** Whether audio is muted. */
|
||||
muted: false,
|
||||
/** Whether volume can be programmatically set on this platform. */
|
||||
volumeAvailability: 'unavailable' as FeatureAvailability,
|
||||
volumeAvailability: 'unavailable',
|
||||
|
||||
/** Set volume (clamped 0-1). Returns the clamped value. */
|
||||
changeVolume(volume: number) {
|
||||
const { media } = target();
|
||||
media.volume = Math.max(0, Math.min(1, volume));
|
||||
return media.volume;
|
||||
},
|
||||
|
||||
/** Toggle mute state. Returns new muted value. */
|
||||
toggleMute() {
|
||||
const { media } = target();
|
||||
media.muted = !media.muted;
|
||||
@@ -40,8 +34,6 @@ export const volumeFeature = definePlayerFeature({
|
||||
},
|
||||
});
|
||||
|
||||
export type VolumeState = InferSliceState<typeof volumeFeature>;
|
||||
|
||||
/** Check if volume can be programmatically set (fails on iOS Safari). */
|
||||
function canSetVolume(): FeatureAvailability {
|
||||
const video = document.createElement('video');
|
||||
|
||||
Reference in New Issue
Block a user