aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-12-17 11:20:24 +0100
committerChocobozzz <me@florianbigard.com>2019-12-18 10:14:22 +0100
commit3f9c4955af81702591a6eeb2069f99faf0d2814d (patch)
tree8f23b5e79bde4a46dbc2318c0500576c35712486 /client/src
parentf88ee4a9523bf3c4a61a45832963c558aed4d0b1 (diff)
downloadPeerTube-3f9c4955af81702591a6eeb2069f99faf0d2814d.tar.gz
PeerTube-3f9c4955af81702591a6eeb2069f99faf0d2814d.tar.zst
PeerTube-3f9c4955af81702591a6eeb2069f99faf0d2814d.zip
Speedup embed first paint
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment-add.component.ts8
-rw-r--r--client/src/assets/player/peertube-player-manager.ts54
-rw-r--r--client/src/assets/player/translations-manager.ts52
-rw-r--r--client/src/standalone/videos/embed-api.ts1
-rw-r--r--client/src/standalone/videos/embed.html2
-rw-r--r--client/src/standalone/videos/embed.scss10
-rw-r--r--client/src/standalone/videos/embed.ts54
7 files changed, 116 insertions, 65 deletions
diff --git a/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts b/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
index 083509b83..1be96ad9e 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
@@ -137,6 +137,10 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
137 this.router.navigate([ '/login' ]) 137 this.router.navigate([ '/login' ])
138 } 138 }
139 139
140 cancelCommentReply () {
141 this.cancel.emit(null)
142 }
143
140 private addCommentReply (commentCreate: VideoCommentCreate) { 144 private addCommentReply (commentCreate: VideoCommentCreate) {
141 return this.videoCommentService 145 return this.videoCommentService
142 .addCommentReply(this.video.id, this.parentComment.id, commentCreate) 146 .addCommentReply(this.video.id, this.parentComment.id, commentCreate)
@@ -146,8 +150,4 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
146 return this.videoCommentService 150 return this.videoCommentService
147 .addCommentThread(this.video.id, commentCreate) 151 .addCommentThread(this.video.id, commentCreate)
148 } 152 }
149
150 private cancelCommentReply () {
151 this.cancel.emit(null)
152 }
153} 153}
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts
index 2f4e0ac1a..b1551185a 100644
--- a/client/src/assets/player/peertube-player-manager.ts
+++ b/client/src/assets/player/peertube-player-manager.ts
@@ -15,11 +15,12 @@ import './videojs-components/peertube-load-progress-bar'
15import './videojs-components/theater-button' 15import './videojs-components/theater-button'
16import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions, videojsUntyped } from './peertube-videojs-typings' 16import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions, videojsUntyped } from './peertube-videojs-typings'
17import { buildVideoEmbed, buildVideoLink, copyToClipboard, getRtcConfig } from './utils' 17import { buildVideoEmbed, buildVideoLink, copyToClipboard, getRtcConfig } from './utils'
18import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' 18import { isDefaultLocale } from '../../../../shared/models/i18n/i18n'
19import { segmentValidatorFactory } from './p2p-media-loader/segment-validator' 19import { segmentValidatorFactory } from './p2p-media-loader/segment-validator'
20import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder' 20import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder'
21import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' 21import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
22import { getStoredP2PEnabled } from './peertube-player-local-storage' 22import { getStoredP2PEnabled } from './peertube-player-local-storage'
23import { TranslationsManager } from './translations-manager'
23 24
24// Change 'Playback Rate' to 'Speed' (smaller for our settings menu) 25// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
25videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' 26videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
@@ -86,24 +87,9 @@ export type PeertubePlayerManagerOptions = {
86} 87}
87 88
88export class PeertubePlayerManager { 89export class PeertubePlayerManager {
89
90 private static videojsLocaleCache: { [ path: string ]: any } = {}
91 private static playerElementClassName: string 90 private static playerElementClassName: string
92 private static onPlayerChange: (player: any) => void 91 private static onPlayerChange: (player: any) => void
93 92
94 static getServerTranslations (serverUrl: string, locale: string) {
95 const path = PeertubePlayerManager.getLocalePath(serverUrl, locale)
96 // It is the default locale, nothing to translate
97 if (!path) return Promise.resolve(undefined)
98
99 return fetch(path + '/server.json')
100 .then(res => res.json())
101 .catch(err => {
102 console.error('Cannot get server translations', err)
103 return undefined
104 })
105 }
106
107 static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions, onPlayerChange: (player: any) => void) { 93 static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions, onPlayerChange: (player: any) => void) {
108 let p2pMediaLoader: any 94 let p2pMediaLoader: any
109 95
@@ -120,7 +106,7 @@ export class PeertubePlayerManager {
120 106
121 const videojsOptions = this.getVideojsOptions(mode, options, p2pMediaLoader) 107 const videojsOptions = this.getVideojsOptions(mode, options, p2pMediaLoader)
122 108
123 await this.loadLocaleInVideoJS(options.common.serverUrl, options.common.language) 109 await TranslationsManager.loadLocaleInVideoJS(options.common.serverUrl, options.common.language, videojs)
124 110
125 const self = this 111 const self = this
126 return new Promise(res => { 112 return new Promise(res => {
@@ -181,32 +167,6 @@ export class PeertubePlayerManager {
181 }) 167 })
182 } 168 }
183 169
184 private static loadLocaleInVideoJS (serverUrl: string, locale: string) {
185 const path = PeertubePlayerManager.getLocalePath(serverUrl, locale)
186 // It is the default locale, nothing to translate
187 if (!path) return Promise.resolve(undefined)
188
189 let p: Promise<any>
190
191 if (PeertubePlayerManager.videojsLocaleCache[path]) {
192 p = Promise.resolve(PeertubePlayerManager.videojsLocaleCache[path])
193 } else {
194 p = fetch(path + '/player.json')
195 .then(res => res.json())
196 .then(json => {
197 PeertubePlayerManager.videojsLocaleCache[path] = json
198 return json
199 })
200 .catch(err => {
201 console.error('Cannot get player translations', err)
202 return undefined
203 })
204 }
205
206 const completeLocale = getCompleteLocale(locale)
207 return p.then(json => videojs.addLanguage(getShortLocale(completeLocale), json))
208 }
209
210 private static getVideojsOptions (mode: PlayerMode, options: PeertubePlayerManagerOptions, p2pMediaLoaderModule?: any) { 170 private static getVideojsOptions (mode: PlayerMode, options: PeertubePlayerManagerOptions, p2pMediaLoaderModule?: any) {
211 const commonOptions = options.common 171 const commonOptions = options.common
212 172
@@ -519,14 +479,6 @@ export class PeertubePlayerManager {
519 } 479 }
520 }) 480 })
521 } 481 }
522
523 private static getLocalePath (serverUrl: string, locale: string) {
524 const completeLocale = getCompleteLocale(locale)
525
526 if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return undefined
527
528 return serverUrl + '/client/locales/' + completeLocale
529 }
530} 482}
531 483
532// ############################################################################ 484// ############################################################################
diff --git a/client/src/assets/player/translations-manager.ts b/client/src/assets/player/translations-manager.ts
new file mode 100644
index 000000000..e9f300ce7
--- /dev/null
+++ b/client/src/assets/player/translations-manager.ts
@@ -0,0 +1,52 @@
1import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models'
2
3export class TranslationsManager {
4 private static videojsLocaleCache: { [ path: string ]: any } = {}
5
6 static getServerTranslations (serverUrl: string, locale: string) {
7 const path = TranslationsManager.getLocalePath(serverUrl, locale)
8 // It is the default locale, nothing to translate
9 if (!path) return Promise.resolve(undefined)
10
11 return fetch(path + '/server.json')
12 .then(res => res.json())
13 .catch(err => {
14 console.error('Cannot get server translations', err)
15 return undefined
16 })
17 }
18
19 static loadLocaleInVideoJS (serverUrl: string, locale: string, videojs: any) {
20 const path = TranslationsManager.getLocalePath(serverUrl, locale)
21 // It is the default locale, nothing to translate
22 if (!path) return Promise.resolve(undefined)
23
24 let p: Promise<any>
25
26 if (TranslationsManager.videojsLocaleCache[ path ]) {
27 p = Promise.resolve(TranslationsManager.videojsLocaleCache[ path ])
28 } else {
29 p = fetch(path + '/player.json')
30 .then(res => res.json())
31 .then(json => {
32 TranslationsManager.videojsLocaleCache[ path ] = json
33 return json
34 })
35 .catch(err => {
36 console.error('Cannot get player translations', err)
37 return undefined
38 })
39 }
40
41 const completeLocale = getCompleteLocale(locale)
42 return p.then(json => videojs.addLanguage(getShortLocale(completeLocale), json))
43 }
44
45 private static getLocalePath (serverUrl: string, locale: string) {
46 const completeLocale = getCompleteLocale(locale)
47
48 if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return undefined
49
50 return serverUrl + '/client/locales/' + completeLocale
51 }
52}
diff --git a/client/src/standalone/videos/embed-api.ts b/client/src/standalone/videos/embed-api.ts
index 169e371da..259113215 100644
--- a/client/src/standalone/videos/embed-api.ts
+++ b/client/src/standalone/videos/embed-api.ts
@@ -43,7 +43,6 @@ export class PeerTubeEmbedApi {
43 channel.bind('setPlaybackRate', (txn, playbackRate) => this.embed.player.playbackRate(playbackRate)) 43 channel.bind('setPlaybackRate', (txn, playbackRate) => this.embed.player.playbackRate(playbackRate))
44 channel.bind('getPlaybackRate', (txn, params) => this.embed.player.playbackRate()) 44 channel.bind('getPlaybackRate', (txn, params) => this.embed.player.playbackRate())
45 channel.bind('getPlaybackRates', (txn, params) => this.embed.playerOptions.playbackRates) 45 channel.bind('getPlaybackRates', (txn, params) => this.embed.playerOptions.playbackRates)
46
47 this.channel = channel 46 this.channel = channel
48 } 47 }
49 48
diff --git a/client/src/standalone/videos/embed.html b/client/src/standalone/videos/embed.html
index 5a15bf552..6edf71f48 100644
--- a/client/src/standalone/videos/embed.html
+++ b/client/src/standalone/videos/embed.html
@@ -22,5 +22,7 @@
22 <video playsinline="true" id="video-container" class="video-js vjs-peertube-skin"> 22 <video playsinline="true" id="video-container" class="video-js vjs-peertube-skin">
23 </video> 23 </video>
24 24
25 <div id="placeholder-preview" />
26
25 </body> 27 </body>
26</html> 28</html>
diff --git a/client/src/standalone/videos/embed.scss b/client/src/standalone/videos/embed.scss
index c40ea1208..95573dabe 100644
--- a/client/src/standalone/videos/embed.scss
+++ b/client/src/standalone/videos/embed.scss
@@ -79,6 +79,16 @@ html, body {
79 } 79 }
80} 80}
81 81
82#placeholder-preview {
83 position: absolute;
84 top: 0;
85 left: 0;
86 background-size: 100% auto;
87 width: 100%;
88 height: 100%;
89 background-position: 50% 50%;
90}
91
82@media screen and (max-width: 300px) { 92@media screen and (max-width: 300px) {
83 #error-block { 93 #error-block {
84 font-size: 36px; 94 font-size: 36px;
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index bd012f506..f33dd8869 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -1,16 +1,24 @@
1import './embed.scss' 1import './embed.scss'
2 2
3import { peertubeTranslate, ResultList, ServerConfig, VideoDetails } from '../../../../shared' 3import {
4 getCompleteLocale,
5 is18nLocale,
6 isDefaultLocale,
7 peertubeTranslate,
8 ResultList,
9 ServerConfig,
10 VideoDetails
11} from '../../../../shared'
4import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' 12import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
5import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' 13import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
6import { 14import {
7 P2PMediaLoaderOptions, 15 P2PMediaLoaderOptions,
8 PeertubePlayerManager,
9 PeertubePlayerManagerOptions, 16 PeertubePlayerManagerOptions,
10 PlayerMode 17 PlayerMode
11} from '../../assets/player/peertube-player-manager' 18} from '../../assets/player/peertube-player-manager'
12import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' 19import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
13import { PeerTubeEmbedApi } from './embed-api' 20import { PeerTubeEmbedApi } from './embed-api'
21import { TranslationsManager } from '../../assets/player/translations-manager'
14 22
15export class PeerTubeEmbed { 23export class PeerTubeEmbed {
16 videoElement: HTMLVideoElement 24 videoElement: HTMLVideoElement
@@ -154,20 +162,30 @@ export class PeerTubeEmbed {
154 const urlParts = window.location.pathname.split('/') 162 const urlParts = window.location.pathname.split('/')
155 const videoId = urlParts[ urlParts.length - 1 ] 163 const videoId = urlParts[ urlParts.length - 1 ]
156 164
157 const [ serverTranslations, videoResponse, captionsResponse, configResponse ] = await Promise.all([ 165 const videoPromise = this.loadVideoInfo(videoId)
158 PeertubePlayerManager.getServerTranslations(window.location.origin, navigator.language), 166 const captionsPromise = this.loadVideoCaptions(videoId)
159 this.loadVideoInfo(videoId), 167 const configPromise = this.loadConfig()
160 this.loadVideoCaptions(videoId), 168
161 this.loadConfig() 169 const translationsPromise = TranslationsManager.getServerTranslations(window.location.origin, navigator.language)
162 ]) 170 const videoResponse = await videoPromise
163 171
164 if (!videoResponse.ok) { 172 if (!videoResponse.ok) {
173 const serverTranslations = await translationsPromise
174
165 if (videoResponse.status === 404) return this.videoNotFound(serverTranslations) 175 if (videoResponse.status === 404) return this.videoNotFound(serverTranslations)
166 176
167 return this.videoFetchError(serverTranslations) 177 return this.videoFetchError(serverTranslations)
168 } 178 }
169 179
170 const videoInfo: VideoDetails = await videoResponse.json() 180 const videoInfo: VideoDetails = await videoResponse.json()
181 this.loadPlaceholder(videoInfo)
182
183 const PeertubePlayerManagerModulePromise = import('../../assets/player/peertube-player-manager')
184
185 const promises = [ translationsPromise, captionsPromise, configPromise, PeertubePlayerManagerModulePromise ]
186 const [ serverTranslations, captionsResponse, configResponse, PeertubePlayerManagerModule ] = await Promise.all(promises)
187
188 const PeertubePlayerManager = PeertubePlayerManagerModule.PeertubePlayerManager
171 const videoCaptions = await this.buildCaptions(serverTranslations, captionsResponse) 189 const videoCaptions = await this.buildCaptions(serverTranslations, captionsResponse)
172 190
173 this.loadParams(videoInfo) 191 this.loadParams(videoInfo)
@@ -220,7 +238,7 @@ export class PeerTubeEmbed {
220 }) 238 })
221 } 239 }
222 240
223 this.player = await PeertubePlayerManager.initialize(this.mode, options, player => this.player = player) 241 this.player = await PeertubePlayerManager.initialize(this.mode, options, (player: any) => this.player = player)
224 this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) 242 this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations))
225 243
226 window[ 'videojsPlayer' ] = this.player 244 window[ 'videojsPlayer' ] = this.player
@@ -230,6 +248,8 @@ export class PeerTubeEmbed {
230 await this.buildDock(videoInfo, configResponse) 248 await this.buildDock(videoInfo, configResponse)
231 249
232 this.initializeApi() 250 this.initializeApi()
251
252 this.removePlaceholder()
233 } 253 }
234 254
235 private handleError (err: Error, translations?: { [ id: string ]: string }) { 255 private handleError (err: Error, translations?: { [ id: string ]: string }) {
@@ -282,6 +302,22 @@ export class PeerTubeEmbed {
282 302
283 return [] 303 return []
284 } 304 }
305
306 private loadPlaceholder (video: VideoDetails) {
307 const placeholder = this.getPlaceholderElement()
308
309 const url = window.location.origin + video.previewPath
310 placeholder.style.backgroundImage = `url("${url}")`
311 }
312
313 private removePlaceholder () {
314 const placeholder = this.getPlaceholderElement()
315 placeholder.parentElement.removeChild(placeholder)
316 }
317
318 private getPlaceholderElement () {
319 return document.getElementById('placeholder-preview')
320 }
285} 321}
286 322
287PeerTubeEmbed.main() 323PeerTubeEmbed.main()