diff options
author | Chocobozzz <me@florianbigard.com> | 2018-07-13 18:21:19 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-07-16 11:50:08 +0200 |
commit | 16f7022b06fb76c0b00c23c970bc8df605b0ec63 (patch) | |
tree | 0677c72b449485dcaa87ee2b470dfb1a8124b9e0 /client/src/assets/player | |
parent | 40e87e9ecc54e3513fb586928330a7855eb192c6 (diff) | |
download | PeerTube-16f7022b06fb76c0b00c23c970bc8df605b0ec63.tar.gz PeerTube-16f7022b06fb76c0b00c23c970bc8df605b0ec63.tar.zst PeerTube-16f7022b06fb76c0b00c23c970bc8df605b0ec63.zip |
Handle subtitles in player
Diffstat (limited to 'client/src/assets/player')
-rw-r--r-- | client/src/assets/player/peertube-player.ts | 25 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-plugin.ts | 20 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-typings.ts | 12 | ||||
-rw-r--r-- | client/src/assets/player/settings-menu-item.ts | 2 |
4 files changed, 49 insertions, 10 deletions
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' | |||
11 | import './peertube-videojs-plugin' | 11 | import './peertube-videojs-plugin' |
12 | import './peertube-load-progress-bar' | 12 | import './peertube-load-progress-bar' |
13 | import './theater-button' | 13 | import './theater-button' |
14 | import { videojsUntyped } from './peertube-videojs-typings' | 14 | import { VideoJSCaption, videojsUntyped } from './peertube-videojs-typings' |
15 | import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' | 15 | import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' |
16 | import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' | 16 | import { 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) |
19 | videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' | 19 | videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' |
20 | // Change Captions to Subtitles/CC | ||
21 | videojsUntyped.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) | ||
23 | videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' ' | ||
20 | 24 | ||
21 | function getVideojsOptions (options: { | 25 | function 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 | ||
72 | function getControlBarChildren (options: { | 80 | function 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' | |||
3 | import { VideoFile } from '../../../../shared/models/videos/video.model' | 3 | import { VideoFile } from '../../../../shared/models/videos/video.model' |
4 | import { renderVideo } from './video-renderer' | 4 | import { renderVideo } from './video-renderer' |
5 | import './settings-menu-button' | 5 | import './settings-menu-button' |
6 | import { PeertubePluginOptions, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 6 | import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
7 | import { isMobile, videoFileMaxByResolution, videoFileMinByResolution } from './utils' | 7 | import { isMobile, videoFileMaxByResolution, videoFileMinByResolution } from './utils' |
8 | import * as CacheChunkStore from 'cache-chunk-store' | 8 | import * as CacheChunkStore from 'cache-chunk-store' |
9 | import { PeertubeChunkStore } from './peertube-chunk-store' | 9 | import { 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 | ||
19 | type VideoJSCaption = { | ||
20 | label: string | ||
21 | language: string | ||
22 | src: string | ||
23 | } | ||
24 | |||
19 | type PeertubePluginOptions = { | 25 | type 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 | |||
31 | export { | 38 | export { |
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 | ||