Skip to content

Commit fa46745

Browse files
committed
[IMPL] useVideo hook
1 parent 1774994 commit fa46745

15 files changed

Lines changed: 386 additions & 197 deletions

File tree

apps/react-tools-demo/src/components/hooks/useAudio/UseAudio.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import audio from '../../../assets/bubbles.mp3';
55
The component use _useAudio_ hook to use an audio track.
66
*/
77
export const UseAudio = () => {
8-
const { state, play, pause } = useAudio({ url: audio, loop: true });
8+
const {MediaElement, state, controls: {play, pause}} = useAudio({ src: audio, controls: true });
99

1010
return <div>
11-
<p>Status: {state.status}</p>
12-
<button onClick={play} disabled={state.status === "playing"}>Play</button>
13-
<button onClick={pause} disabled={state.status !== "playing"}>Pause</button>
11+
{MediaElement}
12+
<p>Status: {state.paused ? "paused" : state.playing ? "playing" : "ready"}</p>
13+
<button onClick={play} disabled={state.playing}>Play</button>
14+
<button onClick={pause} disabled={state.paused}>Pause</button>
1415
</div>
1516
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useVideo } from '../../../../../../packages/react-tools/src';
2+
import video from './../../../assets/mov_bbb.mp4';
3+
4+
/**
5+
The component use _useVideo_ hook to use a video track.
6+
*/
7+
export const UseVideo = () => {
8+
const {MediaElement, state, controls: {play, pause}} = useVideo({ src: video, controls: true });
9+
10+
return <div>
11+
{MediaElement}
12+
<p>Status: {state.paused ? "paused" : state.playing ? "playing" : "ready"}</p>
13+
<button onClick={play} disabled={state.playing}>Play</button>
14+
<button onClick={pause} disabled={state.paused}>Pause</button>
15+
</div>
16+
}

apps/react-tools-demo/src/constants/components.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ export const COMPONENTS = [
107107
"usePopover",
108108
"useRemotePlayback",
109109
"useAnimation",
110-
"useAudio"
110+
"useAudio",
111+
"useVideo"
111112
]
112113
],
113114
//UTILS
Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
# useAudio
2-
Hook to use an Audio source.
2+
Hook to use an HTML audio element.
33

44
## Usage
55

