aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-07-13 18:21:19 +0200
committerChocobozzz <me@florianbigard.com>2018-07-16 11:50:08 +0200
commit16f7022b06fb76c0b00c23c970bc8df605b0ec63 (patch)
tree0677c72b449485dcaa87ee2b470dfb1a8124b9e0 /client/src
parent40e87e9ecc54e3513fb586928330a7855eb192c6 (diff)
downloadPeerTube-16f7022b06fb76c0b00c23c970bc8df605b0ec63.tar.gz
PeerTube-16f7022b06fb76c0b00c23c970bc8df605b0ec63.tar.zst
PeerTube-16f7022b06fb76c0b00c23c970bc8df605b0ec63.zip
Handle subtitles in player
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts1
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts37
-rw-r--r--client/src/assets/player/peertube-player.ts25
-rw-r--r--client/src/assets/player/peertube-videojs-plugin.ts20
-rw-r--r--client/src/assets/player/peertube-videojs-typings.ts12
-rw-r--r--client/src/assets/player/settings-menu-item.ts2
-rw-r--r--client/src/sass/player/settings-menu.scss26
-rw-r--r--client/src/standalone/videos/embed.ts30
8 files changed, 124 insertions, 29 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
index 8d476393f..c77249a02 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
@@ -213,6 +213,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
213 servicesTwitterUsername: this.customConfig.services.twitter.username, 213 servicesTwitterUsername: this.customConfig.services.twitter.username,
214 servicesTwitterWhitelisted: this.customConfig.services.twitter.whitelisted, 214 servicesTwitterWhitelisted: this.customConfig.services.twitter.whitelisted,
215 cachePreviewsSize: this.customConfig.cache.previews.size, 215 cachePreviewsSize: this.customConfig.cache.previews.size,
216 cacheCaptionsSize: this.customConfig.cache.captions.size,
216 signupEnabled: this.customConfig.signup.enabled, 217 signupEnabled: this.customConfig.signup.enabled,
217 signupLimit: this.customConfig.signup.limit, 218 signupLimit: this.customConfig.signup.limit,
218 adminEmail: this.customConfig.admin.email, 219 adminEmail: this.customConfig.admin.email,
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index 8adf97d48..601c6a38d 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -6,11 +6,11 @@ import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
6import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' 6import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
7import { MetaService } from '@ngx-meta/core' 7import { MetaService } from '@ngx-meta/core'
8import { NotificationsService } from 'angular2-notifications' 8import { NotificationsService } from 'angular2-notifications'
9import { Subscription } from 'rxjs' 9import { forkJoin, Subscription } from 'rxjs'
10import * as videojs from 'video.js' 10import * as videojs from 'video.js'
11import 'videojs-hotkeys' 11import 'videojs-hotkeys'
12import * as WebTorrent from 'webtorrent' 12import * as WebTorrent from 'webtorrent'
13import { UserVideoRateType, VideoPrivacy, VideoRateType, VideoState } from '../../../../../shared' 13import { ResultList, UserVideoRateType, VideoPrivacy, VideoRateType, VideoState } from '../../../../../shared'
14import '../../../assets/player/peertube-videojs-plugin' 14import '../../../assets/player/peertube-videojs-plugin'
15import { AuthService, ConfirmService } from '../../core' 15import { AuthService, ConfirmService } from '../../core'
16import { RestExtractor, VideoBlacklistService } from '../../shared' 16import { RestExtractor, VideoBlacklistService } from '../../shared'
@@ -26,6 +26,9 @@ import { ServerService } from '@app/core'
26import { I18n } from '@ngx-translate/i18n-polyfill' 26import { I18n } from '@ngx-translate/i18n-polyfill'
27import { environment } from '../../../environments/environment' 27import { environment } from '../../../environments/environment'
28import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' 28import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
29import { VideoCaptionService } from '@app/shared/video-caption'
30import { VideoCaption } from '../../../../../shared/models/videos/video-caption.model'
31import { VideoJSCaption } from '../../../assets/player/peertube-videojs-typings'
29 32
30@Component({ 33@Component({
31 selector: 'my-video-watch', 34 selector: 'my-video-watch',
@@ -74,6 +77,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
74 private markdownService: MarkdownService, 77 private markdownService: MarkdownService,
75 private zone: NgZone, 78 private zone: NgZone,
76 private redirectService: RedirectService, 79 private redirectService: RedirectService,
80 private videoCaptionService: VideoCaptionService,
77 private i18n: I18n, 81 private i18n: I18n,
78 @Inject(LOCALE_ID) private localeId: string 82 @Inject(LOCALE_ID) private localeId: string
79 ) {} 83 ) {}
@@ -109,14 +113,18 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
109 if (this.player) this.player.pause() 113 if (this.player) this.player.pause()
110 114
111 // Video did change 115 // Video did change
112 this.videoService 116 forkJoin(
113 .getVideo(uuid) 117 this.videoService.getVideo(uuid),
114 .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))) 118 this.videoCaptionService.listCaptions(uuid)
115 .subscribe(video => { 119 )
116 const startTime = this.route.snapshot.queryParams.start 120 .pipe(
117 this.onVideoFetched(video, startTime) 121 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))
118 .catch(err => this.handleError(err)) 122 )
119 }) 123 .subscribe(([ video, captionsResult ]) => {
124 const startTime = this.route.snapshot.queryParams.start
125 this.onVideoFetched(video, captionsResult.data, startTime)
126 .catch(err => this.handleError(err))
127 })
120 }) 128 })
121 } 129 }
122 130
@@ -331,7 +339,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
331 ) 339 )
332 } 340 }
333 341
334 private async onVideoFetched (video: VideoDetails, startTime = 0) { 342 private async onVideoFetched (video: VideoDetails, videoCaptions: VideoCaption[], startTime = 0) {
335 this.video = video 343 this.video = video
336 344
337 // Re init attributes 345 // Re init attributes
@@ -358,10 +366,17 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
358 this.playerElement.setAttribute('playsinline', 'true') 366 this.playerElement.setAttribute('playsinline', 'true')
359 playerElementWrapper.appendChild(this.playerElement) 367 playerElementWrapper.appendChild(this.playerElement)
360 368
369 const playerCaptions = videoCaptions.map(c => ({
370 label: c.language.label,
371 language: c.language.id,
372 src: environment.apiUrl + c.captionPath
373 }))
374
361 const videojsOptions = getVideojsOptions({ 375 const videojsOptions = getVideojsOptions({
362 autoplay: this.isAutoplay(), 376 autoplay: this.isAutoplay(),
363 inactivityTimeout: 2500, 377 inactivityTimeout: 2500,
364 videoFiles: this.video.files, 378 videoFiles: this.video.files,
379 videoCaptions: playerCaptions,
365 playerElement: this.playerElement, 380 playerElement: this.playerElement,
366 videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, 381 videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null,
367 videoDuration: this.video.duration, 382 videoDuration: this.video.duration,
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts
index baae740fe..bf02ce91c 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/assets/player/peertube-player.ts
@@ -11,12 +11,16 @@ import './webtorrent-info-button'
11import './peertube-videojs-plugin' 11import './peertube-videojs-plugin'
12import './peertube-load-progress-bar' 12import './peertube-load-progress-bar'
13import './theater-button' 13import './theater-button'
14import { videojsUntyped } from './peertube-videojs-typings' 14import { VideoJSCaption, videojsUntyped } from './peertube-videojs-typings'
15import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' 15import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
16import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' 16import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
17 17
18// Change 'Playback Rate' to 'Speed' (smaller for our settings menu) 18// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
19videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' 19videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
20// Change Captions to Subtitles/CC
21videojsUntyped.getComponent('CaptionsButton').prototype.controlText_ = 'Subtitles/CC'
22// We just want to display 'Off' instead of 'captions off', keep a space so the variable == true (hacky I know)
23videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' '
20 24
21function getVideojsOptions (options: { 25function getVideojsOptions (options: {
22 autoplay: boolean, 26 autoplay: boolean,
@@ -30,11 +34,14 @@ function getVideojsOptions (options: {
30 poster: string, 34 poster: string,
31 startTime: number 35 startTime: number
32 theaterMode: boolean, 36 theaterMode: boolean,
37 videoCaptions: VideoJSCaption[],
33 controls?: boolean, 38 controls?: boolean,
34 muted?: boolean, 39 muted?: boolean,
35 loop?: boolean 40 loop?: boolean
36}) { 41}) {
37 const videojsOptions = { 42 const videojsOptions = {
43 // We don't use text track settings for now
44 textTrackSettings: false,
38 controls: options.controls !== undefined ? options.controls : true, 45 controls: options.controls !== undefined ? options.controls : true,
39 muted: options.controls !== undefined ? options.muted : false, 46 muted: options.controls !== undefined ? options.muted : false,
40 loop: options.loop !== undefined ? options.loop : false, 47 loop: options.loop !== undefined ? options.loop : false,
@@ -45,6 +52,7 @@ function getVideojsOptions (options: {
45 plugins: { 52 plugins: {
46 peertube: { 53 peertube: {
47 autoplay: options.autoplay, // Use peertube plugin autoplay because we get the file by webtorrent 54 autoplay: options.autoplay, // Use peertube plugin autoplay because we get the file by webtorrent
55 videoCaptions: options.videoCaptions,
48 videoFiles: options.videoFiles, 56 videoFiles: options.videoFiles,
49 playerElement: options.playerElement, 57 playerElement: options.playerElement,
50 videoViewUrl: options.videoViewUrl, 58 videoViewUrl: options.videoViewUrl,
@@ -71,8 +79,16 @@ function getVideojsOptions (options: {
71 79
72function getControlBarChildren (options: { 80function getControlBarChildren (options: {
73 peertubeLink: boolean 81 peertubeLink: boolean
74 theaterMode: boolean 82 theaterMode: boolean,
83 videoCaptions: VideoJSCaption[]
75}) { 84}) {
85 const settingEntries = []
86
87 // Keep an order
88 settingEntries.push('playbackRateMenuButton')
89 if (options.videoCaptions.length !== 0) settingEntries.push('captionsButton')
90 settingEntries.push('resolutionMenuButton')
91
76 const children = { 92 const children = {
77 'playToggle': {}, 93 'playToggle': {},
78 'currentTimeDisplay': {}, 94 'currentTimeDisplay': {},
@@ -102,10 +118,7 @@ function getControlBarChildren (options: {
102 setup: { 118 setup: {
103 maxHeightOffset: 40 119 maxHeightOffset: 40
104 }, 120 },
105 entries: [ 121 entries: settingEntries
106 'resolutionMenuButton',
107 'playbackRateMenuButton'
108 ]
109 } 122 }
110 } 123 }
111 124
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts
index 57c894ee6..3f6fc4cc6 100644
--- a/client/src/assets/player/peertube-videojs-plugin.ts
+++ b/client/src/assets/player/peertube-videojs-plugin.ts
@@ -3,7 +3,7 @@ import * as WebTorrent from 'webtorrent'
3import { VideoFile } from '../../../../shared/models/videos/video.model' 3import { VideoFile } from '../../../../shared/models/videos/video.model'
4import { renderVideo } from './video-renderer' 4import { renderVideo } from './video-renderer'
5import './settings-menu-button' 5import './settings-menu-button'
6import { PeertubePluginOptions, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 6import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
7import { isMobile, videoFileMaxByResolution, videoFileMinByResolution } from './utils' 7import { isMobile, videoFileMaxByResolution, videoFileMinByResolution } from './utils'
8import * as CacheChunkStore from 'cache-chunk-store' 8import * as CacheChunkStore from 'cache-chunk-store'
9import { PeertubeChunkStore } from './peertube-chunk-store' 9import { PeertubeChunkStore } from './peertube-chunk-store'
@@ -54,6 +54,7 @@ class PeerTubePlugin extends Plugin {
54 private player: any 54 private player: any
55 private currentVideoFile: VideoFile 55 private currentVideoFile: VideoFile
56 private torrent: WebTorrent.Torrent 56 private torrent: WebTorrent.Torrent
57 private videoCaptions: VideoJSCaption[]
57 private renderer 58 private renderer
58 private fakeRenderer 59 private fakeRenderer
59 private autoResolution = true 60 private autoResolution = true
@@ -79,6 +80,7 @@ class PeerTubePlugin extends Plugin {
79 this.videoFiles = options.videoFiles 80 this.videoFiles = options.videoFiles
80 this.videoViewUrl = options.videoViewUrl 81 this.videoViewUrl = options.videoViewUrl
81 this.videoDuration = options.videoDuration 82 this.videoDuration = options.videoDuration
83 this.videoCaptions = options.videoCaptions
82 84
83 this.savePlayerSrcFunction = this.player.src 85 this.savePlayerSrcFunction = this.player.src
84 // Hack to "simulate" src link in video.js >= 6 86 // Hack to "simulate" src link in video.js >= 6
@@ -421,6 +423,8 @@ class PeerTubePlugin extends Plugin {
421 423
422 this.initSmoothProgressBar() 424 this.initSmoothProgressBar()
423 425
426 this.initCaptions()
427
424 this.alterInactivity() 428 this.alterInactivity()
425 429
426 if (this.autoplay === true) { 430 if (this.autoplay === true) {
@@ -581,7 +585,7 @@ class PeerTubePlugin extends Plugin {
581 this.player.options_.inactivityTimeout = 0 585 this.player.options_.inactivityTimeout = 0
582 } 586 }
583 const enableInactivity = () => { 587 const enableInactivity = () => {
584 this.player.options_.inactivityTimeout = saveInactivityTimeout 588 // this.player.options_.inactivityTimeout = saveInactivityTimeout
585 } 589 }
586 590
587 const settingsDialog = this.player.children_.find(c => c.name_ === 'SettingsDialog') 591 const settingsDialog = this.player.children_.find(c => c.name_ === 'SettingsDialog')
@@ -611,6 +615,18 @@ class PeerTubePlugin extends Plugin {
611 } 615 }
612 } 616 }
613 617
618 private initCaptions () {
619 for (const caption of this.videoCaptions) {
620 this.player.addRemoteTextTrack({
621 kind: 'captions',
622 label: caption.label,
623 language: caption.language,
624 id: caption.language,
625 src: caption.src
626 }, false)
627 }
628 }
629
614 // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657 630 // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657
615 private initSmoothProgressBar () { 631 private initSmoothProgressBar () {
616 const SeekBar = videojsUntyped.getComponent('SeekBar') 632 const SeekBar = videojsUntyped.getComponent('SeekBar')
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts
index 50d6039ea..9c0299237 100644
--- a/client/src/assets/player/peertube-videojs-typings.ts
+++ b/client/src/assets/player/peertube-videojs-typings.ts
@@ -16,13 +16,20 @@ interface VideoJSComponentInterface {
16 registerComponent (name: string, obj: any) 16 registerComponent (name: string, obj: any)
17} 17}
18 18
19type VideoJSCaption = {
20 label: string
21 language: string
22 src: string
23}
24
19type PeertubePluginOptions = { 25type PeertubePluginOptions = {
20 videoFiles: VideoFile[] 26 videoFiles: VideoFile[]
21 playerElement: HTMLVideoElement 27 playerElement: HTMLVideoElement
22 videoViewUrl: string 28 videoViewUrl: string
23 videoDuration: number 29 videoDuration: number
24 startTime: number 30 startTime: number
25 autoplay: boolean 31 autoplay: boolean,
32 videoCaptions: VideoJSCaption[]
26} 33}
27 34
28// videojs typings don't have some method we need 35// videojs typings don't have some method we need
@@ -31,5 +38,6 @@ const videojsUntyped = videojs as any
31export { 38export {
32 VideoJSComponentInterface, 39 VideoJSComponentInterface,
33 PeertubePluginOptions, 40 PeertubePluginOptions,
34 videojsUntyped 41 videojsUntyped,
42 VideoJSCaption
35} 43}
diff --git a/client/src/assets/player/settings-menu-item.ts b/client/src/assets/player/settings-menu-item.ts
index 88985e1ae..6e2224e20 100644
--- a/client/src/assets/player/settings-menu-item.ts
+++ b/client/src/assets/player/settings-menu-item.ts
@@ -32,6 +32,8 @@ class SettingsMenuItem extends MenuItem {
32 throw new Error(`Component ${subMenuName} does not exist`) 32 throw new Error(`Component ${subMenuName} does not exist`)
33 } 33 }
34 this.subMenu = new SubMenuComponent(this.player(), options, menuButton, this) 34 this.subMenu = new SubMenuComponent(this.player(), options, menuButton, this)
35 const subMenuClass = this.subMenu.buildCSSClass().split(' ')[0]
36 this.settingsSubMenuEl_.className += ' ' + subMenuClass
35 37
36 this.eventHandlers() 38 this.eventHandlers()
37 39
diff --git a/client/src/sass/player/settings-menu.scss b/client/src/sass/player/settings-menu.scss
index 0c064c182..d065e72fb 100644
--- a/client/src/sass/player/settings-menu.scss
+++ b/client/src/sass/player/settings-menu.scss
@@ -52,6 +52,7 @@ $setting-transition-easing: ease-out;
52 .vjs-settings-sub-menu-title { 52 .vjs-settings-sub-menu-title {
53 display: table-cell; 53 display: table-cell;
54 padding: 0 5px; 54 padding: 0 5px;
55 text-transform: capitalize;
55 } 56 }
56 57
57 .vjs-settings-sub-menu-title { 58 .vjs-settings-sub-menu-title {
@@ -141,15 +142,15 @@ $setting-transition-easing: ease-out;
141 .vjs-menu-item { 142 .vjs-menu-item {
142 outline: 0; 143 outline: 0;
143 font-weight: $font-semibold; 144 font-weight: $font-semibold;
144
145 padding: 5px 8px;
146 text-align: right; 145 text-align: right;
146 padding: 5px 8px;
147 147
148 &.vjs-back-button { 148 &.vjs-back-button {
149 background-color: inherit; 149 background-color: inherit;
150 padding: 8px 8px 13px 8px; 150 padding: 8px 8px 13px 12px;
151 margin-bottom: 5px; 151 margin-bottom: 5px;
152 border-bottom: 1px solid grey; 152 border-bottom: 1px solid grey;
153 text-align: left;
153 154
154 &::before { 155 &::before {
155 @include chevron-left(9px, 2px); 156 @include chevron-left(9px, 2px);
@@ -174,6 +175,25 @@ $setting-transition-easing: ease-out;
174 } 175 }
175 } 176 }
176 } 177 }
178
179 // Special captions case
180 // Bigger caption button
181 &.vjs-captions-button {
182 width: 200px;
183
184 .vjs-menu-item {
185 text-align: left;
186
187 .vjs-menu-item-text {
188 margin-left: 25px;
189 text-transform: capitalize;
190 }
191 }
192 }
193
194 .vjs-menu {
195 width: inherit;
196 }
177 } 197 }
178 } 198 }
179 } 199 }
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index a4196600a..1275998b8 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -20,9 +20,11 @@ import 'whatwg-fetch'
20import * as vjs from 'video.js' 20import * as vjs from 'video.js'
21import * as Channel from 'jschannel' 21import * as Channel from 'jschannel'
22 22
23import { VideoDetails } from '../../../../shared' 23import { ResultList, VideoDetails } from '../../../../shared'
24import { addContextMenu, getVideojsOptions, loadLocale } from '../../assets/player/peertube-player' 24import { addContextMenu, getVideojsOptions, loadLocale } from '../../assets/player/peertube-player'
25import { PeerTubeResolution } from '../player/definitions' 25import { PeerTubeResolution } from '../player/definitions'
26import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
27import { VideoCaption } from '../../../../shared/models/videos/video-caption.model'
26 28
27/** 29/**
28 * Embed API exposes control of the embed player to the outside world via 30 * Embed API exposes control of the embed player to the outside world via
@@ -178,6 +180,10 @@ class PeerTubeEmbed {
178 return fetch(this.getVideoUrl(videoId)) 180 return fetch(this.getVideoUrl(videoId))
179 } 181 }
180 182
183 loadVideoCaptions (videoId: string): Promise<Response> {
184 return fetch(this.getVideoUrl(videoId) + '/captions')
185 }
186
181 removeElement (element: HTMLElement) { 187 removeElement (element: HTMLElement) {
182 element.parentElement.removeChild(element) 188 element.parentElement.removeChild(element)
183 } 189 }
@@ -254,15 +260,27 @@ class PeerTubeEmbed {
254 const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ] 260 const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ]
255 261
256 await loadLocale(window.location.origin, vjs, navigator.language) 262 await loadLocale(window.location.origin, vjs, navigator.language)
257 let response = await this.loadVideoInfo(videoId) 263 const [ videoResponse, captionsResponse ] = await Promise.all([
264 this.loadVideoInfo(videoId),
265 this.loadVideoCaptions(videoId)
266 ])
258 267
259 if (!response.ok) { 268 if (!videoResponse.ok) {
260 if (response.status === 404) return this.videoNotFound(this.videoElement) 269 if (videoResponse.status === 404) return this.videoNotFound(this.videoElement)
261 270
262 return this.videoFetchError(this.videoElement) 271 return this.videoFetchError(this.videoElement)
263 } 272 }
264 273
265 const videoInfo: VideoDetails = await response.json() 274 const videoInfo: VideoDetails = await videoResponse.json()
275 let videoCaptions: VideoJSCaption[] = []
276 if (captionsResponse.ok) {
277 const { data } = (await captionsResponse.json()) as ResultList<VideoCaption>
278 videoCaptions = data.map(c => ({
279 label: c.language.label,
280 language: c.language.id,
281 src: window.location.origin + c.captionPath
282 }))
283 }
266 284
267 this.loadParams() 285 this.loadParams()
268 286
@@ -273,6 +291,7 @@ class PeerTubeEmbed {
273 loop: this.loop, 291 loop: this.loop,
274 startTime: this.startTime, 292 startTime: this.startTime,
275 293
294 videoCaptions,
276 inactivityTimeout: 1500, 295 inactivityTimeout: 1500,
277 videoViewUrl: this.getVideoUrl(videoId) + '/views', 296 videoViewUrl: this.getVideoUrl(videoId) + '/views',
278 playerElement: this.videoElement, 297 playerElement: this.videoElement,
@@ -297,6 +316,7 @@ class PeerTubeEmbed {
297 } 316 }
298 317
299 addContextMenu(this.player, window.location.origin + videoInfo.embedPath) 318 addContextMenu(this.player, window.location.origin + videoInfo.embedPath)
319
300 this.initializeApi() 320 this.initializeApi()
301 }) 321 })
302 } 322 }