@ldelia/react-media 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/README.md +1 -4
  2. package/package.json +2 -1
  3. package/src/components/index.js +1 -0
  4. package/src/components/index.ts +1 -0
  5. package/src/components/reproduction-widget/README.md +27 -0
  6. package/src/components/reproduction-widget/ReproductionWidget.js +29 -0
  7. package/src/components/reproduction-widget/ReproductionWidget.tsx +68 -0
  8. package/src/components/reproduction-widget/index.js +1 -0
  9. package/src/components/reproduction-widget/index.tsx +1 -0
  10. package/src/components/reproduction-widget/inner-players/PlayAlongInnerPlayer.js +5 -0
  11. package/src/components/reproduction-widget/inner-players/PlayAlongInnerPlayer.tsx +10 -0
  12. package/src/components/reproduction-widget/inner-players/YouTubeInnerPlayer.js +21 -0
  13. package/src/components/reproduction-widget/inner-players/YouTubeInnerPlayer.tsx +36 -0
  14. package/src/components/reproduction-widget/models/Player/PlayAlongPlayer.js +97 -0
  15. package/src/components/reproduction-widget/models/Player/PlayAlongPlayer.ts +129 -0
  16. package/src/components/reproduction-widget/models/Player/PlayerEvents.js +4 -0
  17. package/src/components/reproduction-widget/models/Player/PlayerEvents.ts +4 -0
  18. package/src/components/reproduction-widget/models/Player/YouTubePlayer.js +126 -0
  19. package/src/components/reproduction-widget/models/Player/YouTubePlayer.ts +171 -0
  20. package/src/components/reproduction-widget/models/Reproduction.js +214 -0
  21. package/src/components/reproduction-widget/models/Reproduction.ts +272 -0
  22. package/src/components/reproduction-widget/models/ReproductionBuilder.js +51 -0
  23. package/src/components/reproduction-widget/models/ReproductionBuilder.ts +70 -0
  24. package/src/stories/reproduction-widget.stories.js +16 -0
  25. package/src/stories/reproduction-widget.stories.tsx +23 -0
package/README.md CHANGED
@@ -5,10 +5,7 @@ A React components collection for media-related features.
5
5
  ## Available Components
6
6
 
7
7
  - Timeline ([Docs](./src/components/timeline/README.md))
8
-
9
- ## In Progress
10
-
11
- - Audio/Video player
8
+ - ReproductionWidget ([Docs](./src/components/reproduction-widget/README.md))
12
9
 
13
10
  ## Storybook
14
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ldelia/react-media",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "A React components collection for media-related features.",
5
5
  "private": false,