66
```tsx
77
export const UseAudio = () => {
8-
const { state, play, pause } = useAudio({ url: audio });
8+
const {MediaElement, state, controls: {play, pause}} = useAudio({ src: audio, controls: true });
99

1010
return <div>
11-
<p>Status: {state.status}</p>
12-
<button onClick={play} disabled={state.status === "playing"}>Play</button>
13-
<button onClick={pause} disabled={state.status !== "playing"}>Pause</button>
11+
{MediaElement}
12+
<p>Status: {state.paused ? "paused" : state.playing ? "playing" : "ready"}</p>
13+
<button onClick={play} disabled={state.playing}>Play</button>
14+
<button onClick={pause} disabled={state.paused}>Pause</button>
1415
</div>
1516
}
1617
```
@@ -21,40 +22,36 @@ export const UseAudio = () => {
2122
## API
2223

2324
```tsx
24-
useAudio({ url, volume, loop, defaultMuted, autoPlay, playbackRate, onError }: UseAudioProps): UseAudioResult
25+
useAudiocreateHTMLMediaHook<HTMLAudioElement>("audio");
2526
```
2627

2728
> ### Params
2829
>
2930
> - __param__: _UseAudioProps_
30-
object
31-
> - __param.url?__: _string_
32-
An optional string containing the URL of an audio file to be associated with the new audio element.
33-
> - __param.volume?__: _number_
34-
A double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest).
35-
> - __param.loop?__: _boolean_
36-
A boolean that reflects the loop HTML attribute, which indicates whether the media element should start over when it reaches the end.
37-
> - __param.defaultMuted?__: _boolean_
38-
A boolean that reflects the muted HTML attribute, which indicates whether the media element's audio output should be muted by default.
39-
> - __param.autoPlay?__: _boolean_
40-
A boolean value that reflects the autoplay HTML attribute, indicating whether playback should automatically begin as soon as enough media is available to do so without interruption.
41-
> - __param.playbackRate?__: _number_
42-
A double that indicates the rate at which the media is being played back.
43-
> - __param.onError] ?__: _OnErrorEventHandler_
31+
Media HTML Attributes of an html audio element.
4432
>
4533
4634
> ### Returns
4735
>
4836
> __result__: _UseAudioResult_
4937
> Object with these properties:
5038
> - __state__: object with current audio properties:
51-
> - _status_: value between __"unavailable"__ __"ready"__ __"playing"__ __"pause"__ indicating current audio status.
52-
> - _volume_: current audio volume.
53-
> - _playbackRate_: current audio playbackRate.
54-
> - __setAudio__: function to set audio.
55-
> - __setPlaybackRate__: function to set audio playbackRate.
56-
> - __setVolume__: function to set audio volume.
57-
> - __play__: function to play audio.
58-
> - __pause__: function to pause audio.
59-
> - __load__: function to reload audio.
39+
> - _buffered_: array of objects, with __start__ and __end__ properties, or null. It indicates the ranges of the media source that the browser has buffered (if any) at the moment the buffered property is accessed.
40+
> undefined
41+
> undefined
42+
> undefined
43+
> undefined
44+
> undefined
45+
> undefined
46+
> undefined
47+
> - __controls__: object with current audio properties:
48+
> - _play_: function to set audio.
49+
> - _pause_: function to pause audio.
50+
> - _mute_: function to mute audio.
51+
> - _unmute_: function to unmute audio.
52+
> - _playbackRate_: function to set audio playbackRate.
53+
> - _volume_: function to set audio volume.
54+
> - _seek_: function to seek to the given time with low precision.
55+
> - MediaElement: HTMLAudioElement to render.
56+
> - ref: ref to HTMLAudioElement.
6057
>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# useVideo
2+
Hook to use an HTML video element.
3+
4+
## Usage
5+
6+
```tsx
7+
export const UseVideo = () => {
8+
const {MediaElement, state, controls: {play, pause}} = useVideo({ src: video, controls: true });
9+
10+
return <div>
11+
{MediaElement}
12+
<p>Status: {state.paused ? "paused" : state.playing ? "playing" : "ready"}</p>
13+
<button onClick={play} disabled={state.playing}>Play</button>
14+
<button onClick={pause} disabled={state.paused}>Pause</button>
15+
</div>
16+
}
17+
```
18+
19+
> The component use _useVideo_ hook to use a video track.
20+
21+
22+
## API
23+
24+
```tsx
25+
useVideocreateHTMLMediaHook<HTMLVideoElement>("video");
26+
```
27+
28+
> ### Params
29+
>
30+
> - __param__: _UseVideoProps_
31+
Media HTML Attributes of an html video element.
32+
>
33+
34+
> ### Returns
35+
>
36+
> __result__: _UseVideoResult_
37+
> Object with these properties:
38+
> - __state__: object with current video properties:
39+
> - _buffered_: array of objects, with __start__ and __end__ properties, or null. It indicates the ranges of the media source that the browser has buffered (if any) at the moment the buffered property is accessed.
40+
> undefined
41+
> undefined
42+
> undefined
43+
> undefined
44+
> undefined
45+
> undefined
46+
> undefined
47+
> - __controls__: object with current video properties:
48+
> - _play_: function to set video.
49+
> - _pause_: function to pause video.
50+
> - _mute_: function to mute video.
51+
> - _unmute_: function to unmute video.
52+
> - _playbackRate_: function to set video playbackRate.
53+
> - _volume_: function to set video volume.
54+
> - _seek_: function to seek to the given time with low precision.
55+
> - MediaElement: HTMLVideoElement to render.
56+
> - ref: ref to HTMLVideoElement.
57+
>

