aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/standalone/videos/embed.ts
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/standalone/videos/embed.ts')
-rw-r--r--client/src/standalone/videos/embed.ts180
1 files changed, 103 insertions, 77 deletions
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 54b8fb543..707f04253 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -1,33 +1,18 @@
1import './embed.scss' 1import './embed.scss'
2 2
3import 'core-js/es6/symbol'
4import 'core-js/es6/object'
5import 'core-js/es6/function'
6import 'core-js/es6/parse-int'
7import 'core-js/es6/parse-float'
8import 'core-js/es6/number'
9import 'core-js/es6/math'
10import 'core-js/es6/string'
11import 'core-js/es6/date'
12import 'core-js/es6/array'
13import 'core-js/es6/regexp'
14import 'core-js/es6/map'
15import 'core-js/es6/weak-map'
16import 'core-js/es6/set'
17// For google bot that uses Chrome 41 and does not understand fetch
18import 'whatwg-fetch'
19
20// FIXME: something weird with our path definition in tsconfig and typings
21// @ts-ignore
22import * as vjs from 'video.js'
23
24import * as Channel from 'jschannel' 3import * as Channel from 'jschannel'
25 4
26import { peertubeTranslate, ResultList, VideoDetails } from '../../../../shared' 5import { peertubeTranslate, ResultList, ServerConfig, VideoDetails } from '../../../../shared'
27import { addContextMenu, getServerTranslations, getVideojsOptions, loadLocaleInVideoJS } from '../../assets/player/peertube-player'
28import { PeerTubeResolution } from '../player/definitions' 6import { PeerTubeResolution } from '../player/definitions'
29import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' 7import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
30import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' 8import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
9import {
10 P2PMediaLoaderOptions,
11 PeertubePlayerManager,
12 PeertubePlayerManagerOptions,
13 PlayerMode
14} from '../../assets/player/peertube-player-manager'
15import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
31 16
32/** 17/**
33 * Embed API exposes control of the embed player to the outside world via 18 * Embed API exposes control of the embed player to the outside world via
@@ -55,7 +40,7 @@ class PeerTubeEmbedApi {
55 } 40 }
56 41
57 private constructChannel () { 42 private constructChannel () {
58 let channel = Channel.build({ window: window.parent, origin: '*', scope: this.embed.scope }) 43 const channel = Channel.build({ window: window.parent, origin: '*', scope: this.embed.scope })
59 44
60 channel.bind('play', (txn, params) => this.embed.player.play()) 45 channel.bind('play', (txn, params) => this.embed.player.play())
61 channel.bind('pause', (txn, params) => this.embed.player.pause()) 46 channel.bind('pause', (txn, params) => this.embed.player.pause())
@@ -73,16 +58,16 @@ class PeerTubeEmbedApi {
73 } 58 }
74 59
75 private setResolution (resolutionId: number) { 60 private setResolution (resolutionId: number) {
76 if (resolutionId === -1 && this.embed.player.peertube().isAutoResolutionForbidden()) return 61 if (resolutionId === -1 && this.embed.player.webtorrent().isAutoResolutionForbidden()) return
77 62
78 // Auto resolution 63 // Auto resolution
79 if (resolutionId === -1) { 64 if (resolutionId === -1) {
80 this.embed.player.peertube().enableAutoResolution() 65 this.embed.player.webtorrent().enableAutoResolution()
81 return 66 return
82 } 67 }
83 68
84 this.embed.player.peertube().disableAutoResolution() 69 this.embed.player.webtorrent().disableAutoResolution()
85 this.embed.player.peertube().updateResolution(resolutionId) 70 this.embed.player.webtorrent().updateResolution(resolutionId)
86 } 71 }
87 72
88 /** 73 /**
@@ -97,8 +82,8 @@ class PeerTubeEmbedApi {
97 let currentState: 'playing' | 'paused' | 'unstarted' = 'unstarted' 82 let currentState: 'playing' | 'paused' | 'unstarted' = 'unstarted'
98 83
99 setInterval(() => { 84 setInterval(() => {
100 let position = this.element.currentTime 85 const position = this.element.currentTime
101 let volume = this.element.volume 86 const volume = this.element.volume
102 87
103 this.channel.notify({ 88 this.channel.notify({
104 method: 'playbackStatusUpdate', 89 method: 'playbackStatusUpdate',
@@ -122,15 +107,17 @@ class PeerTubeEmbedApi {
122 107
123 // PeerTube specific capabilities 108 // PeerTube specific capabilities
124 109
125 this.embed.player.peertube().on('autoResolutionUpdate', () => this.loadResolutions()) 110 if (this.embed.player.webtorrent) {
126 this.embed.player.peertube().on('videoFileUpdate', () => this.loadResolutions()) 111 this.embed.player.webtorrent().on('autoResolutionUpdate', () => this.loadWebTorrentResolutions())
112 this.embed.player.webtorrent().on('videoFileUpdate', () => this.loadWebTorrentResolutions())
113 }
127 } 114 }
128 115
129 private loadResolutions () { 116 private loadWebTorrentResolutions () {
130 let resolutions = [] 117 const resolutions = []
131 let currentResolutionId = this.embed.player.peertube().getCurrentResolutionId() 118 const currentResolutionId = this.embed.player.webtorrent().getCurrentResolutionId()
132 119
133 for (const videoFile of this.embed.player.peertube().videoFiles) { 120 for (const videoFile of this.embed.player.webtorrent().videoFiles) {
134 let label = videoFile.resolution.label 121 let label = videoFile.resolution.label
135 if (videoFile.fps && videoFile.fps >= 50) { 122 if (videoFile.fps && videoFile.fps >= 50) {
136 label += videoFile.fps 123 label += videoFile.fps
@@ -164,6 +151,8 @@ class PeerTubeEmbed {
164 subtitle: string 151 subtitle: string
165 enableApi = false 152 enableApi = false
166 startTime: number | string = 0 153 startTime: number | string = 0
154 stopTime: number | string
155 mode: PlayerMode
167 scope = 'peertube' 156 scope = 'peertube'
168 157
169 static async main () { 158 static async main () {
@@ -188,6 +177,10 @@ class PeerTubeEmbed {
188 return fetch(this.getVideoUrl(videoId) + '/captions') 177 return fetch(this.getVideoUrl(videoId) + '/captions')
189 } 178 }
190 179
180 loadConfig (): Promise<Response> {
181 return fetch('/api/v1/config')
182 }
183
191 removeElement (element: HTMLElement) { 184 removeElement (element: HTMLElement) {
192 element.parentElement.removeChild(element) 185 element.parentElement.removeChild(element)
193 } 186 }
@@ -246,17 +239,20 @@ class PeerTubeEmbed {
246 239
247 private loadParams () { 240 private loadParams () {
248 try { 241 try {
249 let params = new URL(window.location.toString()).searchParams 242 const params = new URL(window.location.toString()).searchParams
250 243
251 this.autoplay = this.getParamToggle(params, 'autoplay') 244 this.autoplay = this.getParamToggle(params, 'autoplay', false)
252 this.controls = this.getParamToggle(params, 'controls') 245 this.controls = this.getParamToggle(params, 'controls', true)
253 this.muted = this.getParamToggle(params, 'muted') 246 this.muted = this.getParamToggle(params, 'muted', false)
254 this.loop = this.getParamToggle(params, 'loop') 247 this.loop = this.getParamToggle(params, 'loop', false)
255 this.enableApi = this.getParamToggle(params, 'api', this.enableApi) 248 this.enableApi = this.getParamToggle(params, 'api', this.enableApi)
256 249
257 this.scope = this.getParamString(params, 'scope', this.scope) 250 this.scope = this.getParamString(params, 'scope', this.scope)
258 this.subtitle = this.getParamString(params, 'subtitle') 251 this.subtitle = this.getParamString(params, 'subtitle')
259 this.startTime = this.getParamString(params, 'start') 252 this.startTime = this.getParamString(params, 'start')
253 this.stopTime = this.getParamString(params, 'stop')
254
255 this.mode = this.getParamString(params, 'mode') === 'p2p-media-loader' ? 'p2p-media-loader' : 'webtorrent'
260 } catch (err) { 256 } catch (err) {
261 console.error('Cannot get params from URL.', err) 257 console.error('Cannot get params from URL.', err)
262 } 258 }
@@ -266,11 +262,11 @@ class PeerTubeEmbed {
266 const urlParts = window.location.pathname.split('/') 262 const urlParts = window.location.pathname.split('/')
267 const videoId = urlParts[ urlParts.length - 1 ] 263 const videoId = urlParts[ urlParts.length - 1 ]
268 264
269 const [ , serverTranslations, videoResponse, captionsResponse ] = await Promise.all([ 265 const [ serverTranslations, videoResponse, captionsResponse, configResponse ] = await Promise.all([
270 loadLocaleInVideoJS(window.location.origin, vjs, navigator.language), 266 PeertubePlayerManager.getServerTranslations(window.location.origin, navigator.language),
271 getServerTranslations(window.location.origin, navigator.language),
272 this.loadVideoInfo(videoId), 267 this.loadVideoInfo(videoId),
273 this.loadVideoCaptions(videoId) 268 this.loadVideoCaptions(videoId),
269 this.loadConfig()
274 ]) 270 ])
275 271
276 if (!videoResponse.ok) { 272 if (!videoResponse.ok) {
@@ -292,43 +288,73 @@ class PeerTubeEmbed {
292 288
293 this.loadParams() 289 this.loadParams()
294 290
295 const videojsOptions = getVideojsOptions({ 291 const options: PeertubePlayerManagerOptions = {
296 autoplay: this.autoplay, 292 common: {
297 controls: this.controls, 293 autoplay: this.autoplay,
298 muted: this.muted, 294 controls: this.controls,
299 loop: this.loop, 295 muted: this.muted,
300 startTime: this.startTime, 296 loop: this.loop,
301 subtitle: this.subtitle, 297 captions: videoCaptions.length !== 0,
302 298 startTime: this.startTime,
303 videoCaptions, 299 stopTime: this.stopTime,
304 inactivityTimeout: 1500, 300 subtitle: this.subtitle,
305 videoViewUrl: this.getVideoUrl(videoId) + '/views', 301
306 playerElement: this.videoElement, 302 videoCaptions,
307 videoFiles: videoInfo.files, 303 inactivityTimeout: 1500,
308 videoDuration: videoInfo.duration, 304 videoViewUrl: this.getVideoUrl(videoId) + '/views',
309 enableHotkeys: true, 305
310 peertubeLink: true, 306 playerElement: this.videoElement,
311 poster: window.location.origin + videoInfo.previewPath, 307 onPlayerElementChange: (element: HTMLVideoElement) => this.videoElement = element,
312 theaterMode: false 308
313 }) 309 videoDuration: videoInfo.duration,
310 enableHotkeys: true,
311 peertubeLink: true,
312 poster: window.location.origin + videoInfo.previewPath,
313 theaterMode: false,
314
315 serverUrl: window.location.origin,
316 language: navigator.language,
317 embedUrl: window.location.origin + videoInfo.embedPath
318 },
319
320 webtorrent: {
321 videoFiles: videoInfo.files
322 }
323 }
314 324
315 this.playerOptions = videojsOptions 325 if (this.mode === 'p2p-media-loader') {
316 this.player = vjs(this.videoContainerId, videojsOptions, () => { 326 const hlsPlaylist = videoInfo.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
317 this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) 327
328 Object.assign(options, {
329 p2pMediaLoader: {
330 playlistUrl: hlsPlaylist.playlistUrl,
331 segmentsSha256Url: hlsPlaylist.segmentsSha256Url,
332 redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl),
333 trackerAnnounce: videoInfo.trackerUrls,
334 videoFiles: videoInfo.files
335 } as P2PMediaLoaderOptions
336 })
337 }
318 338
319 window[ 'videojsPlayer' ] = this.player 339 this.player = await PeertubePlayerManager.initialize(this.mode, options)
320 340
321 if (this.controls) { 341 this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations))
322 this.player.dock({
323 title: videoInfo.name,
324 description: this.player.localize('Uses P2P, others may know your IP is downloading this video.')
325 })
326 }
327 342
328 addContextMenu(this.player, window.location.origin + videoInfo.embedPath) 343 window[ 'videojsPlayer' ] = this.player
329 344
330 this.initializeApi() 345 if (this.controls) {
331 }) 346 const config: ServerConfig = await configResponse.json()
347 const description = config.tracker.enabled
348 ? '<span class="text">' + this.player.localize('Uses P2P, others may know your IP is downloading this video.') + '</span>'
349 : undefined
350
351 this.player.dock({
352 title: videoInfo.name,
353 description
354 })
355 }
356
357 this.initializeApi()
332 } 358 }
333 359
334 private handleError (err: Error, translations?: { [ id: string ]: string }) { 360 private handleError (err: Error, translations?: { [ id: string ]: string }) {