aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/standalone/videos/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/standalone/videos/shared')
-rw-r--r--client/src/standalone/videos/shared/index.ts2
-rw-r--r--client/src/standalone/videos/shared/player-html.ts19
-rw-r--r--client/src/standalone/videos/shared/player-options-builder.ts (renamed from client/src/standalone/videos/shared/player-manager-options.ts)261
3 files changed, 159 insertions, 123 deletions
diff --git a/client/src/standalone/videos/shared/index.ts b/client/src/standalone/videos/shared/index.ts
index 928b8e270..dcc522ac6 100644
--- a/client/src/standalone/videos/shared/index.ts
+++ b/client/src/standalone/videos/shared/index.ts
@@ -2,7 +2,7 @@ export * from './auth-http'
2export * from './peertube-plugin' 2export * from './peertube-plugin'
3export * from './live-manager' 3export * from './live-manager'
4export * from './player-html' 4export * from './player-html'
5export * from './player-manager-options' 5export * from './player-options-builder'
6export * from './playlist-fetcher' 6export * from './playlist-fetcher'
7export * from './playlist-tracker' 7export * from './playlist-tracker'
8export * from './translations' 8export * from './translations'
diff --git a/client/src/standalone/videos/shared/player-html.ts b/client/src/standalone/videos/shared/player-html.ts
index a0846d9d7..0defa0d70 100644
--- a/client/src/standalone/videos/shared/player-html.ts
+++ b/client/src/standalone/videos/shared/player-html.ts
@@ -1,5 +1,4 @@
1import { peertubeTranslate } from '../../../../../shared/core-utils/i18n' 1import { peertubeTranslate } from '../../../../../shared/core-utils/i18n'
2import { VideoDetails } from '../../../../../shared/models'
3import { logger } from '../../../root-helpers' 2import { logger } from '../../../root-helpers'
4import { Translations } from './translations' 3import { Translations } from './translations'
5 4
@@ -59,7 +58,6 @@ export class PlayerHTML {
59 const { incorrectPassword, translations } = options 58 const { incorrectPassword, translations } = options
60 return new Promise((resolve) => { 59 return new Promise((resolve) => {
61 60
62 this.removePlaceholder()
63 this.wrapperElement.style.display = 'none' 61 this.wrapperElement.style.display = 'none'
64 62
65 const translatedTitle = peertubeTranslate('This video is password protected', translations) 63 const translatedTitle = peertubeTranslate('This video is password protected', translations)
@@ -107,19 +105,6 @@ export class PlayerHTML {
107 this.wrapperElement.style.display = 'block' 105 this.wrapperElement.style.display = 'block'
108 } 106 }
109 107
110 buildPlaceholder (video: VideoDetails) {
111 const placeholder = this.getPlaceholderElement()
112
113 const url = window.location.origin + video.previewPath
114 placeholder.style.backgroundImage = `url("${url}")`
115 placeholder.style.display = 'block'
116 }
117
118 removePlaceholder () {
119 const placeholder = this.getPlaceholderElement()
120 placeholder.style.display = 'none'
121 }
122
123 displayInformation (text: string, translations: Translations) { 108 displayInformation (text: string, translations: Translations) {
124 if (this.informationElement) this.removeInformation() 109 if (this.informationElement) this.removeInformation()
125 110
@@ -137,10 +122,6 @@ export class PlayerHTML {
137 this.informationElement = undefined 122 this.informationElement = undefined
138 } 123 }
139 124
140 private getPlaceholderElement () {
141 return document.getElementById('placeholder-preview')
142 }
143
144 private removeElement (element: HTMLElement) { 125 private removeElement (element: HTMLElement) {
145 element.parentElement.removeChild(element) 126 element.parentElement.removeChild(element)
146 } 127 }
diff --git a/client/src/standalone/videos/shared/player-manager-options.ts b/client/src/standalone/videos/shared/player-options-builder.ts
index 3c7521bc2..8a4e32444 100644
--- a/client/src/standalone/videos/shared/player-manager-options.ts
+++ b/client/src/standalone/videos/shared/player-options-builder.ts
@@ -10,7 +10,7 @@ import {
10 VideoState, 10 VideoState,
11 VideoStreamingPlaylistType 11 VideoStreamingPlaylistType
12} from '../../../../../shared/models' 12} from '../../../../../shared/models'
13import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode, VideoJSCaption } from '../../../assets/player' 13import { HLSOptions, PeerTubePlayerContructorOptions, PeerTubePlayerLoadOptions, PlayerMode, VideoJSCaption } from '../../../assets/player'
14import { 14import {
15 getBoolOrDefault, 15 getBoolOrDefault,
16 getParamString, 16 getParamString,
@@ -27,7 +27,7 @@ import { PlaylistTracker } from './playlist-tracker'
27import { Translations } from './translations' 27import { Translations } from './translations'
28import { VideoFetcher } from './video-fetcher' 28import { VideoFetcher } from './video-fetcher'
29 29
30export class PlayerManagerOptions { 30export class PlayerOptionsBuilder {
31 private autoplay: boolean 31 private autoplay: boolean
32 32
33 private controls: boolean 33 private controls: boolean
@@ -141,10 +141,10 @@ export class PlayerManagerOptions {
141 141
142 if (modeParam) { 142 if (modeParam) {
143 if (modeParam === 'p2p-media-loader') this.mode = 'p2p-media-loader' 143 if (modeParam === 'p2p-media-loader') this.mode = 'p2p-media-loader'
144 else this.mode = 'webtorrent' 144 else this.mode = 'web-video'
145 } else { 145 } else {
146 if (Array.isArray(video.streamingPlaylists) && video.streamingPlaylists.length !== 0) this.mode = 'p2p-media-loader' 146 if (Array.isArray(video.streamingPlaylists) && video.streamingPlaylists.length !== 0) this.mode = 'p2p-media-loader'
147 else this.mode = 'webtorrent' 147 else this.mode = 'web-video'
148 } 148 }
149 } catch (err) { 149 } catch (err) {
150 logger.error('Cannot get params from URL.', err) 150 logger.error('Cannot get params from URL.', err)
@@ -153,7 +153,47 @@ export class PlayerManagerOptions {
153 153
154 // --------------------------------------------------------------------------- 154 // ---------------------------------------------------------------------------
155 155
156 async getPlayerOptions (options: { 156 getPlayerConstructorOptions (options: {
157 serverConfig: HTMLServerConfig
158 authorizationHeader: () => string
159 }): PeerTubePlayerContructorOptions {
160 const { serverConfig, authorizationHeader } = options
161
162 return {
163 controls: this.controls,
164 controlBar: this.controlBar,
165
166 muted: this.muted,
167 loop: this.loop,
168
169 playbackRate: this.playbackRate,
170
171 inactivityTimeout: 2500,
172 videoViewIntervalMs: 5000,
173 metricsUrl: window.location.origin + '/api/v1/metrics/playback',
174
175 authorizationHeader,
176
177 playerElement: () => this.playerHTML.getPlayerElement(),
178 enableHotkeys: true,
179
180 peertubeLink: () => this.peertubeLink,
181 instanceName: serverConfig.instance.name,
182
183 theaterButton: false,
184
185 serverUrl: window.location.origin,
186 language: navigator.language,
187
188 pluginsManager: this.peertubePlugin.getPluginsManager(),
189
190 errorNotifier: () => {
191 // Empty, we don't have a notifier in the embed
192 }
193 }
194 }
195
196 async getPlayerLoadOptions (options: {
157 video: VideoDetails 197 video: VideoDetails
158 captionsResponse: Response 198 captionsResponse: Response
159 199
@@ -161,39 +201,35 @@ export class PlayerManagerOptions {
161 201
162 live?: LiveVideo 202 live?: LiveVideo
163 203
204 alreadyPlayed: boolean
164 forceAutoplay: boolean 205 forceAutoplay: boolean
165 206
166 authorizationHeader: () => string
167 videoFileToken: () => string 207 videoFileToken: () => string
168 208
169 videoPassword: () => string 209 videoPassword: () => string
170 requiresPassword: boolean 210 requiresPassword: boolean
171 211
172 serverConfig: HTMLServerConfig
173
174 autoplayFromPreviousVideo: boolean
175
176 translations: Translations 212 translations: Translations
177 213
178 playlistTracker?: PlaylistTracker 214 playlist?: {
179 playNextPlaylistVideo?: () => any 215 playlistTracker: PlaylistTracker
180 playPreviousPlaylistVideo?: () => any 216 playNext: () => any
181 onVideoUpdate?: (uuid: string) => any 217 playPrevious: () => any
182 }) { 218 onVideoUpdate: (uuid: string) => any
219 }
220 }): Promise<PeerTubePlayerLoadOptions> {
183 const { 221 const {
184 video, 222 video,
185 captionsResponse, 223 captionsResponse,
186 autoplayFromPreviousVideo,
187 videoFileToken, 224 videoFileToken,
188 videoPassword, 225 videoPassword,
189 requiresPassword, 226 requiresPassword,
190 translations, 227 translations,
228 alreadyPlayed,
191 forceAutoplay, 229 forceAutoplay,
192 playlistTracker, 230 playlist,
193 live, 231 live,
194 storyboardsResponse, 232 storyboardsResponse
195 authorizationHeader,
196 serverConfig
197 } = options 233 } = options
198 234
199 const [ videoCaptions, storyboard ] = await Promise.all([ 235 const [ videoCaptions, storyboard ] = await Promise.all([
@@ -201,88 +237,56 @@ export class PlayerManagerOptions {
201 this.buildStoryboard(storyboardsResponse) 237 this.buildStoryboard(storyboardsResponse)
202 ]) 238 ])
203 239
204 const playerOptions: PeertubePlayerManagerOptions = { 240 return {
205 common: { 241 mode: this.mode,
206 // Autoplay in playlist mode
207 autoplay: autoplayFromPreviousVideo ? true : this.autoplay,
208 forceAutoplay,
209
210 controls: this.controls,
211 controlBar: this.controlBar,
212
213 muted: this.muted,
214 loop: this.loop,
215
216 p2pEnabled: this.p2pEnabled,
217
218 captions: videoCaptions.length !== 0,
219 subtitle: this.subtitle,
220 242
221 storyboard, 243 autoplay: forceAutoplay || alreadyPlayed || this.autoplay,
244 forceAutoplay,
222 245
223 startTime: playlistTracker 246 p2pEnabled: this.p2pEnabled,
224 ? playlistTracker.getCurrentElement().startTimestamp
225 : this.startTime,
226 stopTime: playlistTracker
227 ? playlistTracker.getCurrentElement().stopTimestamp
228 : this.stopTime,
229 247
230 playbackRate: this.playbackRate, 248 subtitle: this.subtitle,
231 249
232 videoCaptions, 250 storyboard,
233 inactivityTimeout: 2500,
234 videoViewUrl: this.videoFetcher.getVideoViewsUrl(video.uuid),
235 videoViewIntervalMs: 5000,
236 metricsUrl: window.location.origin + '/api/v1/metrics/playback',
237 251
238 videoShortUUID: video.shortUUID, 252 startTime: playlist
239 videoUUID: video.uuid, 253 ? playlist.playlistTracker.getCurrentElement().startTimestamp
254 : this.startTime,
255 stopTime: playlist
256 ? playlist.playlistTracker.getCurrentElement().stopTimestamp
257 : this.stopTime,
240 258
241 playerElement: this.playerHTML.getPlayerElement(), 259 videoCaptions,
242 onPlayerElementChange: (element: HTMLVideoElement) => { 260 videoViewUrl: this.videoFetcher.getVideoViewsUrl(video.uuid),
243 this.playerHTML.setPlayerElement(element)
244 },
245 261
246 videoDuration: video.duration, 262 videoShortUUID: video.shortUUID,
247 enableHotkeys: true, 263 videoUUID: video.uuid,
248 264
249 peertubeLink: this.peertubeLink, 265 duration: video.duration,
250 instanceName: serverConfig.instance.name,
251 266
252 poster: window.location.origin + video.previewPath, 267 poster: window.location.origin + video.previewPath,
253 theaterButton: false,
254 268
255 serverUrl: window.location.origin, 269 embedUrl: window.location.origin + video.embedPath,
256 language: navigator.language, 270 embedTitle: video.name,
257 embedUrl: window.location.origin + video.embedPath,
258 embedTitle: video.name,
259 271
260 requiresUserAuth: videoRequiresUserAuth(video), 272 requiresUserAuth: videoRequiresUserAuth(video),
261 authorizationHeader, 273 videoFileToken,
262 videoFileToken,
263 274
264 requiresPassword, 275 requiresPassword,
265 videoPassword, 276 videoPassword,
266 277
267 errorNotifier: () => { 278 ...this.buildLiveOptions(video, live),
268 // Empty, we don't have a notifier in the embed
269 },
270 279
271 ...this.buildLiveOptions(video, live), 280 ...this.buildPlaylistOptions(playlist),
272 281
273 ...this.buildPlaylistOptions(options) 282 dock: this.buildDockOptions(video),
274 },
275 283
276 webtorrent: { 284 webVideo: {
277 videoFiles: video.files 285 videoFiles: video.files
278 }, 286 },
279 287
280 ...this.buildP2PMediaLoaderOptions(video), 288 hls: this.buildHLSOptions(video)
281
282 pluginsManager: this.peertubePlugin.getPluginsManager()
283 } 289 }
284
285 return playerOptions
286 } 290 }
287 291
288 private buildLiveOptions (video: VideoDetails, live: LiveVideo) { 292 private buildLiveOptions (video: VideoDetails, live: LiveVideo) {
@@ -308,15 +312,27 @@ export class PlayerManagerOptions {
308 } 312 }
309 } 313 }
310 314
311 private buildPlaylistOptions (options: { 315 private buildPlaylistOptions (options?: {
312 playlistTracker?: PlaylistTracker 316 playlistTracker: PlaylistTracker
313 playNextPlaylistVideo?: () => any 317 playNext: () => any
314 playPreviousPlaylistVideo?: () => any 318 playPrevious: () => any
315 onVideoUpdate?: (uuid: string) => any 319 onVideoUpdate: (uuid: string) => any
316 }) { 320 }) {
317 const { playlistTracker, playNextPlaylistVideo, playPreviousPlaylistVideo, onVideoUpdate } = options 321 if (!options) {
322 return {
323 nextVideo: {
324 enabled: false,
325 displayControlBarButton: false,
326 getVideoTitle: () => ''
327 },
328 previousVideo: {
329 enabled: false,
330 displayControlBarButton: false
331 }
332 }
333 }
318 334
319 if (!playlistTracker) return {} 335 const { playlistTracker, playNext, playPrevious, onVideoUpdate } = options
320 336
321 return { 337 return {
322 playlist: { 338 playlist: {
@@ -332,27 +348,37 @@ export class PlayerManagerOptions {
332 } 348 }
333 }, 349 },
334 350
335 nextVideo: () => playNextPlaylistVideo(), 351 previousVideo: {
336 hasNextVideo: () => playlistTracker.hasNextPlaylistElement(), 352 enabled: playlistTracker.hasPreviousPlaylistElement(),
353 handler: () => playPrevious(),
354 displayControlBarButton: true
355 },
356
357 nextVideo: {
358 enabled: playlistTracker.hasNextPlaylistElement(),
359 handler: () => playNext(),
360 getVideoTitle: () => playlistTracker.getNextPlaylistElement()?.video?.name,
361 displayControlBarButton: true
362 },
337 363
338 previousVideo: () => playPreviousPlaylistVideo(), 364 upnext: {
339 hasPreviousVideo: () => playlistTracker.hasPreviousPlaylistElement() 365 isEnabled: () => true,
366 isSuspended: () => false,
367 timeout: 0
368 }
340 } 369 }
341 } 370 }
342 371
343 private buildP2PMediaLoaderOptions (video: VideoDetails) { 372 private buildHLSOptions (video: VideoDetails): HLSOptions {
344 if (this.mode !== 'p2p-media-loader') return {}
345
346 const hlsPlaylist = video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) 373 const hlsPlaylist = video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
374 if (!hlsPlaylist) return undefined
347 375
348 return { 376 return {
349 p2pMediaLoader: { 377 playlistUrl: hlsPlaylist.playlistUrl,
350 playlistUrl: hlsPlaylist.playlistUrl, 378 segmentsSha256Url: hlsPlaylist.segmentsSha256Url,
351 segmentsSha256Url: hlsPlaylist.segmentsSha256Url, 379 redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl),
352 redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl), 380 trackerAnnounce: video.trackerUrls,
353 trackerAnnounce: video.trackerUrls, 381 videoFiles: hlsPlaylist.files
354 videoFiles: hlsPlaylist.files
355 } as P2PMediaLoaderOptions
356 } 382 }
357 } 383 }
358 384
@@ -374,6 +400,35 @@ export class PlayerManagerOptions {
374 400
375 // --------------------------------------------------------------------------- 401 // ---------------------------------------------------------------------------
376 402
403 private buildDockOptions (videoInfo: VideoDetails) {
404 if (!this.hasControls()) return undefined
405
406 const title = this.hasTitle()
407 ? videoInfo.name
408 : undefined
409
410 const description = this.hasWarningTitle() && this.hasP2PEnabled()
411 ? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>'
412 : undefined
413
414 if (!title && !description) return
415
416 const availableAvatars = videoInfo.channel.avatars.filter(a => a.width < 50)
417 const avatar = availableAvatars.length !== 0
418 ? availableAvatars[0]
419 : undefined
420
421 return {
422 title,
423 description,
424 avatarUrl: title && avatar
425 ? avatar.path
426 : undefined
427 }
428 }
429
430 // ---------------------------------------------------------------------------
431
377 private isP2PEnabled (config: HTMLServerConfig, video: Video) { 432 private isP2PEnabled (config: HTMLServerConfig, video: Video) {
378 const userP2PEnabled = getBoolOrDefault( 433 const userP2PEnabled = getBoolOrDefault(
379 peertubeLocalStorage.getItem(UserLocalStorageKeys.P2P_ENABLED), 434 peertubeLocalStorage.getItem(UserLocalStorageKeys.P2P_ENABLED),