aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/standalone/videos
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/standalone/videos')
-rw-r--r--client/src/standalone/videos/embed-api.ts34
-rw-r--r--client/src/standalone/videos/embed.ts46
-rw-r--r--client/src/standalone/videos/test-embed.html6
-rw-r--r--client/src/standalone/videos/test-embed.ts36
4 files changed, 94 insertions, 28 deletions
diff --git a/client/src/standalone/videos/embed-api.ts b/client/src/standalone/videos/embed-api.ts
index 61e5d0b9a..a9263555d 100644
--- a/client/src/standalone/videos/embed-api.ts
+++ b/client/src/standalone/videos/embed-api.ts
@@ -1,7 +1,7 @@
1import './embed.scss' 1import './embed.scss'
2 2
3import * as Channel from 'jschannel' 3import * as Channel from 'jschannel'
4import { PeerTubeResolution } from '../player/definitions' 4import { PeerTubeResolution, PeerTubeTextTrack } from '../player/definitions'
5import { PeerTubeEmbed } from './embed' 5import { PeerTubeEmbed } from './embed'
6 6
7/** 7/**
@@ -44,6 +44,9 @@ export class PeerTubeEmbedApi {
44 channel.bind('setResolution', (txn, resolutionId) => this.setResolution(resolutionId)) 44 channel.bind('setResolution', (txn, resolutionId) => this.setResolution(resolutionId))
45 channel.bind('getResolutions', (txn, params) => this.resolutions) 45 channel.bind('getResolutions', (txn, params) => this.resolutions)
46 46
47 channel.bind('getCaptions', (txn, params) => this.getCaptions())
48 channel.bind('setCaption', (txn, id) => this.setCaption(id)),
49
47 channel.bind('setPlaybackRate', (txn, playbackRate) => this.embed.player.playbackRate(playbackRate)) 50 channel.bind('setPlaybackRate', (txn, playbackRate) => this.embed.player.playbackRate(playbackRate))
48 channel.bind('getPlaybackRate', (txn, params) => this.embed.player.playbackRate()) 51 channel.bind('getPlaybackRate', (txn, params) => this.embed.player.playbackRate())
49 channel.bind('getPlaybackRates', (txn, params) => this.embed.player.options_.playbackRates) 52 channel.bind('getPlaybackRates', (txn, params) => this.embed.player.options_.playbackRates)
@@ -71,6 +74,26 @@ export class PeerTubeEmbedApi {
71 this.embed.player.p2pMediaLoader().getHLSJS().nextLevel = resolutionId 74 this.embed.player.p2pMediaLoader().getHLSJS().nextLevel = resolutionId
72 } 75 }
73 76
77 private getCaptions (): PeerTubeTextTrack[] {
78 return this.embed.player.textTracks().tracks_.map(t => {
79 return {
80 id: t.id,
81 src: t.src,
82 label: t.label,
83 mode: t.mode as any
84 }
85 })
86 }
87
88 private setCaption (id: string) {
89 const tracks = this.embed.player.textTracks().tracks_
90
91 for (const track of tracks) {
92 if (track.id === id) track.mode = 'showing'
93 else track.mode = 'disabled'
94 }
95 }
96
74 /** 97 /**
75 * Let the host know that we're ready to go! 98 * Let the host know that we're ready to go!
76 */ 99 */
@@ -80,17 +103,19 @@ export class PeerTubeEmbedApi {
80 } 103 }
81 104
82 private setupStateTracking () { 105 private setupStateTracking () {
83 let currentState: 'playing' | 'paused' | 'unstarted' = 'unstarted' 106 let currentState: 'playing' | 'paused' | 'unstarted' | 'ended' = 'unstarted'
84 107
85 setInterval(() => { 108 setInterval(() => {
86 const position = this.element.currentTime 109 const position = this.element.currentTime
87 const volume = this.element.volume 110 const volume = this.element.volume
111 const duration = this.element.duration
88 112
89 this.channel.notify({ 113 this.channel.notify({
90 method: 'playbackStatusUpdate', 114 method: 'playbackStatusUpdate',
91 params: { 115 params: {
92 position, 116 position,
93 volume, 117 volume,
118 duration: this.embed.player.duration(),
94 playbackState: currentState 119 playbackState: currentState
95 } 120 }
96 }) 121 })
@@ -106,6 +131,11 @@ export class PeerTubeEmbedApi {
106 this.channel.notify({ method: 'playbackStatusChange', params: 'paused' }) 131 this.channel.notify({ method: 'playbackStatusChange', params: 'paused' })
107 }) 132 })
108 133
134 this.element.addEventListener('ended', ev => {
135 currentState = 'ended'
136 this.channel.notify({ method: 'playbackStatusChange', params: 'ended' })
137 })
138
109 // PeerTube specific capabilities 139 // PeerTube specific capabilities
110 140
111 if (this.isWebtorrent()) { 141 if (this.isWebtorrent()) {
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 5213443fc..286757e5e 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -1,15 +1,11 @@
1import './embed.scss' 1import './embed.scss'
2 2
3import { 3import {
4 getCompleteLocale,
5 is18nLocale,
6 isDefaultLocale,
7 peertubeTranslate, 4 peertubeTranslate,
8 ResultList, 5 ResultList,
9 ServerConfig, 6 ServerConfig,
10 VideoDetails 7 VideoDetails
11} from '../../../../shared' 8} from '../../../../shared'
12import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
13import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' 9import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
14import { 10import {
15 P2PMediaLoaderOptions, 11 P2PMediaLoaderOptions,
@@ -19,10 +15,14 @@ import {
19import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' 15import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
20import { PeerTubeEmbedApi } from './embed-api' 16import { PeerTubeEmbedApi } from './embed-api'
21import { TranslationsManager } from '../../assets/player/translations-manager' 17import { TranslationsManager } from '../../assets/player/translations-manager'
18import videojs from 'video.js'
19import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
20
21type Translations = { [ id: string ]: string }
22 22
23export class PeerTubeEmbed { 23export class PeerTubeEmbed {
24 videoElement: HTMLVideoElement 24 videoElement: HTMLVideoElement
25 player: any 25 player: videojs.Player
26 api: PeerTubeEmbedApi = null 26 api: PeerTubeEmbedApi = null
27 autoplay: boolean 27 autoplay: boolean
28 controls: boolean 28 controls: boolean
@@ -71,7 +71,7 @@ export class PeerTubeEmbed {
71 element.parentElement.removeChild(element) 71 element.parentElement.removeChild(element)
72 } 72 }
73 73
74 displayError (text: string, translations?: { [ id: string ]: string }) { 74 displayError (text: string, translations?: Translations) {
75 // Remove video element 75 // Remove video element
76 if (this.videoElement) this.removeElement(this.videoElement) 76 if (this.videoElement) this.removeElement(this.videoElement)
77 77
@@ -90,12 +90,12 @@ export class PeerTubeEmbed {
90 errorText.innerHTML = translatedText 90 errorText.innerHTML = translatedText
91 } 91 }
92 92
93 videoNotFound (translations?: { [ id: string ]: string }) { 93 videoNotFound (translations?: Translations) {
94 const text = 'This video does not exist.' 94 const text = 'This video does not exist.'
95 this.displayError(text, translations) 95 this.displayError(text, translations)
96 } 96 }
97 97
98 videoFetchError (translations?: { [ id: string ]: string }) { 98 videoFetchError (translations?: Translations) {
99 const text = 'We cannot fetch the video. Please try again later.' 99 const text = 'We cannot fetch the video. Please try again later.'
100 this.displayError(text, translations) 100 this.displayError(text, translations)
101 } 101 }
@@ -129,7 +129,7 @@ export class PeerTubeEmbed {
129 129
130 this.autoplay = this.getParamToggle(params, 'autoplay', false) 130 this.autoplay = this.getParamToggle(params, 'autoplay', false)
131 this.controls = this.getParamToggle(params, 'controls', true) 131 this.controls = this.getParamToggle(params, 'controls', true)
132 this.muted = this.getParamToggle(params, 'muted', false) 132 this.muted = this.getParamToggle(params, 'muted', undefined)
133 this.loop = this.getParamToggle(params, 'loop', false) 133 this.loop = this.getParamToggle(params, 'loop', false)
134 this.title = this.getParamToggle(params, 'title', true) 134 this.title = this.getParamToggle(params, 'title', true)
135 this.enableApi = this.getParamToggle(params, 'api', this.enableApi) 135 this.enableApi = this.getParamToggle(params, 'api', this.enableApi)
@@ -237,7 +237,7 @@ export class PeerTubeEmbed {
237 }) 237 })
238 } 238 }
239 239
240 this.player = await PeertubePlayerManager.initialize(this.mode, options, (player: any) => this.player = player) 240 this.player = await PeertubePlayerManager.initialize(this.mode, options, (player: videojs.Player) => this.player = player)
241 this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) 241 this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations))
242 242
243 window[ 'videojsPlayer' ] = this.player 243 window[ 'videojsPlayer' ] = this.player
@@ -261,22 +261,22 @@ export class PeerTubeEmbed {
261 } 261 }
262 262
263 private async buildDock (videoInfo: VideoDetails, configResponse: Response) { 263 private async buildDock (videoInfo: VideoDetails, configResponse: Response) {
264 if (this.controls) { 264 if (!this.controls) return
265 // On webtorrent fallback, player may have been disposed
266 if (!this.player.player_) return
267 265
268 const title = this.title ? videoInfo.name : undefined 266 // On webtorrent fallback, player may have been disposed
267 if (!this.player.player_) return
269 268
270 const config: ServerConfig = await configResponse.json() 269 const title = this.title ? videoInfo.name : undefined
271 const description = config.tracker.enabled && this.warningTitle
272 ? '<span class="text">' + this.player.localize('Watching this video may reveal your IP address to others.') + '</span>'
273 : undefined
274 270
275 this.player.dock({ 271 const config: ServerConfig = await configResponse.json()
276 title, 272 const description = config.tracker.enabled && this.warningTitle
277 description 273 ? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>'
278 }) 274 : undefined
279 } 275
276 this.player.dock({
277 title,
278 description
279 })
280 } 280 }
281 281
282 private buildCSS () { 282 private buildCSS () {
diff --git a/client/src/standalone/videos/test-embed.html b/client/src/standalone/videos/test-embed.html
index 20cdbdc5f..9e1d6fc61 100644
--- a/client/src/standalone/videos/test-embed.html
+++ b/client/src/standalone/videos/test-embed.html
@@ -38,6 +38,12 @@
38 </fieldset> 38 </fieldset>
39 39
40 <fieldset> 40 <fieldset>
41 <legend>Captions:</legend>
42 <div id="caption-list"></div>
43 <br/>
44 </fieldset>
45
46 <fieldset>
41 <legend>Rates:</legend> 47 <legend>Rates:</legend>
42 <div id="rate-list"></div> 48 <div id="rate-list"></div>
43 </fieldset> 49 </fieldset>
diff --git a/client/src/standalone/videos/test-embed.ts b/client/src/standalone/videos/test-embed.ts
index e5e6365dc..24cb62230 100644
--- a/client/src/standalone/videos/test-embed.ts
+++ b/client/src/standalone/videos/test-embed.ts
@@ -1,6 +1,6 @@
1import './test-embed.scss' 1import './test-embed.scss'
2import { PeerTubePlayer } from '../player/player' 2import { PeerTubePlayer } from '../player/player'
3import { PeerTubeResolution, PlayerEventType } from '../player/definitions' 3import { PeerTubeResolution, PlayerEventType, PeerTubeTextTrack } from '../player/definitions'
4 4
5window.addEventListener('load', async () => { 5window.addEventListener('load', async () => {
6 const urlParts = window.location.href.split('/') 6 const urlParts = window.location.href.split('/')
@@ -8,7 +8,7 @@ window.addEventListener('load', async () => {
8 const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ] 8 const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ]
9 9
10 const iframe = document.createElement('iframe') 10 const iframe = document.createElement('iframe')
11 iframe.src = `/videos/embed/${videoId}?autoplay=1&controls=0&api=1` 11 iframe.src = `/videos/embed/${videoId}?api=1`
12 12
13 const mainElement = document.querySelector('#host') 13 const mainElement = document.querySelector('#host')
14 mainElement.appendChild(iframe) 14 mainElement.appendChild(iframe)
@@ -30,7 +30,7 @@ window.addEventListener('load', async () => {
30 ] 30 ]
31 31
32 monitoredEvents.forEach(e => { 32 monitoredEvents.forEach(e => {
33 player.addEventListener(e as PlayerEventType, () => console.log(`PLAYER: event '${e}' received`)) 33 player.addEventListener(e as PlayerEventType, (param) => console.log(`PLAYER: event '${e}' received`, param))
34 console.log(`PLAYER: now listening for event '${e}'`) 34 console.log(`PLAYER: now listening for event '${e}'`)
35 }) 35 })
36 36
@@ -67,6 +67,36 @@ window.addEventListener('load', async () => {
67 updateRates() 67 updateRates()
68 }) 68 })
69 69
70 const updateCaptions = async () => {
71 const captions = await player.getCaptions()
72
73 const captionEl = document.querySelector('#caption-list')
74 captionEl.innerHTML = ''
75
76 captions.forEach(c => {
77 console.log(c)
78
79 if (c.mode === 'showing') {
80 const itemEl = document.createElement('strong')
81 itemEl.innerText = `${c.label} (active)`
82 itemEl.style.display = 'block'
83 captionEl.appendChild(itemEl)
84 } else {
85 const itemEl = document.createElement('a')
86 itemEl.href = 'javascript:;'
87 itemEl.innerText = c.label
88 itemEl.addEventListener('click', () => {
89 player.setCaption(c.id)
90 updateCaptions()
91 })
92 itemEl.style.display = 'block'
93 captionEl.appendChild(itemEl)
94 }
95 })
96 }
97
98 updateCaptions()
99
70 const updateResolutions = ((resolutions: PeerTubeResolution[]) => { 100 const updateResolutions = ((resolutions: PeerTubeResolution[]) => {
71 const resolutionListEl = document.querySelector('#resolution-list') 101 const resolutionListEl = document.querySelector('#resolution-list')
72 resolutionListEl.innerHTML = '' 102 resolutionListEl.innerHTML = ''