Add live autostart/messages in embed
This commit is contained in:
parent
f1a0f3b701
commit
d3f4689bde
|
@ -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()
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue