+ private wrapperElement: HTMLElement
+
+ static async main () {
+ const videoContainerId = 'video-wrapper'
+ const embed = new PeerTubeEmbed(videoContainerId)
+ await embed.init()
+ }
+
+ constructor (private videoWrapperId: string) {
+ this.wrapperElement = document.getElementById(this.videoWrapperId)
+ }
+
+ getVideoUrl (id: string) {
+ return window.location.origin + '/api/v1/videos/' + id
+ }
+
+ refreshFetch (url: string, options?: Object) {
+ return fetch(url, options)
+ .then((res: Response) => {
+ if (res.status !== 401) return res
+
+ // 401 unauthorized is not catch-ed, but then-ed
+ const error = res
+
+ const refreshingTokenPromise = new Promise((resolve, reject) => {
+ const clientId: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID)
+ const clientSecret: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET)
+ const headers = new Headers()
+ headers.set('Content-Type', 'application/x-www-form-urlencoded')
+ const data = {
+ refresh_token: this.userTokens.refreshToken,
+ client_id: clientId,
+ client_secret: clientSecret,
+ response_type: 'code',
+ grant_type: 'refresh_token'
+ }
+
+ fetch('/api/v1/users/token', {
+ headers,
+ method: 'POST',
+ body: objectToUrlEncoded(data)
+ })
+ .then(res => res.json())
+ .then((obj: UserRefreshToken) => {
+ this.userTokens.accessToken = obj.access_token
+ this.userTokens.refreshToken = obj.refresh_token
+ this.userTokens.save()
+
+ this.setHeadersFromTokens()
+
+ resolve()
+ })
+ .catch((refreshTokenError: any) => {
+ reject(refreshTokenError)
+ })
+ })
+
+ return refreshingTokenPromise
+ .catch(() => {
+ // If refreshing fails, continue with original error
+ throw error
+ })
+ .then(() => fetch(url, {
+ ...options,
+ headers: this.headers
+ }))
+ })
+ }
+
+ getPlaylistUrl (id: string) {
+ return window.location.origin + '/api/v1/video-playlists/' + id
+ }
+
+ loadVideoInfo (videoId: string): Promise<Response> {
+ return this.refreshFetch(this.getVideoUrl(videoId), { headers: this.headers })
+ }
+
+ loadVideoCaptions (videoId: string): Promise<Response> {
+ return fetch(this.getVideoUrl(videoId) + '/captions')
+ }
+
+ loadPlaylistInfo (playlistId: string): Promise<Response> {
+ return fetch(this.getPlaylistUrl(playlistId))
+ }
+
+ loadPlaylistElements (playlistId: string): Promise<Response> {
+ return fetch(this.getPlaylistUrl(playlistId) + '/videos')
+ }
+
+ loadConfig (): Promise<ServerConfig> {
+ return fetch('/api/v1/config')
+ .then(res => res.json())
+ }
+
+ removeElement (element: HTMLElement) {
+ element.parentElement.removeChild(element)
+ }
+
+ displayError (text: string, translations?: Translations) {
+ // Remove video element
+ if (this.playerElement) {
+ this.removeElement(this.playerElement)
+ this.playerElement = undefined
+ }
+
+ const translatedText = peertubeTranslate(text, translations)
+ const translatedSorry = peertubeTranslate('Sorry', translations)
+
+ document.title = translatedSorry + ' - ' + translatedText
+
+ const errorBlock = document.getElementById('error-block')
+ errorBlock.style.display = 'flex'
+
+ const errorTitle = document.getElementById('error-title')
+ errorTitle.innerHTML = peertubeTranslate('Sorry', translations)
+
+ const errorText = document.getElementById('error-content')
+ errorText.innerHTML = translatedText
+ }
+
+ videoNotFound (translations?: Translations) {
+ const text = 'This video does not exist.'
+ this.displayError(text, translations)
+ }
+
+ videoFetchError (translations?: Translations) {
+ const text = 'We cannot fetch the video. Please try again later.'
+ this.displayError(text, translations)
+ }
+
+ playlistNotFound (translations?: Translations) {
+ const text = 'This playlist does not exist.'
+ this.displayError(text, translations)
+ }