mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(core): add error feature (#713)
This commit is contained in:
@@ -206,6 +206,32 @@ export interface MediaTextTrackState {
|
||||
thumbnailTrackSrc: string | null;
|
||||
}
|
||||
|
||||
export interface MediaError {
|
||||
/**
|
||||
* The error code (mirrors MediaError.code constants).
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code
|
||||
*/
|
||||
code: number;
|
||||
/**
|
||||
* A human-readable error message.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/MediaError/message
|
||||
*/
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface MediaErrorState {
|
||||
/**
|
||||
* The current media error, or null if none.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/error
|
||||
*/
|
||||
error: MediaError | null;
|
||||
/** Dismiss the current error by clearing it. */
|
||||
dismissError(): void;
|
||||
}
|
||||
|
||||
export interface MediaPictureInPictureState {
|
||||
/**
|
||||
* Whether picture-in-picture mode is currently active.
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { AnySlice, Slice, Store, UnionSliceState } from '@videojs/store';
|
||||
import type {
|
||||
MediaBufferState,
|
||||
MediaControlsState,
|
||||
MediaErrorState,
|
||||
MediaFullscreenState,
|
||||
MediaPictureInPictureState,
|
||||
MediaPlaybackRateState,
|
||||
@@ -55,6 +56,7 @@ export type VideoFeatures = [
|
||||
PlayerFeature<MediaPictureInPictureState>,
|
||||
PlayerFeature<MediaControlsState>,
|
||||
PlayerFeature<MediaTextTrackState>,
|
||||
PlayerFeature<MediaErrorState>,
|
||||
];
|
||||
|
||||
export type AudioFeatures = [
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { listen } from '@videojs/utils/dom';
|
||||
|
||||
import type { MediaErrorState } from '../../../core/media/state';
|
||||
import { definePlayerFeature } from '../../feature';
|
||||
|
||||
export const errorFeature = definePlayerFeature({
|
||||
name: 'error',
|
||||
state: ({ set }): MediaErrorState => ({
|
||||
error: null,
|
||||
dismissError() {
|
||||
set({ error: null });
|
||||
},
|
||||
}),
|
||||
|
||||
attach({ target, signal, set }) {
|
||||
const { media } = target;
|
||||
|
||||
const syncError = () => set({ error: media.error });
|
||||
|
||||
listen(media, 'error', syncError, { signal });
|
||||
|
||||
// Reset error state when a new source is loaded.
|
||||
listen(media, 'emptied', () => set({ error: null }), { signal });
|
||||
},
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './buffer';
|
||||
export * from './controls';
|
||||
export * from './error';
|
||||
export * as features from './feature.parts';
|
||||
export * from './fullscreen';
|
||||
export * from './pip';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { AudioFeatures, BackgroundFeatures, VideoFeatures } from '../../media/types';
|
||||
import { bufferFeature } from './buffer';
|
||||
import { controlsFeature } from './controls';
|
||||
import { errorFeature } from './error';
|
||||
import { fullscreenFeature } from './fullscreen';
|
||||
import { pipFeature } from './pip';
|
||||
import { playbackFeature } from './playback';
|
||||
@@ -21,6 +22,7 @@ export const videoFeatures: VideoFeatures = [
|
||||
pipFeature,
|
||||
controlsFeature,
|
||||
textTrackFeature,
|
||||
errorFeature,
|
||||
];
|
||||
|
||||
export const audioFeatures: AudioFeatures = [
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createSelector } from '@videojs/store';
|
||||
|
||||
import { bufferFeature } from './features/buffer';
|
||||
import { controlsFeature } from './features/controls';
|
||||
import { errorFeature } from './features/error';
|
||||
import { fullscreenFeature } from './features/fullscreen';
|
||||
import { pipFeature } from './features/pip';
|
||||
import { playbackFeature } from './features/playback';
|
||||
@@ -15,6 +16,8 @@ import { volumeFeature } from './features/volume';
|
||||
export const selectBuffer = createSelector(bufferFeature);
|
||||
/** Select the controls state (controls visible, user-active). */
|
||||
export const selectControls = createSelector(controlsFeature);
|
||||
/** Select the error state (error, dismissed, dismissError). */
|
||||
export const selectError = createSelector(errorFeature);
|
||||
/** Select the fullscreen state (fullscreen active, availability). */
|
||||
export const selectFullscreen = createSelector(fullscreenFeature);
|
||||
/** Select the PiP state (picture-in-picture active, availability). */
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { AnySlice, InferSliceState, StateContext } from './slice';
|
||||
const stateContext: StateContext<unknown> = {
|
||||
target: throwNoTargetError,
|
||||
signals: new AbortControllerRegistry(),
|
||||
set: throwNoTargetError,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,8 @@ export interface StateContext<Target> {
|
||||
* (e.g., loading a new source cancels pending seeks).
|
||||
*/
|
||||
signals: AbortControllerRegistry;
|
||||
/** Patch the slice state. Safe to use inside action closures (not during `state()` init). */
|
||||
set: (partial: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
@@ -38,6 +38,7 @@ export function createStore<Target = unknown>(): <State>(
|
||||
return target!;
|
||||
},
|
||||
signals,
|
||||
set: (partial) => state.patch(partial as Partial<State>),
|
||||
} satisfies StateContext<Target>);
|
||||
|
||||
state = createState(initialState);
|
||||
|
||||
Reference in New Issue
Block a user