]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/standalone/videos/shared/player-manager-options.ts
More robust player stats card
[github/Chocobozzz/PeerTube.git] / client / src / standalone / videos / shared / player-manager-options.ts
CommitLineData
f1a0f3b7
C
1import { peertubeTranslate } from '../../../../../shared/core-utils/i18n'
2import {
3 HTMLServerConfig,
4 LiveVideo,
5 Video,
6 VideoCaption,
7 VideoDetails,
8 VideoPlaylistElement,
aeb112ed 9 VideoState,
f1a0f3b7
C
10 VideoStreamingPlaylistType
11} from '../../../../../shared/models'
12import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode, VideoJSCaption } from '../../../assets/player'
13import {
14 getBoolOrDefault,
15 getParamString,
16 getParamToggle,
17 isP2PEnabled,
42b40636 18 logger,
f1a0f3b7 19 peertubeLocalStorage,
3545e72c
C
20 UserLocalStorageKeys,
21 videoRequiresAuth
f1a0f3b7
C
22} from '../../../root-helpers'
23import { PeerTubePlugin } from './peertube-plugin'
24import { PlayerHTML } from './player-html'
25import { PlaylistTracker } from './playlist-tracker'
26import { Translations } from './translations'
27import { VideoFetcher } from './video-fetcher'
28
29export class PlayerManagerOptions {
30 private autoplay: boolean
31
32 private controls: boolean
33 private controlBar: boolean
34
35 private muted: boolean
36 private loop: boolean
37 private subtitle: string
38 private enableApi = false
39 private startTime: number | string = 0
40 private stopTime: number | string
41
42 private title: boolean
43 private warningTitle: boolean
44 private peertubeLink: boolean
45 private p2pEnabled: boolean
46 private bigPlayBackgroundColor: string
47 private foregroundColor: string
48
49 private mode: PlayerMode
50 private scope = 'peertube'
51
52 constructor (
53 private readonly playerHTML: PlayerHTML,
54 private readonly videoFetcher: VideoFetcher,
55 private readonly peertubePlugin: PeerTubePlugin
56 ) {}
57
58 hasAPIEnabled () {
59 return this.enableApi
60 }
61
62 hasAutoplay () {
63 return this.autoplay
64 }
65
66 hasControls () {
67 return this.controls
68 }
69
70 hasTitle () {
71 return this.title
72 }
73
74 hasWarningTitle () {
75 return this.warningTitle
76 }
77
78 hasP2PEnabled () {
79 return !!this.p2pEnabled
80 }
81
82 hasBigPlayBackgroundColor () {
83 return !!this.bigPlayBackgroundColor
84 }
85
86 getBigPlayBackgroundColor () {
87 return this.bigPlayBackgroundColor
88 }
89
90 hasForegroundColor () {
91 return !!this.foregroundColor
92 }
93
94 getForegroundColor () {
95 return this.foregroundColor
96 }
97
98 getMode () {
99 return this.mode
100 }
101
102 getScope () {
103 return this.scope
104 }
105
106 // ---------------------------------------------------------------------------
107
108 loadParams (config: HTMLServerConfig, video: VideoDetails) {
109 try {
110 const params = new URL(window.location.toString()).searchParams
111
112 this.autoplay = getParamToggle(params, 'autoplay', false)
aeb112ed
C
113 // Disable auto play on live videos that are not streamed
114 if (video.state.id === VideoState.LIVE_ENDED || video.state.id === VideoState.WAITING_FOR_LIVE) {
115 this.autoplay = false
116 }
f1a0f3b7
C
117
118 this.controls = getParamToggle(params, 'controls', true)
119 this.controlBar = getParamToggle(params, 'controlBar', true)
120
121 this.muted = getParamToggle(params, 'muted', undefined)
122 this.loop = getParamToggle(params, 'loop', false)
123 this.title = getParamToggle(params, 'title', true)
124 this.enableApi = getParamToggle(params, 'api', this.enableApi)
125 this.warningTitle = getParamToggle(params, 'warningTitle', true)
126 this.peertubeLink = getParamToggle(params, 'peertubeLink', true)
127 this.p2pEnabled = getParamToggle(params, 'p2p', this.isP2PEnabled(config, video))
128
129 this.scope = getParamString(params, 'scope', this.scope)
130 this.subtitle = getParamString(params, 'subtitle')
131 this.startTime = getParamString(params, 'start')
132 this.stopTime = getParamString(params, 'stop')
133
134 this.bigPlayBackgroundColor = getParamString(params, 'bigPlayBackgroundColor')
135 this.foregroundColor = getParamString(params, 'foregroundColor')
136
137 const modeParam = getParamString(params, 'mode')
138
139 if (modeParam) {
140 if (modeParam === 'p2p-media-loader') this.mode = 'p2p-media-loader'
141 else this.mode = 'webtorrent'
142 } else {
143 if (Array.isArray(video.streamingPlaylists) && video.streamingPlaylists.length !== 0) this.mode = 'p2p-media-loader'
144 else this.mode = 'webtorrent'
145 }
146 } catch (err) {
42b40636 147 logger.error('Cannot get params from URL.', err)
f1a0f3b7
C
148 }
149 }
150
151 // ---------------------------------------------------------------------------
152
153 async getPlayerOptions (options: {
154 video: VideoDetails
155 captionsResponse: Response
156 live?: LiveVideo
157
59a643aa
C
158 forceAutoplay: boolean
159
3545e72c
C
160 authorizationHeader: () => string
161 videoFileToken: () => string
162
bd2b51be
C
163 serverConfig: HTMLServerConfig
164
7dcd45a9 165 autoplayFromPreviousVideo: boolean
f1a0f3b7
C
166
167 translations: Translations
168
169 playlistTracker?: PlaylistTracker
170 playNextPlaylistVideo?: () => any
171 playPreviousPlaylistVideo?: () => any
172 onVideoUpdate?: (uuid: string) => any
173 }) {
174 const {
175 video,
176 captionsResponse,
7dcd45a9 177 autoplayFromPreviousVideo,
3545e72c 178 videoFileToken,
f1a0f3b7 179 translations,
59a643aa 180 forceAutoplay,
f1a0f3b7 181 playlistTracker,
bd2b51be 182 live,
3545e72c 183 authorizationHeader,
bd2b51be 184 serverConfig
f1a0f3b7
C
185 } = options
186
187 const videoCaptions = await this.buildCaptions(captionsResponse, translations)
188
189 const playerOptions: PeertubePlayerManagerOptions = {
190 common: {
191 // Autoplay in playlist mode
7dcd45a9 192 autoplay: autoplayFromPreviousVideo ? true : this.autoplay,
59a643aa 193 forceAutoplay,
f1a0f3b7
C
194
195 controls: this.controls,
196 controlBar: this.controlBar,
197
198 muted: this.muted,
199 loop: this.loop,
200
201 p2pEnabled: this.p2pEnabled,
202
203 captions: videoCaptions.length !== 0,
204 subtitle: this.subtitle,
205
206 startTime: playlistTracker
207 ? playlistTracker.getCurrentElement().startTimestamp
208 : this.startTime,
209 stopTime: playlistTracker
210 ? playlistTracker.getCurrentElement().stopTimestamp
211 : this.stopTime,
212
213 videoCaptions,
214 inactivityTimeout: 2500,
215 videoViewUrl: this.videoFetcher.getVideoViewsUrl(video.uuid),
fd3c2e87 216 metricsUrl: window.location.origin + '/api/v1/metrics/playback',
f1a0f3b7
C
217
218 videoShortUUID: video.shortUUID,
219 videoUUID: video.uuid,
220
221 playerElement: this.playerHTML.getPlayerElement(),
222 onPlayerElementChange: (element: HTMLVideoElement) => {
223 this.playerHTML.setPlayerElement(element)
224 },
225
226 videoDuration: video.duration,
227 enableHotkeys: true,
bd2b51be 228
f1a0f3b7 229 peertubeLink: this.peertubeLink,
bd2b51be
C
230 instanceName: serverConfig.instance.name,
231
f1a0f3b7
C
232 poster: window.location.origin + video.previewPath,
233 theaterButton: false,
234
235 serverUrl: window.location.origin,
236 language: navigator.language,
237 embedUrl: window.location.origin + video.embedPath,
238 embedTitle: video.name,
239
3545e72c
C
240 requiresAuth: videoRequiresAuth(video),
241 authorizationHeader,
242 videoFileToken,
243
f1a0f3b7
C
244 errorNotifier: () => {
245 // Empty, we don't have a notifier in the embed
246 },
247
248 ...this.buildLiveOptions(video, live),
249
250 ...this.buildPlaylistOptions(options)
251 },
252
253 webtorrent: {
254 videoFiles: video.files
255 },
256
257 ...this.buildP2PMediaLoaderOptions(video),
258
259 pluginsManager: this.peertubePlugin.getPluginsManager()
260 }
261
262 return playerOptions
263 }
264
265 private buildLiveOptions (video: VideoDetails, live: LiveVideo) {
266 if (!video.isLive) return { isLive: false }
267
268 return {
269 isLive: true,
270 liveOptions: {
271 latencyMode: live.latencyMode
272 }
273 }
274 }
275
276 private buildPlaylistOptions (options: {
277 playlistTracker?: PlaylistTracker
278 playNextPlaylistVideo?: () => any
279 playPreviousPlaylistVideo?: () => any
280 onVideoUpdate?: (uuid: string) => any
281 }) {
282 const { playlistTracker, playNextPlaylistVideo, playPreviousPlaylistVideo, onVideoUpdate } = options
283
284 if (!playlistTracker) return {}
285
286 return {
287 playlist: {
288 elements: playlistTracker.getPlaylistElements(),
289 playlist: playlistTracker.getPlaylist(),
290
291 getCurrentPosition: () => playlistTracker.getCurrentPosition(),
292
293 onItemClicked: (videoPlaylistElement: VideoPlaylistElement) => {
294 playlistTracker.setCurrentElement(videoPlaylistElement)
295
296 onVideoUpdate(videoPlaylistElement.video.uuid)
297 }
298 },
299
300 nextVideo: () => playNextPlaylistVideo(),
301 hasNextVideo: () => playlistTracker.hasNextPlaylistElement(),
302
303 previousVideo: () => playPreviousPlaylistVideo(),
304 hasPreviousVideo: () => playlistTracker.hasPreviousPlaylistElement()
305 }
306 }
307
308 private buildP2PMediaLoaderOptions (video: VideoDetails) {
309 if (this.mode !== 'p2p-media-loader') return {}
310
311 const hlsPlaylist = video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
312
313 return {
314 p2pMediaLoader: {
315 playlistUrl: hlsPlaylist.playlistUrl,
316 segmentsSha256Url: hlsPlaylist.segmentsSha256Url,
317 redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl),
318 trackerAnnounce: video.trackerUrls,
319 videoFiles: hlsPlaylist.files
320 } as P2PMediaLoaderOptions
321 }
322 }
323
324 // ---------------------------------------------------------------------------
325
326 private async buildCaptions (captionsResponse: Response, translations: Translations): Promise<VideoJSCaption[]> {
327 if (captionsResponse.ok) {
328 const { data } = await captionsResponse.json()
329
330 return data.map((c: VideoCaption) => ({
331 label: peertubeTranslate(c.language.label, translations),
332 language: c.language.id,
333 src: window.location.origin + c.captionPath
334 }))
335 }
336
337 return []
338 }
339
340 // ---------------------------------------------------------------------------
341
342 private isP2PEnabled (config: HTMLServerConfig, video: Video) {
343 const userP2PEnabled = getBoolOrDefault(
344 peertubeLocalStorage.getItem(UserLocalStorageKeys.P2P_ENABLED),
345 config.defaults.p2p.embed.enabled
346 )
347
348 return isP2PEnabled(video, config, userP2PEnabled)
349 }
350}