6
6
  "keywords": [
@@ -48,6 +48,7 @@
48
48
  "react-dev-utils": "^12.0.1",
49
49
  "react-dom": "^18.3.1",
50
50
  "react-refresh": "^0.11.0",
51
+ "react-youtube": "^10.1.0",
51
52
  "resolve": "^1.20.0",
52
53
  "resolve-url-loader": "^5.0.0",
53
54
  "sass-loader": "^12.3.0",
@@ -1 +1,2 @@
1
+ export * from './reproduction-widget';
1
2
  export * from './timeline';
@@ -1 +1,2 @@
1
+ export * from './reproduction-widget';
1
2
  export * from './timeline';
@@ -0,0 +1,27 @@
1
+ # ReproductionWidget
2
+
3
+ <!-- STORY -->
4
+
5
+ <hr>
6
+
7
+ A reproduction player that exposes an object that allows users to play around with the reproduction, e.g., stop/pause it.
8
+ Currently, it supports YouTube videos and a silent mode, meaning a reproduction without associated media, ideal for playing an instrument without any music but with the time running.
9
+
10
+
11
+ ## Usage
12
+
13
+ ```jsx
14
+ <ReproductionWidget
15
+ trainingMode={true}
16
+ videoId={'jFI-RBqXzhU'}
17
+ onInit={(reproduction) => { reproduction.start() }}
18
+ />
19
+ ```
20
+
21
+ ##### Required props
22
+
23
+ | Name | Type | Description |
24
+ |----------------|------------|-------------------------------------------------------------------------------------|
25
+ | `trainingMode` | `boolean` | If true, will reproduce the video with youtube, otherwise, silent mode will be used |
26
+ | `videoId` | `string` | YouTube video id (required if trainingMode === true) |
27
+ | `onInit` | `function` | Fired when the reproduction is ready to use |
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import { YouTubeInnerPlayer } from './inner-players/YouTubeInnerPlayer';
3
+ import { PlayAlongInnerPlayer } from './inner-players/PlayAlongInnerPlayer';
4
+ import { Reproduction } from './models/Reproduction';
5
+ export const ReproductionWidget = ({ trainingMode, videoId, onInit, }) => {
6
+ const DURATION_TO_TEST = 30;
7
+ const TEMPO_TO_TEST = 90;
8
+ const WITH_COUNTING_IN_TEST = true;
9
+ function onPlayAlongInnerPlayerReadyHandler(event) {
10
+ let newReproduction = Reproduction.newBuilder()
11
+ .withTrainingMode(false)
12
+ .withSongDuration(DURATION_TO_TEST)
13
+ .withSongTempo(TEMPO_TO_TEST)
14
+ .withCountingIn(WITH_COUNTING_IN_TEST)
15
+ .withInnerPlayer(event.target)
16
+ .createReproduction();
17
+ onInit(newReproduction);
18
+ }
19
+ function onYouTubeInnerPlayerReadyHandler(event) {
20
+ let newReproduction = Reproduction.newBuilder()
21
+ .withTrainingMode(true)
22
+ .withSongTempo(TEMPO_TO_TEST)
23
+ .withCountingIn(WITH_COUNTING_IN_TEST)
24
+ .withInnerPlayer(event.target)
25
+ .createReproduction();
26
+ onInit(newReproduction);
27
+ }
28
+ return (React.createElement(React.Fragment, null, trainingMode ? (React.createElement(YouTubeInnerPlayer, { videoId: videoId, onReady: onYouTubeInnerPlayerReadyHandler })) : (React.createElement(PlayAlongInnerPlayer, { onReady: onPlayAlongInnerPlayerReadyHandler }))));
29
+ };
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { YouTubeInnerPlayer } from './inner-players/YouTubeInnerPlayer';
3
+ import { PlayAlongInnerPlayer } from './inner-players/PlayAlongInnerPlayer';
4
+ import { Reproduction } from './models/Reproduction';
5
+ import { YouTubePlayer as InnerYouTubePlayer } from 'react-youtube';
6
+
7
+ interface BaseProps {
8
+ trainingMode: boolean;
9
+ onInit: (reproduction: Reproduction) => void;
10
+ }
11
+
12
+ interface TrainingProps extends BaseProps {
13
+ trainingMode: true;
14
+ videoId: string;
15
+ }
16
+
17
+ interface NonTrainingProps extends BaseProps {
18
+ trainingMode: false;
19
+ videoId?: never;
20
+ }
21
+
22
+ export type ReproductionWidgetProps = TrainingProps | NonTrainingProps;
23
+
24
+ export const ReproductionWidget = ({
25
+ trainingMode,
26
+ videoId,
27
+ onInit,
28
+ }: ReproductionWidgetProps) => {
29
+ const DURATION_TO_TEST = 30;
30
+ const TEMPO_TO_TEST = 90;
31
+ const WITH_COUNTING_IN_TEST = true;
32
+
33
+ function onPlayAlongInnerPlayerReadyHandler(event: { target: string }) {
34
+ let newReproduction = Reproduction.newBuilder()
35
+ .withTrainingMode(false)
36
+ .withSongDuration(DURATION_TO_TEST)
37
+ .withSongTempo(TEMPO_TO_TEST)
38
+ .withCountingIn(WITH_COUNTING_IN_TEST)
39
+ .withInnerPlayer(event.target)
40
+ .createReproduction();
41
+ onInit(newReproduction);
42
+ }
43
+
44
+ function onYouTubeInnerPlayerReadyHandler(event: {
45
+ target: InnerYouTubePlayer;
46
+ }) {
47
+ let newReproduction = Reproduction.newBuilder()
48
+ .withTrainingMode(true)
49
+ .withSongTempo(TEMPO_TO_TEST)
50
+ .withCountingIn(WITH_COUNTING_IN_TEST)
51
+ .withInnerPlayer(event.target)
52
+ .createReproduction();
53
+ onInit(newReproduction);
54
+ }
55
+
56
+ return (
57
+ <>
58
+ {trainingMode ? (
59
+ <YouTubeInnerPlayer
60
+ videoId={videoId}
61
+ onReady={onYouTubeInnerPlayerReadyHandler}
62
+ />
63
+ ) : (
64
+ <PlayAlongInnerPlayer onReady={onPlayAlongInnerPlayerReadyHandler} />
65
+ )}
66
+ </>
67
+ );
68
+ };
@@ -0,0 +1 @@
1
+ export * from './ReproductionWidget';
@@ -0,0 +1 @@
1
+ export * from './ReproductionWidget';
@@ -0,0 +1,5 @@
1
+ import React, { useEffect } from 'react';
2
+ export const PlayAlongInnerPlayer = ({ onReady }) => {
3
+ useEffect(() => onReady({ target: 'mock' }), []);
4
+ return React.createElement("div", null);
5
+ };
@@ -0,0 +1,10 @@
1
+ import React, { useEffect } from 'react';
2
+
3
+ interface Props {
4
+ onReady: (event: { target: string }) => void;
5
+ }
6
+ export const PlayAlongInnerPlayer = ({ onReady }: Props) => {
7
+ useEffect(() => onReady({ target: 'mock' }), []);
8
+
9
+ return <div></div>;
10
+ };
@@ -0,0 +1,21 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import YouTube from 'react-youtube';
3
+ export const YouTubeInnerPlayer = ({ videoId, onReady }) => {
4
+ const [origin, setOrigin] = useState('');
5
+ useEffect(() => {
6
+ if (typeof window !== 'undefined') {
7
+ setOrigin(window.location.href);
8
+ }
9
+ }, []);
10
+ const opts = {
11
+ playerVars: {
12
+ // https://developers.google.com/youtube/player_parameters
13
+ autoplay: 0,
14
+ controls: 0,
15
+ showinfo: 0,
16
+ enablejsapi: 1,
17
+ origin: origin,
18
+ },
19
+ };
20
+ return (React.createElement(YouTube, { id: 'YT-' + videoId, className: 'youtube-player', videoId: videoId, opts: opts, onReady: onReady }));
21
+ };
@@ -0,0 +1,36 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import YouTube, { YouTubePlayer as InnerYouTubePlayer } from 'react-youtube';
3
+
4
+ interface Props {
5
+ videoId: string;
6
+ onReady: (event: { target: InnerYouTubePlayer }) => void;
7
+ }
8
+ export const YouTubeInnerPlayer = ({ videoId, onReady }: Props) => {
9
+ const [origin, setOrigin] = useState('');
10
+
11
+ useEffect(() => {
12
+ if (typeof window !== 'undefined') {
13
+ setOrigin(window.location.href);
14
+ }
15
+ }, []);
16
+
17
+ const opts = {
18
+ playerVars: {
19
+ // https://developers.google.com/youtube/player_parameters
20
+ autoplay: 0,
21
+ controls: 0,
22
+ showinfo: 0,
23
+ enablejsapi: 1,
24
+ origin: origin,
25
+ },
26
+ };
27
+ return (
28
+ <YouTube
29
+ id={'YT-' + videoId}
30
+ className='youtube-player'
31
+ videoId={videoId}
32
+ opts={opts}
33
+ onReady={onReady}
34
+ />
35
+ );
36
+ };
@@ -0,0 +1,97 @@
1
+ import { PLAYER_EVENTS } from './PlayerEvents';
2
+ const dispatchOnReadyHandlers = Symbol();
3
+ const dispatchOnFinishHandlers = Symbol();
4
+ export class PlayAlongPlayer {
5
+ static get EVENTS() {
6
+ return PLAYER_EVENTS;
7
+ }
8
+ constructor(duration, innerPlayer) {
9
+ this.interval = null;
10
+ this.interval = null;
11
+ this.currentTime = 0;
12
+ this.isRunning = false;
13
+ this.duration = duration;
14
+ this.currentPlaybackRate = 1;
15
+ this.innerPlayer = null;
16
+ this[dispatchOnFinishHandlers] = [];
17
+ this[dispatchOnReadyHandlers] = [];
18
+ this.setInnerPlayer(innerPlayer);
19
+ }
20
+ setInnerPlayer(innerPlayer) {
21
+ this.innerPlayer = innerPlayer;
22
+ this.dispatch(PlayAlongPlayer.EVENTS.READY);
23
+ }
24
+ play() {
25
+ this.isRunning = true;
26
+ const intervalTimeout = 1000;
27
+ this.interval = setInterval(() => {
28
+ if (this.isRunning) {
29
+ this.currentTime++;
30
+ if (this.currentTime >= this.getDuration()) {
31
+ this.stop();
32
+ this.dispatch(PlayAlongPlayer.EVENTS.FINISH);
33
+ }
34
+ }
35
+ }, intervalTimeout);
36
+ }
37
+ pause() {
38
+ this.isRunning = false;
39
+ }
40
+ stop() {
41
+ this.currentTime = 0;
42
+ this.isRunning = false;
43
+ if (this.interval !== null) {
44
+ clearInterval(this.interval);
45
+ this.interval = null;
46
+ }
47
+ }
48
+ seekTo(seconds) {
49
+ this.currentTime = seconds;
50
+ }
51
+ getCurrentTime() {
52
+ return this.currentTime;
53
+ }
54
+ getDuration() {
55
+ return this.duration;
56
+ }
57
+ isAvailable() {
58
+ return true;
59
+ }
60
+ getAvailablePlaybackRates() {
61
+ return [1];
62
+ }
63
+ setPlaybackRate(playbackRate) {
64
+ if (!this.getAvailablePlaybackRates().includes(playbackRate)) {
65
+ throw new Error(`The PlayAlongPlayer doesn't support a playbackRate with value ${playbackRate}`);
66
+ }
67
+ this.currentPlaybackRate = playbackRate;
68
+ }
69
+ on(eventName, handler) {
70
+ switch (eventName) {
71
+ case PlayAlongPlayer.EVENTS.READY:
72
+ return this[dispatchOnReadyHandlers].push(handler);
73
+ case PlayAlongPlayer.EVENTS.FINISH:
74
+ return this[dispatchOnFinishHandlers].push(handler);
75
+ default:
76
+ break;
77
+ }
78
+ }
79
+ dispatch(eventName) {
80
+ let handler, i, len;
81
+ let ref = [];
82
+ switch (eventName) {
83
+ case PlayAlongPlayer.EVENTS.READY:
84
+ ref = this[dispatchOnReadyHandlers];
85
+ break;
86
+ case PlayAlongPlayer.EVENTS.FINISH:
87
+ ref = this[dispatchOnFinishHandlers];
88
+ break;
89
+ default:
90
+ break;
91
+ }
92
+ for (i = 0, len = ref.length; i < len; i++) {
93
+ handler = ref[i];
94
+ handler();
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,129 @@
1
+ import { PLAYER_EVENTS } from './PlayerEvents';
2
+
3
+ const dispatchOnReadyHandlers = Symbol();
4
+ const dispatchOnFinishHandlers = Symbol();
5
+
6
+ export class PlayAlongPlayer {
7
+ private readonly duration: number;
8
+ private currentTime: number;
9
+ private isRunning: boolean;
10
+ private currentPlaybackRate: number;
11
+ private innerPlayer: string | null;
12
+ private interval: ReturnType<typeof setInterval> | null = null;
13
+ private [dispatchOnReadyHandlers]: (() => void)[];
14
+ private [dispatchOnFinishHandlers]: (() => void)[];
15
+
16
+ static get EVENTS() {
17
+ return PLAYER_EVENTS;
18
+ }
19
+
20
+ constructor(duration: number, innerPlayer: string) {
21
+ this.interval = null;
22
+ this.currentTime = 0;
23
+ this.isRunning = false;
24
+ this.duration = duration;
25
+ this.currentPlaybackRate = 1;
26
+ this.innerPlayer = null;
27
+
28
+ this[dispatchOnFinishHandlers] = [];
29
+ this[dispatchOnReadyHandlers] = [];
30
+
31
+ this.setInnerPlayer(innerPlayer);
32
+ }
33
+
34
+ private setInnerPlayer(innerPlayer: string) {
35
+ this.innerPlayer = innerPlayer;
36
+ this.dispatch(PlayAlongPlayer.EVENTS.READY);
37
+ }
38
+
39
+ play() {
40
+ this.isRunning = true;
41
+
42
+ const intervalTimeout = 1000;
43
+
44
+ this.interval = setInterval(() => {
45
+ if (this.isRunning) {
46
+ this.currentTime++;
47
+ if (this.currentTime >= this.getDuration()) {
48
+ this.stop();
49
+ this.dispatch(PlayAlongPlayer.EVENTS.FINISH);
50
+ }
51
+ }
52
+ }, intervalTimeout);
53
+ }
54
+
55
+ pause() {
56
+ this.isRunning = false;
57
+ }
58
+
59
+ stop() {
60
+ this.currentTime = 0;
61
+ this.isRunning = false;
62
+
63
+ if (this.interval !== null) {
64
+ clearInterval(this.interval as NodeJS.Timeout);
65
+ this.interval = null;
66
+ }
67
+ }
68
+
69
+ seekTo(seconds: number) {
70
+ this.currentTime = seconds;
71
+ }
72
+
73
+ getCurrentTime() {
74
+ return this.currentTime;
75
+ }
76
+
77
+ getDuration() {
78
+ return this.duration;
79
+ }
80
+
81
+ isAvailable() {
82
+ return true;
83
+ }
84
+
85
+ getAvailablePlaybackRates() {
86
+ return [1];
87
+ }
88
+
89
+ setPlaybackRate(playbackRate: number) {
90
+ if (!this.getAvailablePlaybackRates().includes(playbackRate)) {
91
+ throw new Error(
92
+ `The PlayAlongPlayer doesn't support a playbackRate with value ${playbackRate}`
93
+ );
94
+ }
95
+ this.currentPlaybackRate = playbackRate;
96
+ }
97
+
98
+ on(eventName: keyof typeof PlayAlongPlayer.EVENTS, handler: () => void) {
99
+ switch (eventName) {
100
+ case PlayAlongPlayer.EVENTS.READY:
101
+ return this[dispatchOnReadyHandlers].push(handler);
102
+ case PlayAlongPlayer.EVENTS.FINISH:
103
+ return this[dispatchOnFinishHandlers].push(handler);
104
+ default:
105
+ break;
106
+ }
107
+ }
108
+
109
+ dispatch(eventName: keyof typeof PlayAlongPlayer.EVENTS) {
110
+ let handler, i, len;
111
+ let ref: (() => void)[] = [];
112
+
113
+ switch (eventName) {
114
+ case PlayAlongPlayer.EVENTS.READY:
115
+ ref = this[dispatchOnReadyHandlers];
116
+ break;
117
+ case PlayAlongPlayer.EVENTS.FINISH:
118
+ ref = this[dispatchOnFinishHandlers];
119
+ break;
120
+ default:
121
+ break;
122
+ }
123
+
124
+ for (i = 0, len = ref.length; i < len; i++) {
125
+ handler = ref[i];
126
+ handler();
127
+ }
128
+ }
129
+ }
@@ -0,0 +1,4 @@
1
+ export const PLAYER_EVENTS = {
2
+ READY: 'READY',
3
+ FINISH: 'FINISH',
4
+ };
@@ -0,0 +1,4 @@
1
+ export const PLAYER_EVENTS = {
2
+ READY: 'READY',
3
+ FINISH: 'FINISH',
4
+ } as const;
@@ -0,0 +1,126 @@
1
+ import { PlayAlongPlayer } from './PlayAlongPlayer';
2
+ import { PLAYER_EVENTS } from './PlayerEvents';
3
+ // https://developers.google.com/youtube/iframe_api_reference
4
+ var INNER_YOUTUBE_PLAYER_EVENTS;
5
+ (function (INNER_YOUTUBE_PLAYER_EVENTS) {
6
+ INNER_YOUTUBE_PLAYER_EVENTS[INNER_YOUTUBE_PLAYER_EVENTS["VIDEO_UNSTARTED"] = -1] = "VIDEO_UNSTARTED";
7
+ INNER_YOUTUBE_PLAYER_EVENTS[INNER_YOUTUBE_PLAYER_EVENTS["VIDEO_ENDED"] = 0] = "VIDEO_ENDED";
8
+ INNER_YOUTUBE_PLAYER_EVENTS[INNER_YOUTUBE_PLAYER_EVENTS["VIDEO_PLAYING"] = 1] = "VIDEO_PLAYING";
9
+ INNER_YOUTUBE_PLAYER_EVENTS[INNER_YOUTUBE_PLAYER_EVENTS["VIDEO_PAUSED"] = 2] = "VIDEO_PAUSED";
10
+ INNER_YOUTUBE_PLAYER_EVENTS[INNER_YOUTUBE_PLAYER_EVENTS["VIDEO_BUFFERING"] = 3] = "VIDEO_BUFFERING";
11
+ INNER_YOUTUBE_PLAYER_EVENTS[INNER_YOUTUBE_PLAYER_EVENTS["VIDEO_CUED"] = 5] = "VIDEO_CUED";
12
+ })(INNER_YOUTUBE_PLAYER_EVENTS || (INNER_YOUTUBE_PLAYER_EVENTS = {}));
13
+ const dispatchOnReadyHandlers = Symbol();
14
+ const dispatchOnFinishHandlers = Symbol();
15
+ export class YouTubePlayer {
16
+ static get EVENTS() {
17
+ return PLAYER_EVENTS;
18
+ }
19
+ constructor(innerPlayer) {
20
+ this[dispatchOnFinishHandlers] = [];
21
+ this[dispatchOnReadyHandlers] = [];
22
+ this.currentTime = 0;
23
+ this.isRunning = false;
24
+ this.setInnerPlayer(innerPlayer);
25
+ }
26
+ setInnerPlayer(innerPlayer) {
27
+ this.innerPlayer = innerPlayer;
28
+ this.dispatch(YouTubePlayer.EVENTS.READY);
29
+ // this is necessary for avoiding the state video cued.
30
+ // When a video is in this state, when user seek to X, the song is played
31
+ this.innerPlayer.playVideo();
32
+ this.innerPlayer.pauseVideo();
33
+ this.innerPlayer.addEventListener('onStateChange', (videoState) => {
34
+ switch (videoState.data) {
35
+ case INNER_YOUTUBE_PLAYER_EVENTS.VIDEO_ENDED:
36
+ this.dispatch(YouTubePlayer.EVENTS.FINISH);
37
+ this.isRunning = false;
38
+ this.currentTime = 0;
39
+ break;
40
+ default:
41
+ break;
42
+ }
43
+ });
44
+ }
45
+ getInnerPlayer() {
46
+ return this.innerPlayer;
47
+ }
48
+ play() {
49
+ const videoPlayer = this.getInnerPlayer();
50
+ videoPlayer.playVideo();
51
+ this.isRunning = true;
52
+ }
53
+ pause() {
54
+ this.isRunning = false;
55
+ this.getInnerPlayer().pauseVideo();
56
+ this.currentTime = this.getInnerPlayer().getCurrentTime();
57
+ }
58
+ stop() {
59
+ this.isRunning = false;
60
+ /**
61
+ * Hay un issue al llamar a getDuration del video luego de reanudar una canción pausada (devuelve siempre 0)
62
+ * Para evitar que se pierda la información y tener que cargarla de nuevo, se simula un stop pausando y llevando al comienzo
63
+ * videoPlayer.stopVideo();
64
+ */
65
+ this.getInnerPlayer().pauseVideo();
66
+ this.seekTo(0);
67
+ }
68
+ seekTo(seconds) {
69
+ const videoPlayer = this.getInnerPlayer();
70
+ this.currentTime = seconds;
71
+ videoPlayer.seekTo(this.currentTime);
72
+ if (this.isRunning) {
73
+ this.play();
74
+ }
75
+ }
76
+ getCurrentTime() {
77
+ return this.isRunning
78
+ ? this.getInnerPlayer().getCurrentTime()
79
+ : this.currentTime;
80
+ }
81
+ getDuration() {
82
+ if (this.isAvailable()) {
83
+ return this.getInnerPlayer().getDuration();
84
+ }
85
+ }
86
+ getAvailablePlaybackRates() {
87
+ return this.getInnerPlayer().getAvailablePlaybackRates();
88
+ }
89
+ setPlaybackRate(playbackRate) {
90
+ if (!this.getAvailablePlaybackRates().includes(playbackRate)) {
91
+ throw new Error(`The PlayAlongPlayer doesn't support a playbackRate with value ${playbackRate}`);
92
+ }
93
+ this.getInnerPlayer().setPlaybackRate(playbackRate);
94
+ }
95
+ isAvailable() {
96
+ return this.getInnerPlayer() !== null;
97
+ }
98
+ on(eventName, handler) {
99
+ switch (eventName) {
100
+ case PlayAlongPlayer.EVENTS.READY:
101
+ return this[dispatchOnReadyHandlers].push(handler);
102
+ case PlayAlongPlayer.EVENTS.FINISH:
103
+ return this[dispatchOnFinishHandlers].push(handler);
104
+ default:
105
+ break;
106
+ }
107
+ }
108
+ dispatch(eventName) {
109
+ let handler, i, len;
110
+ let ref = [];
111
+ switch (eventName) {
112
+ case YouTubePlayer.EVENTS.READY:
113
+ ref = this[dispatchOnReadyHandlers];
114
+ break;
115
+ case YouTubePlayer.EVENTS.FINISH:
116
+ ref = this[dispatchOnFinishHandlers];
117
+ break;
118
+ default:
119
+ break;
120
+ }
121
+ for (i = 0, len = ref.length; i < len; i++) {
122
+ handler = ref[i];
123
+ setTimeout(handler, 0);
124
+ }
125
+ }
126
+ }