diff options
Diffstat (limited to 'client/src/assets/player')
-rw-r--r-- | client/src/assets/player/peertube-player-local-storage.ts | 12 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player.ts | 44 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-plugin.ts | 49 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-typings.ts | 1 | ||||
-rw-r--r-- | client/src/assets/player/settings-menu-item.ts | 13 | ||||
-rw-r--r-- | client/src/assets/player/utils.ts | 1 |
6 files changed, 92 insertions, 28 deletions
diff --git a/client/src/assets/player/peertube-player-local-storage.ts b/client/src/assets/player/peertube-player-local-storage.ts index 7e3813570..059fca308 100644 --- a/client/src/assets/player/peertube-player-local-storage.ts +++ b/client/src/assets/player/peertube-player-local-storage.ts | |||
@@ -60,6 +60,14 @@ function getAverageBandwidthInStore () { | |||
60 | return undefined | 60 | return undefined |
61 | } | 61 | } |
62 | 62 | ||
63 | function saveLastSubtitle (language: string) { | ||
64 | return setLocalStorage('last-subtitle', language) | ||
65 | } | ||
66 | |||
67 | function getStoredLastSubtitle () { | ||
68 | return getLocalStorage('last-subtitle') | ||
69 | } | ||
70 | |||
63 | // --------------------------------------------------------------------------- | 71 | // --------------------------------------------------------------------------- |
64 | 72 | ||
65 | export { | 73 | export { |
@@ -71,7 +79,9 @@ export { | |||
71 | saveMuteInStore, | 79 | saveMuteInStore, |
72 | saveTheaterInStore, | 80 | saveTheaterInStore, |
73 | saveAverageBandwidth, | 81 | saveAverageBandwidth, |
74 | getAverageBandwidthInStore | 82 | getAverageBandwidthInStore, |
83 | saveLastSubtitle, | ||
84 | getStoredLastSubtitle | ||
75 | } | 85 | } |
76 | 86 | ||
77 | // --------------------------------------------------------------------------- | 87 | // --------------------------------------------------------------------------- |
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts index aaa1170b6..2de6d7fef 100644 --- a/client/src/assets/player/peertube-player.ts +++ b/client/src/assets/player/peertube-player.ts | |||
@@ -26,23 +26,24 @@ videojsUntyped.getComponent('CaptionsButton').prototype.controlText_ = 'Subtitle | |||
26 | videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' ' | 26 | videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' ' |
27 | 27 | ||
28 | function getVideojsOptions (options: { | 28 | function getVideojsOptions (options: { |
29 | autoplay: boolean, | 29 | autoplay: boolean |
30 | playerElement: HTMLVideoElement, | 30 | playerElement: HTMLVideoElement |
31 | videoViewUrl: string, | 31 | videoViewUrl: string |
32 | videoDuration: number, | 32 | videoDuration: number |
33 | videoFiles: VideoFile[], | 33 | videoFiles: VideoFile[] |
34 | enableHotkeys: boolean, | 34 | enableHotkeys: boolean |
35 | inactivityTimeout: number, | 35 | inactivityTimeout: number |
36 | peertubeLink: boolean, | 36 | peertubeLink: boolean |
37 | poster: string, | 37 | poster: string |
38 | startTime: number | string | 38 | startTime: number | string |
39 | theaterMode: boolean, | 39 | theaterMode: boolean |
40 | videoCaptions: VideoJSCaption[], | 40 | videoCaptions: VideoJSCaption[] |
41 | 41 | ||
42 | language?: string, | 42 | language?: string |
43 | controls?: boolean, | 43 | controls?: boolean |
44 | muted?: boolean, | 44 | muted?: boolean |
45 | loop?: boolean | 45 | loop?: boolean |
46 | subtitle?: string | ||
46 | 47 | ||
47 | userWatching?: UserWatching | 48 | userWatching?: UserWatching |
48 | }) { | 49 | }) { |
@@ -50,8 +51,10 @@ function getVideojsOptions (options: { | |||
50 | // We don't use text track settings for now | 51 | // We don't use text track settings for now |
51 | textTrackSettings: false, | 52 | textTrackSettings: false, |
52 | controls: options.controls !== undefined ? options.controls : true, | 53 | controls: options.controls !== undefined ? options.controls : true, |
53 | muted: options.controls !== undefined ? options.muted : false, | ||
54 | loop: options.loop !== undefined ? options.loop : false, | 54 | loop: options.loop !== undefined ? options.loop : false, |
55 | |||
56 | muted: options.muted !== undefined ? options.muted : undefined, // Undefined so the player knows it has to check the local storage | ||
57 | |||
55 | poster: options.poster, | 58 | poster: options.poster, |
56 | autoplay: false, | 59 | autoplay: false, |
57 | inactivityTimeout: options.inactivityTimeout, | 60 | inactivityTimeout: options.inactivityTimeout, |
@@ -65,7 +68,8 @@ function getVideojsOptions (options: { | |||
65 | videoViewUrl: options.videoViewUrl, | 68 | videoViewUrl: options.videoViewUrl, |
66 | videoDuration: options.videoDuration, | 69 | videoDuration: options.videoDuration, |
67 | startTime: options.startTime, | 70 | startTime: options.startTime, |
68 | userWatching: options.userWatching | 71 | userWatching: options.userWatching, |
72 | subtitle: options.subtitle | ||
69 | } | 73 | } |
70 | }, | 74 | }, |
71 | controlBar: { | 75 | controlBar: { |
@@ -250,6 +254,10 @@ function loadLocaleInVideoJS (serverUrl: string, videojs: any, locale: string) { | |||
250 | loadLocaleInVideoJS.cache[path] = json | 254 | loadLocaleInVideoJS.cache[path] = json |
251 | return json | 255 | return json |
252 | }) | 256 | }) |
257 | .catch(err => { | ||
258 | console.error('Cannot get player translations', err) | ||
259 | return undefined | ||
260 | }) | ||
253 | } | 261 | } |
254 | 262 | ||
255 | const completeLocale = getCompleteLocale(locale) | 263 | const completeLocale = getCompleteLocale(locale) |
@@ -266,6 +274,10 @@ function getServerTranslations (serverUrl: string, locale: string) { | |||
266 | 274 | ||
267 | return fetch(path + '/server.json') | 275 | return fetch(path + '/server.json') |
268 | .then(res => res.json()) | 276 | .then(res => res.json()) |
277 | .catch(err => { | ||
278 | console.error('Cannot get server translations', err) | ||
279 | return undefined | ||
280 | }) | ||
269 | } | 281 | } |
270 | 282 | ||
271 | // ############################################################################ | 283 | // ############################################################################ |
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts index 4fd5a9be2..e9fb90c61 100644 --- a/client/src/assets/player/peertube-videojs-plugin.ts +++ b/client/src/assets/player/peertube-videojs-plugin.ts | |||
@@ -11,10 +11,12 @@ import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution | |||
11 | import { PeertubeChunkStore } from './peertube-chunk-store' | 11 | import { PeertubeChunkStore } from './peertube-chunk-store' |
12 | import { | 12 | import { |
13 | getAverageBandwidthInStore, | 13 | getAverageBandwidthInStore, |
14 | getStoredLastSubtitle, | ||
14 | getStoredMute, | 15 | getStoredMute, |
15 | getStoredVolume, | 16 | getStoredVolume, |
16 | getStoredWebTorrentEnabled, | 17 | getStoredWebTorrentEnabled, |
17 | saveAverageBandwidth, | 18 | saveAverageBandwidth, |
19 | saveLastSubtitle, | ||
18 | saveMuteInStore, | 20 | saveMuteInStore, |
19 | saveVolumeInStore | 21 | saveVolumeInStore |
20 | } from './peertube-player-local-storage' | 22 | } from './peertube-player-local-storage' |
@@ -67,10 +69,11 @@ class PeerTubePlugin extends Plugin { | |||
67 | private currentVideoFile: VideoFile | 69 | private currentVideoFile: VideoFile |
68 | private torrent: WebTorrent.Torrent | 70 | private torrent: WebTorrent.Torrent |
69 | private videoCaptions: VideoJSCaption[] | 71 | private videoCaptions: VideoJSCaption[] |
72 | private defaultSubtitle: string | ||
70 | 73 | ||
71 | private renderer: any | 74 | private renderer: any |
72 | private fakeRenderer: any | 75 | private fakeRenderer: any |
73 | private destoyingFakeRenderer = false | 76 | private destroyingFakeRenderer = false |
74 | 77 | ||
75 | private autoResolution = true | 78 | private autoResolution = true |
76 | private forbidAutoResolution = false | 79 | private forbidAutoResolution = false |
@@ -106,11 +109,34 @@ class PeerTubePlugin extends Plugin { | |||
106 | if (this.autoplay === true) this.player.addClass('vjs-has-autoplay') | 109 | if (this.autoplay === true) this.player.addClass('vjs-has-autoplay') |
107 | 110 | ||
108 | this.player.ready(() => { | 111 | this.player.ready(() => { |
112 | const playerOptions = this.player.options_ | ||
113 | |||
109 | const volume = getStoredVolume() | 114 | const volume = getStoredVolume() |
110 | if (volume !== undefined) this.player.volume(volume) | 115 | if (volume !== undefined) this.player.volume(volume) |
111 | const muted = getStoredMute() | 116 | |
117 | const muted = playerOptions.muted !== undefined ? playerOptions.muted : getStoredMute() | ||
112 | if (muted !== undefined) this.player.muted(muted) | 118 | if (muted !== undefined) this.player.muted(muted) |
113 | 119 | ||
120 | this.defaultSubtitle = options.subtitle || getStoredLastSubtitle() | ||
121 | |||
122 | this.player.on('volumechange', () => { | ||
123 | saveVolumeInStore(this.player.volume()) | ||
124 | saveMuteInStore(this.player.muted()) | ||
125 | }) | ||
126 | |||
127 | this.player.textTracks().on('change', () => { | ||
128 | const showing = this.player.textTracks().tracks_.find((t: { kind: string, mode: string }) => { | ||
129 | return t.kind === 'captions' && t.mode === 'showing' | ||
130 | }) | ||
131 | |||
132 | if (!showing) { | ||
133 | saveLastSubtitle('off') | ||
134 | return | ||
135 | } | ||
136 | |||
137 | saveLastSubtitle(showing.language) | ||
138 | }) | ||
139 | |||
114 | this.player.duration(options.videoDuration) | 140 | this.player.duration(options.videoDuration) |
115 | 141 | ||
116 | this.initializePlayer() | 142 | this.initializePlayer() |
@@ -124,11 +150,6 @@ class PeerTubePlugin extends Plugin { | |||
124 | this.runAutoQualitySchedulerTimer = setTimeout(() => this.runAutoQualityScheduler(), this.CONSTANTS.AUTO_QUALITY_SCHEDULER) | 150 | this.runAutoQualitySchedulerTimer = setTimeout(() => this.runAutoQualityScheduler(), this.CONSTANTS.AUTO_QUALITY_SCHEDULER) |
125 | }) | 151 | }) |
126 | }) | 152 | }) |
127 | |||
128 | this.player.on('volumechange', () => { | ||
129 | saveVolumeInStore(this.player.volume()) | ||
130 | saveMuteInStore(this.player.muted()) | ||
131 | }) | ||
132 | } | 153 | } |
133 | 154 | ||
134 | dispose () { | 155 | dispose () { |
@@ -599,6 +620,9 @@ class PeerTubePlugin extends Plugin { | |||
599 | this.player.src = this.savePlayerSrcFunction | 620 | this.player.src = this.savePlayerSrcFunction |
600 | this.player.src(httpUrl) | 621 | this.player.src(httpUrl) |
601 | 622 | ||
623 | // We changed the source, so reinit captions | ||
624 | this.initCaptions() | ||
625 | |||
602 | return this.tryToPlay(err => { | 626 | return this.tryToPlay(err => { |
603 | if (err && done) return done(err) | 627 | if (err && done) return done(err) |
604 | 628 | ||
@@ -657,14 +681,14 @@ class PeerTubePlugin extends Plugin { | |||
657 | } | 681 | } |
658 | 682 | ||
659 | private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { | 683 | private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { |
660 | this.destoyingFakeRenderer = false | 684 | this.destroyingFakeRenderer = false |
661 | 685 | ||
662 | const fakeVideoElem = document.createElement('video') | 686 | const fakeVideoElem = document.createElement('video') |
663 | renderVideo(file, fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => { | 687 | renderVideo(file, fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => { |
664 | this.fakeRenderer = renderer | 688 | this.fakeRenderer = renderer |
665 | 689 | ||
666 | // The renderer returns an error when we destroy it, so skip them | 690 | // The renderer returns an error when we destroy it, so skip them |
667 | if (this.destoyingFakeRenderer === false && err) { | 691 | if (this.destroyingFakeRenderer === false && err) { |
668 | console.error('Cannot render new torrent in fake video element.', err) | 692 | console.error('Cannot render new torrent in fake video element.', err) |
669 | } | 693 | } |
670 | 694 | ||
@@ -675,7 +699,7 @@ class PeerTubePlugin extends Plugin { | |||
675 | 699 | ||
676 | private destroyFakeRenderer () { | 700 | private destroyFakeRenderer () { |
677 | if (this.fakeRenderer) { | 701 | if (this.fakeRenderer) { |
678 | this.destoyingFakeRenderer = true | 702 | this.destroyingFakeRenderer = true |
679 | 703 | ||
680 | if (this.fakeRenderer.destroy) { | 704 | if (this.fakeRenderer.destroy) { |
681 | try { | 705 | try { |
@@ -695,9 +719,12 @@ class PeerTubePlugin extends Plugin { | |||
695 | label: caption.label, | 719 | label: caption.label, |
696 | language: caption.language, | 720 | language: caption.language, |
697 | id: caption.language, | 721 | id: caption.language, |
698 | src: caption.src | 722 | src: caption.src, |
723 | default: this.defaultSubtitle === caption.language | ||
699 | }, false) | 724 | }, false) |
700 | } | 725 | } |
726 | |||
727 | this.player.trigger('captionsChanged') | ||
701 | } | 728 | } |
702 | 729 | ||
703 | // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657 | 730 | // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657 |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index d127230fa..634c7fdc9 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -39,6 +39,7 @@ type PeertubePluginOptions = { | |||
39 | autoplay: boolean, | 39 | autoplay: boolean, |
40 | videoCaptions: VideoJSCaption[] | 40 | videoCaptions: VideoJSCaption[] |
41 | 41 | ||
42 | subtitle?: string | ||
42 | userWatching?: UserWatching | 43 | userWatching?: UserWatching |
43 | } | 44 | } |
44 | 45 | ||
diff --git a/client/src/assets/player/settings-menu-item.ts b/client/src/assets/player/settings-menu-item.ts index 698f4627a..2a3460ae5 100644 --- a/client/src/assets/player/settings-menu-item.ts +++ b/client/src/assets/player/settings-menu-item.ts | |||
@@ -48,6 +48,19 @@ class SettingsMenuItem extends MenuItem { | |||
48 | // Update on rate change | 48 | // Update on rate change |
49 | player.on('ratechange', this.submenuClickHandler) | 49 | player.on('ratechange', this.submenuClickHandler) |
50 | 50 | ||
51 | if (subMenuName === 'CaptionsButton') { | ||
52 | // Hack to regenerate captions on HTTP fallback | ||
53 | player.on('captionsChanged', () => { | ||
54 | setTimeout(() => { | ||
55 | this.settingsSubMenuEl_.innerHTML = '' | ||
56 | this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_) | ||
57 | this.update() | ||
58 | this.bindClickEvents() | ||
59 | |||
60 | }, 0) | ||
61 | }) | ||
62 | } | ||
63 | |||
51 | this.reset() | 64 | this.reset() |
52 | }, 0) | 65 | }, 0) |
53 | }) | 66 | }) |
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index c87287482..8b9f34b99 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -39,6 +39,7 @@ function buildVideoLink (time?: number, url?: string) { | |||
39 | } | 39 | } |
40 | 40 | ||
41 | function timeToInt (time: number | string) { | 41 | function timeToInt (time: number | string) { |
42 | if (!time) return 0 | ||
42 | if (typeof time === 'number') return time | 43 | if (typeof time === 'number') return time |
43 | 44 | ||
44 | const reg = /^((\d+)h)?((\d+)m)?((\d+)s?)?$/ | 45 | const reg = /^((\d+)h)?((\d+)m)?((\d+)s?)?$/ |