1 import { peertubeTranslate } from '../../../../../shared/core-utils/i18n'
10 VideoStreamingPlaylistType
11 } from '../../../../../shared/models'
12 import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode, VideoJSCaption } from '../../../assets/player'
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'
29 export class PlayerManagerOptions {
30 private autoplay: boolean
32 private controls: boolean
33 private controlBar: boolean
35 private muted: boolean
37 private subtitle: string
38 private enableApi = false
39 private startTime: number | string = 0
40 private stopTime: number | string
42 private title: boolean
43 private warningTitle: boolean
44 private peertubeLink: boolean
45 private p2pEnabled: boolean
46 private bigPlayBackgroundColor: string
47 private foregroundColor: string
49 private mode: PlayerMode
50 private scope = 'peertube'
53 private readonly playerHTML: PlayerHTML,
54 private readonly videoFetcher: VideoFetcher,
55 private readonly peertubePlugin: PeerTubePlugin
75 return this.warningTitle
79 return !!this.p2pEnabled
82 hasBigPlayBackgroundColor () {
83 return !!this.bigPlayBackgroundColor
86 getBigPlayBackgroundColor () {
87 return this.bigPlayBackgroundColor
90 hasForegroundColor () {
91 return !!this.foregroundColor
94 getForegroundColor () {
95 return this.foregroundColor
106 // ---------------------------------------------------------------------------
108 loadParams (config: HTMLServerConfig, video: VideoDetails) {
110 const params = new URL(window.location.toString()).searchParams
112 this.autoplay = getParamToggle(params, 'autoplay', false)
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
118 this.controls = getParamToggle(params, 'controls', true)
119 this.controlBar = getParamToggle(params, 'controlBar', true)
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))
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')
134 this.bigPlayBackgroundColor = getParamString(params, 'bigPlayBackgroundColor')
135 this.foregroundColor = getParamString(params, 'foregroundColor')
137 const modeParam = getParamString(params, 'mode')
140 if (modeParam === 'p2p-media-loader') this.mode = 'p2p-media-loader'
141 else this.mode = 'webtorrent'
143 if (Array.isArray(video.streamingPlaylists) && video.streamingPlaylists.length !== 0) this.mode = 'p2p-media-loader'
144 else this.mode = 'webtorrent'
147 logger.error('Cannot get params from URL.', err)
151 // ---------------------------------------------------------------------------
153 async getPlayerOptions (options: {
155 captionsResponse: Response
158 authorizationHeader: () => string
159 videoFileToken: () => string
161 serverConfig: HTMLServerConfig
163 alreadyHadPlayer: boolean
165 translations: Translations
167 playlistTracker?: PlaylistTracker
168 playNextPlaylistVideo?: () => any
169 playPreviousPlaylistVideo?: () => any
170 onVideoUpdate?: (uuid: string) => any
184 const videoCaptions = await this.buildCaptions(captionsResponse, translations)
186 const playerOptions: PeertubePlayerManagerOptions = {
188 // Autoplay in playlist mode
189 autoplay: alreadyHadPlayer ? true : this.autoplay,
191 controls: this.controls,
192 controlBar: this.controlBar,
197 p2pEnabled: this.p2pEnabled,
199 captions: videoCaptions.length !== 0,
200 subtitle: this.subtitle,
202 startTime: playlistTracker
203 ? playlistTracker.getCurrentElement().startTimestamp
205 stopTime: playlistTracker
206 ? playlistTracker.getCurrentElement().stopTimestamp
210 inactivityTimeout: 2500,
211 videoViewUrl: this.videoFetcher.getVideoViewsUrl(video.uuid),
212 metricsUrl: window.location.origin + '/api/v1/metrics/playback',
214 videoShortUUID: video.shortUUID,
215 videoUUID: video.uuid,
217 playerElement: this.playerHTML.getPlayerElement(),
218 onPlayerElementChange: (element: HTMLVideoElement) => {
219 this.playerHTML.setPlayerElement(element)
222 videoDuration: video.duration,
225 peertubeLink: this.peertubeLink,
226 instanceName: serverConfig.instance.name,
228 poster: window.location.origin + video.previewPath,
229 theaterButton: false,
231 serverUrl: window.location.origin,
232 language: navigator.language,
233 embedUrl: window.location.origin + video.embedPath,
234 embedTitle: video.name,
236 requiresAuth: videoRequiresAuth(video),
240 errorNotifier: () => {
241 // Empty, we don't have a notifier in the embed
244 ...this.buildLiveOptions(video, live),
246 ...this.buildPlaylistOptions(options)
250 videoFiles: video.files
253 ...this.buildP2PMediaLoaderOptions(video),
255 pluginsManager: this.peertubePlugin.getPluginsManager()
261 private buildLiveOptions (video: VideoDetails, live: LiveVideo) {
262 if (!video.isLive) return { isLive: false }
267 latencyMode: live.latencyMode
272 private buildPlaylistOptions (options: {
273 playlistTracker?: PlaylistTracker
274 playNextPlaylistVideo?: () => any
275 playPreviousPlaylistVideo?: () => any
276 onVideoUpdate?: (uuid: string) => any
278 const { playlistTracker, playNextPlaylistVideo, playPreviousPlaylistVideo, onVideoUpdate } = options
280 if (!playlistTracker) return {}
284 elements: playlistTracker.getPlaylistElements(),
285 playlist: playlistTracker.getPlaylist(),
287 getCurrentPosition: () => playlistTracker.getCurrentPosition(),
289 onItemClicked: (videoPlaylistElement: VideoPlaylistElement) => {
290 playlistTracker.setCurrentElement(videoPlaylistElement)
292 onVideoUpdate(videoPlaylistElement.video.uuid)
296 nextVideo: () => playNextPlaylistVideo(),
297 hasNextVideo: () => playlistTracker.hasNextPlaylistElement(),
299 previousVideo: () => playPreviousPlaylistVideo(),
300 hasPreviousVideo: () => playlistTracker.hasPreviousPlaylistElement()
304 private buildP2PMediaLoaderOptions (video: VideoDetails) {
305 if (this.mode !== 'p2p-media-loader') return {}
307 const hlsPlaylist = video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
311 playlistUrl: hlsPlaylist.playlistUrl,
312 segmentsSha256Url: hlsPlaylist.segmentsSha256Url,
313 redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl),
314 trackerAnnounce: video.trackerUrls,
315 videoFiles: hlsPlaylist.files
316 } as P2PMediaLoaderOptions
320 // ---------------------------------------------------------------------------
322 private async buildCaptions (captionsResponse: Response, translations: Translations): Promise<VideoJSCaption[]> {
323 if (captionsResponse.ok) {
324 const { data } = await captionsResponse.json()
326 return data.map((c: VideoCaption) => ({
327 label: peertubeTranslate(c.language.label, translations),
328 language: c.language.id,
329 src: window.location.origin + c.captionPath
336 // ---------------------------------------------------------------------------
338 private isP2PEnabled (config: HTMLServerConfig, video: Video) {
339 const userP2PEnabled = getBoolOrDefault(
340 peertubeLocalStorage.getItem(UserLocalStorageKeys.P2P_ENABLED),
341 config.defaults.p2p.embed.enabled
344 return isP2PEnabled(video, config, userP2PEnabled)