X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;ds=sidebyside;f=client%2Fsrc%2Fstandalone%2Fvideos%2Fembed.ts;h=8d1720f7565f5775663d91924dfa248f99ea3f24;hb=6fad8e51c47b9d07bea99b777c1f55c10f6d576d;hp=71bd04e764378dca8cc525deadf1fb2f14598562;hpb=5abc96fca2496f33075796db208fccc3543e0f65;p=github%2FChocobozzz%2FPeerTube.git diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 71bd04e76..8d1720f75 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts @@ -143,8 +143,11 @@ export class PeerTubeEmbed { return fetch(this.getPlaylistUrl(playlistId)) } - loadPlaylistElements (playlistId: string): Promise { - return fetch(this.getPlaylistUrl(playlistId) + '/videos') + loadPlaylistElements (playlistId: string, start = 0): Promise { + const url = new URL(this.getPlaylistUrl(playlistId) + '/videos') + url.search = new URLSearchParams({ start: '' + start, count: '100' }).toString() + + return fetch(url.toString()) } loadConfig (): Promise { @@ -176,6 +179,8 @@ export class PeerTubeEmbed { const errorText = document.getElementById('error-content') errorText.innerHTML = translatedText + + this.wrapperElement.style.display = 'none' } videoNotFound (translations?: Translations) { @@ -206,6 +211,36 @@ export class PeerTubeEmbed { return params.has(name) ? params.get(name) : defaultValue } + async playNextVideo () { + const next = this.getNextPlaylistElement() + if (!next) { + console.log('Next element not found in playlist.') + return + } + + this.currentPlaylistElement = next + + return this.loadVideoAndBuildPlayer(this.currentPlaylistElement.video.uuid) + } + + async playPreviousVideo () { + const previous = this.getPreviousPlaylistElement() + if (!previous) { + console.log('Previous element not found in playlist.') + return + } + + this.currentPlaylistElement = previous + + await this.loadVideoAndBuildPlayer(this.currentPlaylistElement.video.uuid) + } + + getCurrentPosition () { + if (!this.currentPlaylistElement) return -1 + + return this.currentPlaylistElement.position + } + async init () { try { this.userTokens = Tokens.load() @@ -257,6 +292,28 @@ export class PeerTubeEmbed { } } + private async loadAllPlaylistVideos (playlistId: string, baseResult: ResultList) { + let elements = baseResult.data + let total = baseResult.total + let i = 0 + + while (total > elements.length && i < 10) { + const result = await this.loadPlaylistElements(playlistId, elements.length) + + const json = await result.json() as ResultList + total = json.total + + elements = elements.concat(json.data) + i++ + } + + if (i === 10) { + console.error('Cannot fetch all playlists elements, there are too many!') + } + + return elements + } + private async loadPlaylist (playlistId: string) { const playlistPromise = this.loadPlaylistInfo(playlistId) const playlistElementsPromise = this.loadPlaylistElements(playlistId) @@ -309,22 +366,14 @@ export class PeerTubeEmbed { cancelText: peertubeTranslate('Cancel', translations), suspendedText: peertubeTranslate('Autoplay is suspended', translations), getTitle: () => this.nextVideoTitle(), - next: () => this.autoplayNext(), + next: () => this.playNextVideo(), condition: () => !!this.getNextPlaylistElement(), suspended: () => false }) } - private async autoplayNext () { - const next = this.getNextPlaylistElement() - if (!next) { - console.log('Next element not found in playlist.') - return - } - - this.currentPlaylistElement = next - - const res = await this.loadVideo(this.currentPlaylistElement.video.uuid) + private async loadVideoAndBuildPlayer (uuid: string) { + const res = await this.loadVideo(uuid) if (res === undefined) return return this.buildVideoPlayer(res.videoResponse, res.captionsPromise) @@ -353,6 +402,22 @@ export class PeerTubeEmbed { return next } + private getPreviousPlaylistElement (position?: number): VideoPlaylistElement { + if (!position) position = this.currentPlaylistElement.position - 1 + + if (position < 1) { + return undefined + } + + const prev = this.playlistElements.find(e => e.position === position) + + if (!prev || !prev.video) { + return this.getNextPlaylistElement(position - 1) + } + + return prev + } + private async buildVideoPlayer (videoResponse: Response, captionsPromise: Promise) { let alreadyHadPlayer = false @@ -373,7 +438,7 @@ export class PeerTubeEmbed { return videoInfo }) - const [ videoInfo, serverTranslations, captionsResponse, config, PeertubePlayerManagerModule ] = await Promise.all([ + const [ videoInfoTmp, serverTranslations, captionsResponse, config, PeertubePlayerManagerModule ] = await Promise.all([ videoInfoPromise, this.translationsPromise, captionsPromise, @@ -381,11 +446,29 @@ export class PeerTubeEmbed { this.PeertubePlayerManagerModulePromise ]) + const videoInfo: VideoDetails = videoInfoTmp + const PeertubePlayerManager = PeertubePlayerManagerModule.PeertubePlayerManager const videoCaptions = await this.buildCaptions(serverTranslations, captionsResponse) this.loadParams(videoInfo) + const playlistPlugin = this.currentPlaylistElement + ? { + elements: this.playlistElements, + playlist: this.playlist, + + getCurrentPosition: () => this.currentPlaylistElement.position, + + onItemClicked: (videoPlaylistElement: VideoPlaylistElement) => { + this.currentPlaylistElement = videoPlaylistElement + + this.loadVideoAndBuildPlayer(this.currentPlaylistElement.video.uuid) + .catch(err => console.error(err)) + } + } + : undefined + const options: PeertubePlayerManagerOptions = { common: { // Autoplay in playlist mode @@ -393,12 +476,20 @@ export class PeerTubeEmbed { controls: this.controls, muted: this.muted, loop: this.loop, + captions: videoCaptions.length !== 0, - startTime: this.startTime, - stopTime: this.stopTime, subtitle: this.subtitle, - nextVideo: () => this.autoplayNext(), + startTime: this.playlist ? this.currentPlaylistElement.startTimestamp : this.startTime, + stopTime: this.playlist ? this.currentPlaylistElement.stopTimestamp : this.stopTime, + + nextVideo: this.playlist ? () => this.playNextVideo() : undefined, + hasNextVideo: this.playlist ? () => !!this.getNextPlaylistElement() : undefined, + + previousVideo: this.playlist ? () => this.playPreviousVideo() : undefined, + hasPreviousVideo: this.playlist ? () => !!this.getPreviousPlaylistElement() : undefined, + + playlist: playlistPlugin, videoCaptions, inactivityTimeout: 2500, @@ -452,6 +543,12 @@ export class PeerTubeEmbed { if (this.isPlaylistEmbed()) { await this.buildPlaylistManager() + + this.player.playlist().updateSelected() + + this.player.on('stopped', () => { + this.playNextVideo() + }) } } @@ -472,18 +569,36 @@ export class PeerTubeEmbed { this.playlist = await res.playlistResponse.json() const playlistElementResult = await res.videosResponse.json() - this.playlistElements = playlistElementResult.data + this.playlistElements = await this.loadAllPlaylistVideos(playlistId, playlistElementResult) + + const params = new URL(window.location.toString()).searchParams + const playlistPositionParam = this.getParamString(params, 'playlistPosition') + + let position = 1 + + if (playlistPositionParam) { + position = parseInt(playlistPositionParam + '', 10) + } + + this.currentPlaylistElement = this.playlistElements.find(e => e.position === position) + if (!this.currentPlaylistElement || !this.currentPlaylistElement.video) { + console.error('Current playlist element is not valid.', this.currentPlaylistElement) + this.currentPlaylistElement = this.getNextPlaylistElement() + } + + if (!this.currentPlaylistElement) { + console.error('This playlist does not have any valid element.') + const serverTranslations = await this.translationsPromise + this.playlistFetchError(serverTranslations) + return + } - this.currentPlaylistElement = this.playlistElements[0] videoId = this.currentPlaylistElement.video.uuid } else { videoId = this.getResourceId() } - const res = await this.loadVideo(videoId) - if (res === undefined) return - - return this.buildVideoPlayer(res.videoResponse, res.captionsPromise) + return this.loadVideoAndBuildPlayer(videoId) } private handleError (err: Error, translations?: { [ id: string ]: string }) {