diff options
Diffstat (limited to 'client/src/standalone/player')
-rw-r--r-- | client/src/standalone/player/definitions.ts | 24 | ||||
-rw-r--r-- | client/src/standalone/player/events.ts | 56 | ||||
-rw-r--r-- | client/src/standalone/player/player.ts | 104 |
3 files changed, 93 insertions, 91 deletions
diff --git a/client/src/standalone/player/definitions.ts b/client/src/standalone/player/definitions.ts index 6920672a7..7f9ef9b6f 100644 --- a/client/src/standalone/player/definitions.ts +++ b/client/src/standalone/player/definitions.ts | |||
@@ -1,18 +1,16 @@ | |||
1 | |||
2 | export interface EventHandler<T> { | 1 | export interface EventHandler<T> { |
3 | (ev : T) : void | 2 | (ev: T): void |
4 | } | 3 | } |
5 | 4 | ||
6 | export type PlayerEventType = | 5 | export type PlayerEventType = |
7 | 'pause' | 'play' | | 6 | 'pause' | 'play' | |
8 | 'playbackStatusUpdate' | | 7 | 'playbackStatusUpdate' | |
9 | 'playbackStatusChange' | | 8 | 'playbackStatusChange' | |
10 | 'resolutionUpdate' | 9 | 'resolutionUpdate' |
11 | ; | ||
12 | 10 | ||
13 | export interface PeerTubeResolution { | 11 | export interface PeerTubeResolution { |
14 | id : any | 12 | id: any |
15 | label : string | 13 | label: string |
16 | src : string | 14 | src: string |
17 | active : boolean | 15 | active: boolean |
18 | } \ No newline at end of file | 16 | } |
diff --git a/client/src/standalone/player/events.ts b/client/src/standalone/player/events.ts index c01328352..f1639ef19 100644 --- a/client/src/standalone/player/events.ts +++ b/client/src/standalone/player/events.ts | |||
@@ -1,48 +1,48 @@ | |||
1 | import { EventHandler } from "./definitions" | 1 | import { EventHandler } from './definitions' |
2 | 2 | ||
3 | interface PlayerEventRegistrar { | 3 | interface PlayerEventRegistrar { |
4 | registrations : Function[] | 4 | registrations: Function[] |
5 | } | 5 | } |
6 | 6 | ||
7 | interface PlayerEventRegistrationMap { | 7 | interface PlayerEventRegistrationMap { |
8 | [name : string] : PlayerEventRegistrar | 8 | [ name: string ]: PlayerEventRegistrar |
9 | } | 9 | } |
10 | 10 | ||
11 | export class EventRegistrar { | 11 | export class EventRegistrar { |
12 | 12 | ||
13 | private eventRegistrations : PlayerEventRegistrationMap = {} | 13 | private eventRegistrations: PlayerEventRegistrationMap = {} |
14 | 14 | ||
15 | public bindToChannel(channel : Channel.MessagingChannel) { | 15 | public bindToChannel (channel: Channel.MessagingChannel) { |
16 | for (let name of Object.keys(this.eventRegistrations)) | 16 | for (let name of Object.keys(this.eventRegistrations)) { |
17 | channel.bind(name, (txn, params) => this.fire(name, params)) | 17 | channel.bind(name, (txn, params) => this.fire(name, params)) |
18 | } | 18 | } |
19 | } | ||
19 | 20 | ||
20 | public registerTypes(names : string[]) { | 21 | public registerTypes (names: string[]) { |
21 | for (let name of names) | 22 | for (let name of names) { |
22 | this.eventRegistrations[name] = { registrations: [] } | 23 | this.eventRegistrations[ name ] = { registrations: [] } |
23 | } | 24 | } |
25 | } | ||
24 | 26 | ||
25 | public fire<T>(name : string, event : T) { | 27 | public fire<T> (name: string, event: T) { |
26 | this.eventRegistrations[name].registrations.forEach(x => x(event)) | 28 | this.eventRegistrations[ name ].registrations.forEach(x => x(event)) |
29 | } | ||
30 | |||
31 | public addListener<T> (name: string, handler: EventHandler<T>) { | ||
32 | if (!this.eventRegistrations[ name ]) { | ||
33 | console.warn(`PeerTube: addEventListener(): The event '${name}' is not supported`) | ||
34 | return false | ||
27 | } | 35 | } |
28 | 36 | ||
29 | public addListener<T>(name : string, handler : EventHandler<T>) { | 37 | this.eventRegistrations[ name ].registrations.push(handler) |
30 | if (!this.eventRegistrations[name]) { | 38 | return true |
31 | console.warn(`PeerTube: addEventListener(): The event '${name}' is not supported`) | 39 | } |
32 | return false | ||
33 | } | ||
34 | 40 | ||
35 | this.eventRegistrations[name].registrations.push(handler) | 41 | public removeListener<T> (name: string, handler: EventHandler<T>) { |
36 | return true | 42 | if (!this.eventRegistrations[ name ]) return false |
37 | } | ||
38 | 43 | ||
39 | public removeListener<T>(name : string, handler : EventHandler<T>) { | 44 | this.eventRegistrations[ name ].registrations = this.eventRegistrations[ name ].registrations.filter(x => x === handler) |
40 | if (!this.eventRegistrations[name]) | ||
41 | return false | ||
42 | 45 | ||
43 | this.eventRegistrations[name].registrations = | 46 | return true |
44 | this.eventRegistrations[name].registrations.filter(x => x === handler) | 47 | } |
45 | |||
46 | return true | ||
47 | } | ||
48 | } | 48 | } |
diff --git a/client/src/standalone/player/player.ts b/client/src/standalone/player/player.ts index 9fc648d25..91a5e73f3 100644 --- a/client/src/standalone/player/player.ts +++ b/client/src/standalone/player/player.ts | |||
@@ -3,29 +3,35 @@ import { EventRegistrar } from './events' | |||
3 | import { EventHandler, PlayerEventType, PeerTubeResolution } from './definitions' | 3 | import { EventHandler, PlayerEventType, PeerTubeResolution } from './definitions' |
4 | 4 | ||
5 | const PASSTHROUGH_EVENTS = [ | 5 | const PASSTHROUGH_EVENTS = [ |
6 | 'pause', 'play', | 6 | 'pause', |
7 | 'play', | ||
7 | 'playbackStatusUpdate', | 8 | 'playbackStatusUpdate', |
8 | 'playbackStatusChange', | 9 | 'playbackStatusChange', |
9 | 'resolutionUpdate' | 10 | 'resolutionUpdate' |
10 | ] | 11 | ] |
11 | 12 | ||
12 | /** | 13 | /** |
13 | * Allows for programmatic control of a PeerTube embed running in an <iframe> | 14 | * Allows for programmatic control of a PeerTube embed running in an <iframe> |
14 | * within a web page. | 15 | * within a web page. |
15 | */ | 16 | */ |
16 | export class PeerTubePlayer { | 17 | export class PeerTubePlayer { |
18 | |||
19 | private eventRegistrar: EventRegistrar = new EventRegistrar() | ||
20 | private channel: Channel.MessagingChannel | ||
21 | private readyPromise: Promise<void> | ||
22 | |||
17 | /** | 23 | /** |
18 | * Construct a new PeerTubePlayer for the given PeerTube embed iframe. | 24 | * Construct a new PeerTubePlayer for the given PeerTube embed iframe. |
19 | * Optionally provide a `scope` to ensure that messages are not crossed | 25 | * Optionally provide a `scope` to ensure that messages are not crossed |
20 | * between multiple PeerTube embeds. The string passed here must match the | 26 | * between multiple PeerTube embeds. The string passed here must match the |
21 | * `scope=` query parameter on the embed URL. | 27 | * `scope=` query parameter on the embed URL. |
22 | * | 28 | * |
23 | * @param embedElement | 29 | * @param embedElement |
24 | * @param scope | 30 | * @param scope |
25 | */ | 31 | */ |
26 | constructor( | 32 | constructor ( |
27 | private embedElement : HTMLIFrameElement, | 33 | private embedElement: HTMLIFrameElement, |
28 | private scope? : string | 34 | private scope?: string |
29 | ) { | 35 | ) { |
30 | this.eventRegistrar.registerTypes(PASSTHROUGH_EVENTS) | 36 | this.eventRegistrar.registerTypes(PASSTHROUGH_EVENTS) |
31 | 37 | ||
@@ -33,55 +39,51 @@ export class PeerTubePlayer { | |||
33 | this.prepareToBeReady() | 39 | this.prepareToBeReady() |
34 | } | 40 | } |
35 | 41 | ||
36 | private eventRegistrar : EventRegistrar = new EventRegistrar() | ||
37 | private channel : Channel.MessagingChannel | ||
38 | private readyPromise : Promise<void> | ||
39 | |||
40 | /** | 42 | /** |
41 | * Destroy the player object and remove the associated player from the DOM. | 43 | * Destroy the player object and remove the associated player from the DOM. |
42 | */ | 44 | */ |
43 | destroy() { | 45 | destroy () { |
44 | this.embedElement.remove() | 46 | this.embedElement.remove() |
45 | } | 47 | } |
46 | 48 | ||
47 | /** | 49 | /** |
48 | * Listen to an event emitted by this player. | 50 | * Listen to an event emitted by this player. |
49 | * | 51 | * |
50 | * @param event One of the supported event types | 52 | * @param event One of the supported event types |
51 | * @param handler A handler which will be passed an event object (or undefined if no event object is included) | 53 | * @param handler A handler which will be passed an event object (or undefined if no event object is included) |
52 | */ | 54 | */ |
53 | addEventListener(event : PlayerEventType, handler : EventHandler<any>): boolean { | 55 | addEventListener (event: PlayerEventType, handler: EventHandler<any>): boolean { |
54 | return this.eventRegistrar.addListener(event, handler) | 56 | return this.eventRegistrar.addListener(event, handler) |
55 | } | 57 | } |
56 | 58 | ||
57 | /** | 59 | /** |
58 | * Remove an event listener previously added with addEventListener(). | 60 | * Remove an event listener previously added with addEventListener(). |
59 | * | 61 | * |
60 | * @param event The name of the event previously listened to | 62 | * @param event The name of the event previously listened to |
61 | * @param handler | 63 | * @param handler |
62 | */ | 64 | */ |
63 | removeEventListener(event : PlayerEventType, handler : EventHandler<any>): boolean { | 65 | removeEventListener (event: PlayerEventType, handler: EventHandler<any>): boolean { |
64 | return this.eventRegistrar.removeListener(event, handler) | 66 | return this.eventRegistrar.removeListener(event, handler) |
65 | } | 67 | } |
66 | 68 | ||
67 | /** | 69 | /** |
68 | * Promise resolves when the player is ready. | 70 | * Promise resolves when the player is ready. |
69 | */ | 71 | */ |
70 | get ready(): Promise<void> { | 72 | get ready (): Promise<void> { |
71 | return this.readyPromise | 73 | return this.readyPromise |
72 | } | 74 | } |
73 | 75 | ||
74 | /** | 76 | /** |
75 | * Tell the embed to start/resume playback | 77 | * Tell the embed to start/resume playback |
76 | */ | 78 | */ |
77 | async play() { | 79 | async play () { |
78 | await this.sendMessage('play') | 80 | await this.sendMessage('play') |
79 | } | 81 | } |
80 | 82 | ||
81 | /** | 83 | /** |
82 | * Tell the embed to pause playback. | 84 | * Tell the embed to pause playback. |
83 | */ | 85 | */ |
84 | async pause() { | 86 | async pause () { |
85 | await this.sendMessage('pause') | 87 | await this.sendMessage('pause') |
86 | } | 88 | } |
87 | 89 | ||
@@ -89,7 +91,7 @@ export class PeerTubePlayer { | |||
89 | * Tell the embed to change the audio volume | 91 | * Tell the embed to change the audio volume |
90 | * @param value A number from 0 to 1 | 92 | * @param value A number from 0 to 1 |
91 | */ | 93 | */ |
92 | async setVolume(value : number) { | 94 | async setVolume (value: number) { |
93 | await this.sendMessage('setVolume', value) | 95 | await this.sendMessage('setVolume', value) |
94 | } | 96 | } |
95 | 97 | ||
@@ -97,62 +99,62 @@ export class PeerTubePlayer { | |||
97 | * Get the current volume level in the embed. | 99 | * Get the current volume level in the embed. |
98 | * @param value A number from 0 to 1 | 100 | * @param value A number from 0 to 1 |
99 | */ | 101 | */ |
100 | async getVolume(): Promise<number> { | 102 | async getVolume (): Promise<number> { |
101 | return await this.sendMessage<void, number>('setVolume') | 103 | return this.sendMessage<void, number>('setVolume') |
102 | } | 104 | } |
103 | 105 | ||
104 | /** | 106 | /** |
105 | * Tell the embed to seek to a specific position (in seconds) | 107 | * Tell the embed to seek to a specific position (in seconds) |
106 | * @param seconds | 108 | * @param seconds |
107 | */ | 109 | */ |
108 | async seek(seconds : number) { | 110 | async seek (seconds: number) { |
109 | await this.sendMessage('seek', seconds) | 111 | await this.sendMessage('seek', seconds) |
110 | } | 112 | } |
111 | 113 | ||
112 | /** | 114 | /** |
113 | * Tell the embed to switch resolutions to the resolution identified | 115 | * Tell the embed to switch resolutions to the resolution identified |
114 | * by the given ID. | 116 | * by the given ID. |
115 | * | 117 | * |
116 | * @param resolutionId The ID of the resolution as found with getResolutions() | 118 | * @param resolutionId The ID of the resolution as found with getResolutions() |
117 | */ | 119 | */ |
118 | async setResolution(resolutionId : any) { | 120 | async setResolution (resolutionId: any) { |
119 | await this.sendMessage('setResolution', resolutionId) | 121 | await this.sendMessage('setResolution', resolutionId) |
120 | } | 122 | } |
121 | 123 | ||
122 | /** | 124 | /** |
123 | * Retrieve a list of the available resolutions. This may change later, listen to the | 125 | * Retrieve a list of the available resolutions. This may change later, listen to the |
124 | * `resolutionUpdate` event with `addEventListener` in order to be updated as the available | 126 | * `resolutionUpdate` event with `addEventListener` in order to be updated as the available |
125 | * resolutions change. | 127 | * resolutions change. |
126 | */ | 128 | */ |
127 | async getResolutions(): Promise<PeerTubeResolution[]> { | 129 | async getResolutions (): Promise<PeerTubeResolution[]> { |
128 | return await this.sendMessage<void, PeerTubeResolution[]>('getResolutions') | 130 | return this.sendMessage<void, PeerTubeResolution[]>('getResolutions') |
129 | } | 131 | } |
130 | 132 | ||
131 | /** | 133 | /** |
132 | * Retrieve a list of available playback rates. | 134 | * Retrieve a list of available playback rates. |
133 | */ | 135 | */ |
134 | async getPlaybackRates() : Promise<number[]> { | 136 | async getPlaybackRates (): Promise<number[]> { |
135 | return await this.sendMessage<void, number[]>('getPlaybackRates') | 137 | return this.sendMessage<void, number[]>('getPlaybackRates') |
136 | } | 138 | } |
137 | 139 | ||
138 | /** | 140 | /** |
139 | * Get the current playback rate. Defaults to 1 (1x playback rate). | 141 | * Get the current playback rate. Defaults to 1 (1x playback rate). |
140 | */ | 142 | */ |
141 | async getPlaybackRate() : Promise<number> { | 143 | async getPlaybackRate (): Promise<number> { |
142 | return await this.sendMessage<void, number>('getPlaybackRate') | 144 | return this.sendMessage<void, number>('getPlaybackRate') |
143 | } | 145 | } |
144 | 146 | ||
145 | /** | 147 | /** |
146 | * Set the playback rate. Should be one of the options returned by getPlaybackRates(). | 148 | * Set the playback rate. Should be one of the options returned by getPlaybackRates(). |
147 | * Passing 0.5 means half speed, 1 means normal, 2 means 2x speed, etc. | 149 | * Passing 0.5 means half speed, 1 means normal, 2 means 2x speed, etc. |
148 | * | 150 | * |
149 | * @param rate | 151 | * @param rate |
150 | */ | 152 | */ |
151 | async setPlaybackRate(rate : number) { | 153 | async setPlaybackRate (rate: number) { |
152 | await this.sendMessage('setPlaybackRate', rate) | 154 | await this.sendMessage('setPlaybackRate', rate) |
153 | } | 155 | } |
154 | 156 | ||
155 | private constructChannel() { | 157 | private constructChannel () { |
156 | this.channel = Channel.build({ | 158 | this.channel = Channel.build({ |
157 | window: this.embedElement.contentWindow, | 159 | window: this.embedElement.contentWindow, |
158 | origin: '*', | 160 | origin: '*', |
@@ -160,14 +162,16 @@ export class PeerTubePlayer { | |||
160 | }) | 162 | }) |
161 | this.eventRegistrar.bindToChannel(this.channel) | 163 | this.eventRegistrar.bindToChannel(this.channel) |
162 | } | 164 | } |
163 | 165 | ||
164 | private prepareToBeReady() { | 166 | private prepareToBeReady () { |
165 | let readyResolve, readyReject | 167 | let readyResolve: Function |
168 | let readyReject: Function | ||
169 | |||
166 | this.readyPromise = new Promise<void>((res, rej) => { | 170 | this.readyPromise = new Promise<void>((res, rej) => { |
167 | readyResolve = res | 171 | readyResolve = res |
168 | readyReject = rej | 172 | readyReject = rej |
169 | }) | 173 | }) |
170 | 174 | ||
171 | this.channel.bind('ready', success => success ? readyResolve() : readyReject()) | 175 | this.channel.bind('ready', success => success ? readyResolve() : readyReject()) |
172 | this.channel.call({ | 176 | this.channel.call({ |
173 | method: 'isReady', | 177 | method: 'isReady', |
@@ -175,7 +179,7 @@ export class PeerTubePlayer { | |||
175 | }) | 179 | }) |
176 | } | 180 | } |
177 | 181 | ||
178 | private sendMessage<TIn, TOut>(method : string, params? : TIn): Promise<TOut> { | 182 | private sendMessage<TIn, TOut> (method: string, params?: TIn): Promise<TOut> { |
179 | return new Promise<TOut>((resolve, reject) => { | 183 | return new Promise<TOut>((resolve, reject) => { |
180 | this.channel.call({ | 184 | this.channel.call({ |
181 | method, params, | 185 | method, params, |
@@ -187,4 +191,4 @@ export class PeerTubePlayer { | |||
187 | } | 191 | } |
188 | 192 | ||
189 | // put it on the window as well as the export | 193 | // put it on the window as well as the export |
190 | window['PeerTubePlayer'] = PeerTubePlayer \ No newline at end of file | 194 | window[ 'PeerTubePlayer' ] = PeerTubePlayer |