]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/standalone/player/player.ts
Add local/remote badges
[github/Chocobozzz/PeerTube.git] / client / src / standalone / player / player.ts
CommitLineData
99941732 1import * as Channel from 'jschannel'
1151f521 2import { EventHandler, PeerTubeResolution, PeerTubeTextTrack, PlayerEventType } from './definitions'
99941732 3import { EventRegistrar } from './events'
99941732
WL
4
5const PASSTHROUGH_EVENTS = [
902aa3a0
C
6 'pause',
7 'play',
99941732
WL
8 'playbackStatusUpdate',
9 'playbackStatusChange',
6377a9f2
C
10 'resolutionUpdate',
11 'volumeChange'
99941732
WL
12]
13
14/**
902aa3a0 15 * Allows for programmatic control of a PeerTube embed running in an <iframe>
99941732
WL
16 * within a web page.
17 */
18export class PeerTubePlayer {
902aa3a0 19
9df52d66 20 private readonly eventRegistrar: EventRegistrar = new EventRegistrar()
902aa3a0
C
21 private channel: Channel.MessagingChannel
22 private readyPromise: Promise<void>
23
99941732
WL
24 /**
25 * Construct a new PeerTubePlayer for the given PeerTube embed iframe.
902aa3a0
C
26 * Optionally provide a `scope` to ensure that messages are not crossed
27 * between multiple PeerTube embeds. The string passed here must match the
99941732 28 * `scope=` query parameter on the embed URL.
902aa3a0
C
29 *
30 * @param embedElement
31 * @param scope
99941732 32 */
902aa3a0 33 constructor (
9df52d66
C
34 private readonly embedElement: HTMLIFrameElement,
35 private readonly scope?: string
99941732
WL
36 ) {
37 this.eventRegistrar.registerTypes(PASSTHROUGH_EVENTS)
38
39 this.constructChannel()
40 this.prepareToBeReady()
41 }
42
99941732
WL
43 /**
44 * Destroy the player object and remove the associated player from the DOM.
45 */
902aa3a0 46 destroy () {
99941732
WL
47 this.embedElement.remove()
48 }
49
50 /**
51 * Listen to an event emitted by this player.
902aa3a0 52 *
99941732
WL
53 * @param event One of the supported event types
54 * @param handler A handler which will be passed an event object (or undefined if no event object is included)
55 */
902aa3a0 56 addEventListener (event: PlayerEventType, handler: EventHandler<any>): boolean {
99941732
WL
57 return this.eventRegistrar.addListener(event, handler)
58 }
59
60 /**
61 * Remove an event listener previously added with addEventListener().
902aa3a0 62 *
99941732 63 * @param event The name of the event previously listened to
902aa3a0 64 * @param handler
99941732 65 */
902aa3a0 66 removeEventListener (event: PlayerEventType, handler: EventHandler<any>): boolean {
99941732
WL
67 return this.eventRegistrar.removeListener(event, handler)
68 }
902aa3a0 69
99941732
WL
70 /**
71 * Promise resolves when the player is ready.
72 */
902aa3a0 73 get ready (): Promise<void> {
99941732
WL
74 return this.readyPromise
75 }
76
77 /**
78 * Tell the embed to start/resume playback
79 */
902aa3a0 80 async play () {
99941732
WL
81 await this.sendMessage('play')
82 }
83
84 /**
85 * Tell the embed to pause playback.
86 */
902aa3a0 87 async pause () {
99941732
WL
88 await this.sendMessage('pause')
89 }
90
91 /**
92 * Tell the embed to change the audio volume
9df52d66 93 *
99941732
WL
94 * @param value A number from 0 to 1
95 */
902aa3a0 96 async setVolume (value: number) {
99941732
WL
97 await this.sendMessage('setVolume', value)
98 }
99
100 /**
101 * Get the current volume level in the embed.
9df52d66 102 *
99941732
WL
103 * @param value A number from 0 to 1
104 */
902aa3a0 105 async getVolume (): Promise<number> {
9df52d66 106 return this.sendMessage<undefined, number>('getVolume')
99941732
WL
107 }
108
1151f521
C
109 /**
110 * Tell the embed to change the current caption
9df52d66 111 *
1151f521
C
112 * @param value Caption id
113 */
114 async setCaption (value: string) {
115 await this.sendMessage('setCaption', value)
116 }
117
118 /**
119 * Get video captions
120 */
121 async getCaptions (): Promise<PeerTubeTextTrack[]> {
9df52d66 122 return this.sendMessage<undefined, PeerTubeTextTrack[]>('getCaptions')
1151f521
C
123 }
124
99941732
WL
125 /**
126 * Tell the embed to seek to a specific position (in seconds)
9df52d66 127 *
902aa3a0 128 * @param seconds
99941732 129 */
902aa3a0 130 async seek (seconds: number) {
99941732
WL
131 await this.sendMessage('seek', seconds)
132 }
133
134 /**
135 * Tell the embed to switch resolutions to the resolution identified
136 * by the given ID.
902aa3a0 137 *
99941732
WL
138 * @param resolutionId The ID of the resolution as found with getResolutions()
139 */
902aa3a0 140 async setResolution (resolutionId: any) {
99941732
WL
141 await this.sendMessage('setResolution', resolutionId)
142 }
143
144 /**
902aa3a0 145 * Retrieve a list of the available resolutions. This may change later, listen to the
99941732
WL
146 * `resolutionUpdate` event with `addEventListener` in order to be updated as the available
147 * resolutions change.
148 */
902aa3a0 149 async getResolutions (): Promise<PeerTubeResolution[]> {
9df52d66 150 return this.sendMessage<undefined, PeerTubeResolution[]>('getResolutions')
99941732
WL
151 }
152
153 /**
902aa3a0 154 * Retrieve a list of available playback rates.
99941732 155 */
902aa3a0 156 async getPlaybackRates (): Promise<number[]> {
9df52d66 157 return this.sendMessage<undefined, number[]>('getPlaybackRates')
99941732 158 }
902aa3a0 159
99941732
WL
160 /**
161 * Get the current playback rate. Defaults to 1 (1x playback rate).
162 */
902aa3a0 163 async getPlaybackRate (): Promise<number> {
9df52d66 164 return this.sendMessage<undefined, number>('getPlaybackRate')
99941732
WL
165 }
166
167 /**
168 * Set the playback rate. Should be one of the options returned by getPlaybackRates().
169 * Passing 0.5 means half speed, 1 means normal, 2 means 2x speed, etc.
902aa3a0
C
170 *
171 * @param rate
99941732 172 */
902aa3a0 173 async setPlaybackRate (rate: number) {
99941732
WL
174 await this.sendMessage('setPlaybackRate', rate)
175 }
176
9054a8b6
C
177 /**
178 * Play next video in playlist
179 */
180 async playNextVideo () {
181 await this.sendMessage('playNextVideo')
182 }
183
184 /**
185 * Play previous video in playlist
186 */
187 async playPreviousVideo () {
188 await this.sendMessage('playPreviousVideo')
189 }
190
191 /**
192 * Get video position currently played (starts from 1)
193 */
194 async getCurrentPosition () {
9df52d66 195 return this.sendMessage<undefined, number>('getCurrentPosition')
9054a8b6
C
196 }
197
902aa3a0 198 private constructChannel () {
99941732
WL
199 this.channel = Channel.build({
200 window: this.embedElement.contentWindow,
201 origin: '*',
202 scope: this.scope || 'peertube'
203 })
204 this.eventRegistrar.bindToChannel(this.channel)
205 }
902aa3a0
C
206
207 private prepareToBeReady () {
9df52d66
C
208 let readyResolve: () => void
209 let readyReject: () => void
902aa3a0 210
99941732
WL
211 this.readyPromise = new Promise<void>((res, rej) => {
212 readyResolve = res
213 readyReject = rej
214 })
902aa3a0 215
99941732
WL
216 this.channel.bind('ready', success => success ? readyResolve() : readyReject())
217 this.channel.call({
218 method: 'isReady',
219 success: isReady => isReady ? readyResolve() : null
220 })
221 }
222
902aa3a0 223 private sendMessage<TIn, TOut> (method: string, params?: TIn): Promise<TOut> {
99941732
WL
224 return new Promise<TOut>((resolve, reject) => {
225 this.channel.call({
9df52d66
C
226 method,
227 params,
99941732
WL
228 success: result => resolve(result),
229 error: error => reject(error)
230 })
231 })
232 }
233}
234
235// put it on the window as well as the export
9df52d66 236(window['PeerTubePlayer'] as any) = PeerTubePlayer