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