packages/react-tools/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
- [x] useRemotePlayback
111111
- [x] useAnimation
112112
- [x] useAudio
113-
- [ ] useVideo (???)
113+
- [x] useVideo
114114
- [ ] useEventSource (https://vueuse.org/core/useEventSource/)
115115
- [ ] useWebSocket (https://vueuse.org/core/useWebSocket/)
116116
- [ ] useFetch (with suspense ???)

packages/react-tools/src/hooks/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,5 @@ export { useDocumentPIP } from './useDocumentPIP';
8787
export { usePopover } from './usePopover';
8888
export { useRemotePlayback } from './useRemotePlayback';
8989
export { useAnimation } from './useAnimation';
90-
export { useAudio } from './useAudio';
90+
export { useAudio } from './useAudio';
91+
export { useVideo } from './useVideo';
Lines changed: 23 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,29 @@
1-
import { useCallback, useRef } from "react"
2-
import { useEffectOnce, useSyncExternalStore } from ".";
3-
import { UseAudioProps, UseAudioResult } from "../models";
1+
import createHTMLMediaHook from "../utils/createHTMLMediaElement";
42

53
/**
6-
* **`useAudio`**: Hook to use an Audio source.
7-
* @param {UseAudioProps} param - object
8-
* @param {string} [param.url] - An optional string containing the URL of an audio file to be associated with the new audio element.
9-
* @param {number} [param.volume] - A double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest).
10-
* @param {boolean} [param.loop] - A boolean that reflects the loop HTML attribute, which indicates whether the media element should start over when it reaches the end.
11-
* @param {boolean} [param.defaultMuted] - A boolean that reflects the muted HTML attribute, which indicates whether the media element's audio output should be muted by default.
12-
* @param {number} [param.playbackRate] - A double that indicates the rate at which the media is being played back.
13-
* @param {OnErrorEventHandler} [param.onError] -
4+
* **`useAudio`**: Hook to use an HTML audio element.
5+
* @param {UseAudioProps} param - Media HTML Attributes of an html audio element.
146
* @returns {UseAudioResult} result
157
* Object with these properties:
168
* - __state__: object with current audio properties:
17-
* - _status_: value between __"unavailable"__ __"ready"__ __"playing"__ __"pause"__ indicating current audio status.
18-
* - _volume_: current audio volume.
19-
* - _playbackRate_: current audio playbackRate.
20-
* - __setAudio__: function to set audio.
21-
* - __setPlaybackRate__: function to set audio playbackRate.
22-
* - __setVolume__: function to set audio volume.
23-
* - __play__: function to play audio.
24-
* - __pause__: function to pause audio.
25-
* - __load__: function to reload audio.
9+
* - _buffered_: array of objects, with __start__ and __end__ properties, or null. It indicates the ranges of the media source that the browser has buffered (if any) at the moment the buffered property is accessed.
10+
- _duration_: a read-only double-precision floating-point value indicating the total duration of the media in seconds. If no media data is available, the returned value is NaN.
11+
- _paused_: returns a boolean that indicates whether the media element is paused.
12+
- _muted_: boolean that determines whether audio is muted. true if the audio is muted and false otherwise.
13+
- _time_: value indicating the current playback time in seconds; if the media has not started to play and has not been seeked, this value is the media's initial playback time. Setting this value seeks the media to the new time. The time is specified relative to the media's timeline.
14+
- _volume_: double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest).
15+
- _playbackRate_: double that indicates the rate at which the media is being played back.
16+
- _playing_: boolean indicating if audio is playing or not.
17+
* - __controls__: object with current audio properties:
18+
* - _play_: function to set audio.
19+
* - _pause_: function to pause audio.
20+
* - _mute_: function to mute audio.
21+
* - _unmute_: function to unmute audio.
22+
* - _playbackRate_: function to set audio playbackRate.
23+
* - _volume_: function to set audio volume.
24+
* - _seek_: function to seek to the given time with low precision.
25+
* - MediaElement: HTMLAudioElement to render.
26+
* - ref: ref to HTMLAudioElement.
2627
*/
27-
export const useAudio = ({ url, volume, loop, defaultMuted, playbackRate, onError }: UseAudioProps): UseAudioResult => {
28-
const notifyRef = useRef<() => void>();
29-
const audioRef = useRef<HTMLAudioElement>();
30-
const status = useRef<"unavailable" | "ready" | "playing" | "pause">(!url ? "unavailable" : "ready");
31-
const stateCached = useRef<{ status: "unavailable" | "ready" | "playing" | "pause", volume?: number, playbackRate?: number }>({
32-
status: !url ? "unavailable" : "ready",
33-
playbackRate,
34-
volume
35-
});
36-
37-
const setAudio = useCallback((audio: string, autoPlay?: boolean) => {
38-
audioRef.current && (audioRef.current.pause(), audioRef.current.src = "");
39-
audioRef.current = new Audio(audio);
40-
audioRef.current.autoplay = !!autoPlay;
41-
stateCached.current?.volume && (audioRef.current.volume = stateCached.current.volume);
42-
stateCached.current?.playbackRate && (audioRef.current.playbackRate = stateCached.current.playbackRate);
43-
status.current = "ready";
44-
audioRef.current.onended = () => {
45-
status.current = "ready";
46-
notifyRef.current && notifyRef.current();
47-
}
48-
!!onError && (audioRef.current.onerror = onError);
49-
notifyRef.current && notifyRef.current();
50-
}, [onError]);
51-
52-
const setVolume = useCallback((volume: number) => {
53-
stateCached.current = {
54-
...stateCached.current,
55-
volume
56-
};
57-
audioRef.current && (audioRef.current.volume = volume);
58-
notifyRef.current && notifyRef.current();
59-
}, []);
60-
61-
const setPlaybackRate = useCallback((playbackRate: number) => {
62-
stateCached.current = {
63-
...stateCached.current,
64-
playbackRate
65-
};
66-
audioRef.current && (audioRef.current.playbackRate = playbackRate);
67-
notifyRef.current && notifyRef.current();
68-
}, []);
69-
70-
const play = useCallback(() => {
71-
status.current = "playing";
72-
audioRef.current && audioRef.current.play();
73-
notifyRef.current && notifyRef.current();
74-
}, []);
75-
76-
const pause = useCallback(() => {
77-
status.current = "pause";
78-
audioRef.current && audioRef.current.pause();
79-
notifyRef.current && notifyRef.current();
80-
}, []);
81-
82-
const load = useCallback(() => {
83-
status.current = "ready";
84-
audioRef.current && audioRef.current.load();
85-
notifyRef.current && notifyRef.current();
86-
}, [])
87-
88-
useEffectOnce(() => () => {
89-
audioRef.current && (audioRef.current.src = "");
90-
audioRef.current = undefined;
91-
})
92-
93-
const state = useSyncExternalStore(
94-
useCallback(notif => {
95-
notifyRef.current = notif;
96-
return () => {
97-
notifyRef.current = undefined;
98-
};
99-
}, []),
100-
useCallback(() => {
101-
if (status.current !== stateCached.current.status) {
102-
stateCached.current = {
103-
...stateCached.current,
104-
status: status.current
105-
}
106-
}
107-
if (audioRef.current) {
108-
if (audioRef.current.volume !== stateCached.current.volume || audioRef.current.playbackRate !== stateCached.current.playbackRate) {
109-
stateCached.current = {
110-
...stateCached.current,
111-
volume: audioRef.current.volume,
112-
playbackRate: audioRef.current.playbackRate
113-
}
114-
}
115-
}
116-
return stateCached.current
117-
}, [])
118-
);
119-
120-
if (!audioRef.current && url) {
121-
audioRef.current = new Audio(url);
122-
!!volume && (audioRef.current.volume = volume);
123-
!!playbackRate && (audioRef.current.playbackRate = playbackRate);
124-
!!loop && (audioRef.current.loop = loop);
125-
!!defaultMuted && (audioRef.current.defaultMuted = defaultMuted);
126-
stateCached.current.playbackRate = audioRef.current.playbackRate;
127-
stateCached.current.volume = audioRef.current.volume;
128-
audioRef.current.onended = () => {
129-
status.current = "ready";
130-
notifyRef.current && notifyRef.current();
131-
}
132-
!!onError && (audioRef.current.onerror = onError);
133-
notifyRef.current && notifyRef.current();
134-
}
135-
136-
return {
137-
state,
138-
setAudio,
139-
setPlaybackRate,
140-
setVolume,
141-
play,
142-
pause,
143-
load,
144-
}
145-
}
28+
const useAudio = createHTMLMediaHook<HTMLAudioElement>("audio");
29+
export {useAudio}

0 commit comments

Comments
 (0)