Add live autostart/messages in embed

pull/5020/head
Chocobozzz 2022-05-31 14:18:41 +02:00
parent f1a0f3b701
commit d3f4689bde
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
8 changed files with 130 additions and 3 deletions

View File

@ -430,6 +430,11 @@ class WebTorrentPlugin extends Plugin {
private initializePlayer () {
this.buildQualities()
if (this.videoFiles.length === 0) {
this.player.addClass('disabled')
return
}
if (this.autoplay) {
this.player.posterImage.hide()

View File

@ -20,6 +20,15 @@ body {
font-size: $font-size;
color: pvar(--embedForegroundColor);
&.disabled {
cursor: default;
pointer-events: none;
.vjs-big-play-button {
display: none !important;
}
}
.vjs-audio-button {
display: none;
}

View File

@ -92,6 +92,17 @@ body {
width: 100%;
height: 100%;
background-position: 50% 50%;
background-repeat: no-repeat;
}
.player-information {
width: 100%;
color: #fff;
background: rgba(0, 0, 0, 0.6);
padding: 20px 0;
position: absolute;
bottom: 0;
text-align: center;
}
@media screen and (max-width: 300px) {

View File

@ -4,12 +4,12 @@ import '../../assets/player/shared/dock/peertube-dock-plugin'
import videojs from 'video.js'
import { peertubeTranslate } from '../../../../shared/core-utils/i18n'
import { HTMLServerConfig, LiveVideo, ResultList, VideoDetails, VideoPlaylist, VideoPlaylistElement } from '../../../../shared/models'
import { PeertubePlayerManager } from '../../assets/player'
import { TranslationsManager } from '../../assets/player/translations-manager'
import { getParamString } from '../../root-helpers'
import { PeerTubeEmbedApi } from './embed-api'
import { AuthHTTP, PeerTubePlugin, PlayerManagerOptions, PlaylistFetcher, PlaylistTracker, VideoFetcher } from './shared'
import { AuthHTTP, LiveManager, PeerTubePlugin, PlayerManagerOptions, PlaylistFetcher, PlaylistTracker, VideoFetcher } from './shared'
import { PlayerHTML } from './shared/player-html'
import { PeertubePlayerManager } from '../../assets/player'
export class PeerTubeEmbed {
player: videojs.Player
@ -26,6 +26,7 @@ export class PeerTubeEmbed {
private readonly peertubePlugin: PeerTubePlugin
private readonly playerHTML: PlayerHTML
private readonly playerManagerOptions: PlayerManagerOptions
private readonly liveManager: LiveManager
private playlistTracker: PlaylistTracker
@ -37,6 +38,7 @@ export class PeerTubeEmbed {
this.peertubePlugin = new PeerTubePlugin(this.http)
this.playerHTML = new PlayerHTML(videoWrapperId)
this.playerManagerOptions = new PlayerManagerOptions(this.playerHTML, this.videoFetcher, this.peertubePlugin)
this.liveManager = new LiveManager(this.playerHTML)
try {
this.config = JSON.parse(window['PeerTubeServerConfig'])
@ -235,6 +237,17 @@ export class PeerTubeEmbed {
}
this.peertubePlugin.getPluginsManager().runHook('action:embed.player.loaded', undefined, { player: this.player, videojs, video })
if (video.isLive) {
this.liveManager.displayInfoAndListenForChanges({
video,
translations,
onPublishedVideo: () => {
this.liveManager.stopListeningForChanges(video)
this.loadVideoAndBuildPlayer(video.uuid)
}
})
}
}
private resetPlayerElement () {

View File

@ -1,5 +1,6 @@
export * from './auth-http'
export * from './peertube-plugin'
export * from './live-manager'
export * from './player-html'
export * from './player-manager-options'
export * from './playlist-fetcher'

View File

@ -0,0 +1,69 @@
import { Socket } from 'socket.io-client'
import { LiveVideoEventPayload, VideoDetails, VideoState } from '../../../../../shared/models'
import { PlayerHTML } from './player-html'
import { Translations } from './translations'
export class LiveManager {
private liveSocket: Socket
constructor (
private readonly playerHTML: PlayerHTML
) {
}
async displayInfoAndListenForChanges (options: {
video: VideoDetails
translations: Translations
onPublishedVideo: () => any
}) {
const { video, onPublishedVideo } = options
this.displayAppropriateInfo(options)
if (!this.liveSocket) {
const io = (await import('socket.io-client')).io
this.liveSocket = io(window.location.origin + '/live-videos')
}
this.liveSocket.on('state-change', (payload: LiveVideoEventPayload) => {
if (payload.state === VideoState.PUBLISHED) {
this.playerHTML.removeInformation()
onPublishedVideo()
return
}
})
this.liveSocket.emit('subscribe', { videoId: video.id })
}
stopListeningForChanges (video: VideoDetails) {
this.liveSocket.emit('unsubscribe', { videoId: video.id })
}
private displayAppropriateInfo (options: {
video: VideoDetails
translations: Translations
}) {
const { video, translations } = options
if (video.state.id === VideoState.WAITING_FOR_LIVE) {
this.displayWaitingForLiveInfo(translations)
return
}
if (video.state.id === VideoState.LIVE_ENDED) {
this.displayEndedLiveInfo(translations)
return
}
}
private displayWaitingForLiveInfo (translations: Translations) {
this.playerHTML.displayInformation('This live has not started yet.', translations)
}
private displayEndedLiveInfo (translations: Translations) {
this.playerHTML.displayInformation('This live has ended.', translations)
}
}

View File

@ -6,6 +6,7 @@ export class PlayerHTML {
private readonly wrapperElement: HTMLElement
private playerElement: HTMLVideoElement
private informationElement: HTMLDivElement
constructor (private readonly videoWrapperId: string) {
this.wrapperElement = document.getElementById(this.videoWrapperId)
@ -66,6 +67,20 @@ export class PlayerHTML {
placeholder.style.display = 'none'
}
displayInformation (text: string, translations: Translations) {
if (this.informationElement) this.removeInformation()
this.informationElement = document.createElement('div')
this.informationElement.className = 'player-information'
this.informationElement.innerText = peertubeTranslate(text, translations)
document.body.appendChild(this.informationElement)
}
removeInformation () {
this.removeElement(this.informationElement)
}
private getPlaceholderElement () {
return document.getElementById('placeholder-preview')
}

View File

@ -30,6 +30,7 @@ import { MAccountActor, MChannelActor } from '../types/models'
import { getActivityStreamDuration } from './activitypub/activity'
import { getBiggestActorImage } from './actor-image'
import { ServerConfigManager } from './server-config-manager'
import { isTestInstance } from '@server/helpers/core-utils'
type Tags = {
ogType: string
@ -232,7 +233,10 @@ class ClientHtml {
static async getEmbedHTML () {
const path = ClientHtml.getEmbedPath()
if (ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
// Disable HTML cache in dev mode because webpack can regenerate JS files
if (!isTestInstance() && ClientHtml.htmlCache[path]) {
return ClientHtml.htmlCache[path]
}
const buffer = await readFile(path)
const serverConfig = await ServerConfigManager.Instance.getHTMLServerConfig()