+ }
+
+ this.resolutions = resolutions
+ this.channel.notify({
+ method: 'resolutionUpdate',
+ params: this.resolutions
+ })
+ }
+}
+
+class PeerTubeEmbed {
+ videoElement: HTMLVideoElement
+ player: any
+ playerOptions: any
+ api: PeerTubeEmbedApi = null
+ autoplay = false
+ controls = true
+ muted = false
+ loop = false
+ enableApi = false
+ startTime: number | string = 0
+ scope = 'peertube'
+
+ static async main () {
+ const videoContainerId = 'video-container'
+ const embed = new PeerTubeEmbed(videoContainerId)
+ await embed.init()
+ }
+
+ constructor (private videoContainerId: string) {
+ this.videoElement = document.getElementById(videoContainerId) as HTMLVideoElement
+ }
+
+ getVideoUrl (id: string) {
+ return window.location.origin + '/api/v1/videos/' + id
+ }
+
+ loadVideoInfo (videoId: string): Promise<Response> {
+ return fetch(this.getVideoUrl(videoId))
+ }
+
+ loadVideoCaptions (videoId: string): Promise<Response> {
+ return fetch(this.getVideoUrl(videoId) + '/captions')
+ }
+
+ removeElement (element: HTMLElement) {
+ element.parentElement.removeChild(element)
+ }
+
+ displayError (text: string) {
+ // Remove video element
+ if (this.videoElement) this.removeElement(this.videoElement)
+
+ document.title = 'Sorry - ' + text
+
+ const errorBlock = document.getElementById('error-block')
+ errorBlock.style.display = 'flex'
+
+ const errorText = document.getElementById('error-content')
+ errorText.innerHTML = text
+ }
+
+ videoNotFound () {
+ const text = 'This video does not exist.'
+ this.displayError(text)
+ }
+
+ videoFetchError () {
+ const text = 'We cannot fetch the video. Please try again later.'
+ this.displayError(text)
+ }
+
+ getParamToggle (params: URLSearchParams, name: string, defaultValue: boolean) {
+ return params.has(name) ? (params.get(name) === '1' || params.get(name) === 'true') : defaultValue
+ }
+
+ getParamString (params: URLSearchParams, name: string, defaultValue: string) {
+ return params.has(name) ? params.get(name) : defaultValue
+ }
+
+ async init () {
+ try {
+ await this.initCore()
+ } catch (e) {
+ console.error(e)
+ }
+ }
+
+ private initializeApi () {
+ if (!this.enableApi) return
+
+ this.api = new PeerTubeEmbedApi(this)
+ this.api.initialize()
+ }
+
+ private loadParams () {
+ try {
+ let params = new URL(window.location.toString()).searchParams
+
+ this.autoplay = this.getParamToggle(params, 'autoplay', this.autoplay)
+ this.controls = this.getParamToggle(params, 'controls', this.controls)
+ this.muted = this.getParamToggle(params, 'muted', this.muted)
+ this.loop = this.getParamToggle(params, 'loop', this.loop)
+ this.enableApi = this.getParamToggle(params, 'api', this.enableApi)
+ this.scope = this.getParamString(params, 'scope', this.scope)
+
+ const startTimeParamString = params.get('start')
+ if (startTimeParamString) this.startTime = startTimeParamString
+ } catch (err) {
+ console.error('Cannot get params from URL.', err)
+ }
+ }
+
+ private async initCore () {
+ const urlParts = window.location.href.split('/')
+ const lastPart = urlParts[ urlParts.length - 1 ]
+ const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ]
+
+ await loadLocale(window.location.origin, vjs, navigator.language)
+ const [ videoResponse, captionsResponse ] = await Promise.all([
+ this.loadVideoInfo(videoId),
+ this.loadVideoCaptions(videoId)
+ ])
+
+ if (!videoResponse.ok) {
+ if (videoResponse.status === 404) return this.videoNotFound()
+
+ return this.videoFetchError()
+ }
+
+ const videoInfo: VideoDetails = await videoResponse.json()
+ let videoCaptions: VideoJSCaption[] = []
+ if (captionsResponse.ok) {
+ const { data } = (await captionsResponse.json()) as ResultList<VideoCaption>
+ videoCaptions = data.map(c => ({
+ label: c.language.label,
+ language: c.language.id,
+ src: window.location.origin + c.captionPath
+ }))
+ }
+
+ this.loadParams()
+
+ const videojsOptions = getVideojsOptions({
+ autoplay: this.autoplay,
+ controls: this.controls,
+ muted: this.muted,
+ loop: this.loop,
+ startTime: this.startTime,
+
+ videoCaptions,
+ inactivityTimeout: 1500,
+ videoViewUrl: this.getVideoUrl(videoId) + '/views',
+ playerElement: this.videoElement,
+ videoFiles: videoInfo.files,
+ videoDuration: videoInfo.duration,
+ enableHotkeys: true,
+ peertubeLink: true,
+ poster: window.location.origin + videoInfo.previewPath,
+ theaterMode: false
+ })
+
+ this.playerOptions = videojsOptions
+ this.player = vjs(this.videoContainerId, videojsOptions, () => {
+ this.player.on('customError', (event, data) => this.handleError(data.err))
+
+ window[ 'videojsPlayer' ] = this.player
+
+ if (this.controls) {
+ this.player.dock({
+ title: videoInfo.name,
+ description: this.player.localize('Uses P2P, others may know your IP is downloading this video.')
+ })
+ }
+
+ addContextMenu(this.player, window.location.origin + videoInfo.embedPath)
+
+ this.initializeApi()