Add ability to set password from embed API
This commit is contained in:
parent
4c07200d64
commit
b13460a10a
|
@ -49,20 +49,6 @@ function isMobile () {
|
|||
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
||||
}
|
||||
|
||||
function buildVideoOrPlaylistEmbed (embedUrl: string, embedTitle: string) {
|
||||
const iframe = document.createElement('iframe')
|
||||
|
||||
iframe.title = embedTitle
|
||||
iframe.width = '560'
|
||||
iframe.height = '315'
|
||||
iframe.src = embedUrl
|
||||
iframe.frameBorder = '0'
|
||||
iframe.allowFullscreen = true
|
||||
iframe.sandbox.add('allow-same-origin', 'allow-scripts', 'allow-popups')
|
||||
|
||||
return iframe.outerHTML
|
||||
}
|
||||
|
||||
function videoFileMaxByResolution (files: VideoFile[]) {
|
||||
let max = files[0]
|
||||
|
||||
|
@ -106,7 +92,6 @@ export {
|
|||
isWebRTCDisabled,
|
||||
isP2PEnabled,
|
||||
|
||||
buildVideoOrPlaylistEmbed,
|
||||
videoFileMaxByResolution,
|
||||
videoFileMinByResolution,
|
||||
isMobile,
|
||||
|
|
|
@ -195,6 +195,15 @@ export class PeerTubePlayer {
|
|||
return this.sendMessage<undefined, number>('getCurrentPosition')
|
||||
}
|
||||
|
||||
/**
|
||||
* Set video password to so the user doesn't have to manually fill it
|
||||
*
|
||||
* @param password
|
||||
*/
|
||||
async setVideoPassword (password: string): Promise<void> {
|
||||
await this.sendMessage('setVideoPassword', password)
|
||||
}
|
||||
|
||||
private constructChannel () {
|
||||
this.channel = Channel.build({
|
||||
window: this.embedElement.contentWindow,
|
||||
|
|
|
@ -25,16 +25,15 @@ export class PeerTubeEmbedApi {
|
|||
|
||||
initialize () {
|
||||
this.constructChannel()
|
||||
this.setupStateTracking()
|
||||
|
||||
// We're ready!
|
||||
|
||||
this.notifyReady()
|
||||
}
|
||||
|
||||
reInit () {
|
||||
initWithVideo () {
|
||||
this.disposeStateTracking()
|
||||
this.setupStateTracking()
|
||||
|
||||
if (!this.isReady) {
|
||||
this.notifyReady()
|
||||
}
|
||||
}
|
||||
|
||||
private get element () {
|
||||
|
@ -44,6 +43,8 @@ export class PeerTubeEmbedApi {
|
|||
private constructChannel () {
|
||||
const channel = Channel.build({ window: window.parent, origin: '*', scope: this.embed.getScope() })
|
||||
|
||||
channel.bind('setVideoPassword', (txn, value) => this.embed.setVideoPasswordByAPI(value))
|
||||
|
||||
channel.bind('play', (txn, params) => this.embed.player.play())
|
||||
channel.bind('pause', (txn, params) => this.embed.player.pause())
|
||||
channel.bind('seek', (txn, time) => this.embed.player.currentTime(time))
|
||||
|
@ -66,6 +67,7 @@ export class PeerTubeEmbedApi {
|
|||
channel.bind('playNextVideo', (txn, params) => this.embed.playNextPlaylistVideo())
|
||||
channel.bind('playPreviousVideo', (txn, params) => this.embed.playPreviousPlaylistVideo())
|
||||
channel.bind('getCurrentPosition', (txn, params) => this.embed.getCurrentPlaylistPosition())
|
||||
|
||||
this.channel = channel
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ export class PeerTubeEmbed {
|
|||
private alreadyPlayed = false
|
||||
|
||||
private videoPassword: string
|
||||
private videoPasswordFromAPI: string
|
||||
private onVideoPasswordFromAPIResolver: (value: string) => void
|
||||
private requiresPassword: boolean
|
||||
|
||||
constructor (videoWrapperId: string) {
|
||||
|
@ -142,17 +144,33 @@ export class PeerTubeEmbed {
|
|||
}
|
||||
|
||||
private initializeApi () {
|
||||
if (this.playerOptionsBuilder.hasAPIEnabled()) {
|
||||
if (this.api) {
|
||||
this.api.reInit()
|
||||
return
|
||||
}
|
||||
if (!this.playerOptionsBuilder.hasAPIEnabled()) return
|
||||
if (this.api) return
|
||||
|
||||
this.api = new PeerTubeEmbedApi(this)
|
||||
this.api.initialize()
|
||||
this.api = new PeerTubeEmbedApi(this)
|
||||
this.api.initialize()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
setVideoPasswordByAPI (password: string) {
|
||||
logger.info('Setting password from API')
|
||||
|
||||
this.videoPasswordFromAPI = password
|
||||
|
||||
if (this.onVideoPasswordFromAPIResolver) {
|
||||
this.onVideoPasswordFromAPIResolver(password)
|
||||
}
|
||||
}
|
||||
|
||||
private getPasswordByAPI () {
|
||||
if (this.videoPasswordFromAPI) return Promise.resolve(this.videoPasswordFromAPI)
|
||||
|
||||
return new Promise<string>(res => {
|
||||
this.onVideoPasswordFromAPIResolver = res
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async playNextPlaylistVideo () {
|
||||
|
@ -191,6 +209,9 @@ export class PeerTubeEmbed {
|
|||
}) {
|
||||
const { uuid, forceAutoplay } = options
|
||||
|
||||
this.playerOptionsBuilder.loadCommonParams()
|
||||
this.initializeApi()
|
||||
|
||||
try {
|
||||
const {
|
||||
videoResponse,
|
||||
|
@ -218,7 +239,7 @@ export class PeerTubeEmbed {
|
|||
|
||||
const videoInfoPromise = videoResponse.json()
|
||||
.then(async (videoInfo: VideoDetails) => {
|
||||
this.playerOptionsBuilder.loadParams(this.config, videoInfo)
|
||||
this.playerOptionsBuilder.loadVideoParams(this.config, videoInfo)
|
||||
|
||||
const live = videoInfo.isLive
|
||||
? await this.videoFetcher.loadLive(videoInfo)
|
||||
|
@ -287,7 +308,8 @@ export class PeerTubeEmbed {
|
|||
(window as any)['videojsPlayer'] = this.player
|
||||
|
||||
this.buildCSS()
|
||||
this.initializeApi()
|
||||
|
||||
if (this.api) this.api.initWithVideo()
|
||||
}
|
||||
|
||||
this.alreadyInitialized = true
|
||||
|
@ -360,10 +382,30 @@ export class PeerTubeEmbed {
|
|||
if (incorrectPassword === null) return false
|
||||
|
||||
this.requiresPassword = true
|
||||
|
||||
if (this.playerOptionsBuilder.mustWaitPasswordFromEmbedAPI()) {
|
||||
logger.info('Waiting for password from Embed API')
|
||||
|
||||
const videoPasswordFromAPI = await this.getPasswordByAPI()
|
||||
|
||||
if (videoPasswordFromAPI && this.videoPassword !== videoPasswordFromAPI) {
|
||||
logger.info('Using video password from API')
|
||||
|
||||
this.videoPassword = videoPasswordFromAPI
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
logger.error('Password from embed API is not valid')
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.videoPassword = await this.playerHTML.askVideoPassword({
|
||||
incorrectPassword,
|
||||
translations: await this.translationsPromise
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ export class PlayerOptionsBuilder {
|
|||
private bigPlayBackgroundColor: string
|
||||
private foregroundColor: string
|
||||
|
||||
private waitPasswordFromEmbedAPI = false
|
||||
|
||||
private mode: PlayerMode
|
||||
private scope = 'peertube'
|
||||
|
||||
|
@ -106,18 +108,16 @@ export class PlayerOptionsBuilder {
|
|||
return this.scope
|
||||
}
|
||||
|
||||
mustWaitPasswordFromEmbedAPI () {
|
||||
return this.waitPasswordFromEmbedAPI
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
loadParams (config: HTMLServerConfig, video: VideoDetails) {
|
||||
loadCommonParams () {
|
||||
try {
|
||||
const params = new URL(window.location.toString()).searchParams
|
||||
|
||||
this.autoplay = getParamToggle(params, 'autoplay', false)
|
||||
// Disable auto play on live videos that are not streamed
|
||||
if (video.state.id === VideoState.LIVE_ENDED || video.state.id === VideoState.WAITING_FOR_LIVE) {
|
||||
this.autoplay = false
|
||||
}
|
||||
|
||||
this.controls = getParamToggle(params, 'controls', true)
|
||||
this.controlBar = getParamToggle(params, 'controlBar', true)
|
||||
|
||||
|
@ -125,9 +125,9 @@ export class PlayerOptionsBuilder {
|
|||
this.loop = getParamToggle(params, 'loop', false)
|
||||
this.title = getParamToggle(params, 'title', true)
|
||||
this.enableApi = getParamToggle(params, 'api', this.enableApi)
|
||||
this.waitPasswordFromEmbedAPI = getParamToggle(params, 'waitPasswordFromEmbedAPI', this.waitPasswordFromEmbedAPI)
|
||||
this.warningTitle = getParamToggle(params, 'warningTitle', true)
|
||||
this.peertubeLink = getParamToggle(params, 'peertubeLink', true)
|
||||
this.p2pEnabled = getParamToggle(params, 'p2p', this.isP2PEnabled(config, video))
|
||||
|
||||
this.scope = getParamString(params, 'scope', this.scope)
|
||||
this.subtitle = getParamString(params, 'subtitle')
|
||||
|
@ -137,6 +137,22 @@ export class PlayerOptionsBuilder {
|
|||
|
||||
this.bigPlayBackgroundColor = getParamString(params, 'bigPlayBackgroundColor')
|
||||
this.foregroundColor = getParamString(params, 'foregroundColor')
|
||||
} catch (err) {
|
||||
logger.error('Cannot get params from URL.', err)
|
||||
}
|
||||
}
|
||||
|
||||
loadVideoParams (config: HTMLServerConfig, video: VideoDetails) {
|
||||
try {
|
||||
const params = new URL(window.location.toString()).searchParams
|
||||
|
||||
this.autoplay = getParamToggle(params, 'autoplay', false)
|
||||
// Disable auto play on live videos that are not streamed
|
||||
if (video.state.id === VideoState.LIVE_ENDED || video.state.id === VideoState.WAITING_FOR_LIVE) {
|
||||
this.autoplay = false
|
||||
}
|
||||
|
||||
this.p2pEnabled = getParamToggle(params, 'p2p', this.isP2PEnabled(config, video))
|
||||
|
||||
const modeParam = getParamString(params, 'mode')
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ export class VideoFetcher {
|
|||
}
|
||||
if (videoResponse?.status === HttpStatusCode.FORBIDDEN_403) {
|
||||
const res = await videoResponse.json()
|
||||
throw new PeerTubeServerError(res.message, res.code)
|
||||
throw new PeerTubeServerError(res.message || res.detail, res.code)
|
||||
}
|
||||
throw new Error('We cannot fetch the video. Please try again later.')
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ window.addEventListener('load', async () => {
|
|||
const iframe = document.createElement('iframe')
|
||||
iframe.src = isPlaylist
|
||||
? `/video-playlists/embed/${elementId}?api=1`
|
||||
: `/videos/embed/${elementId}?api=1`
|
||||
: `/videos/embed/${elementId}?api=1&waitPasswordFromEmbedAPI=1`
|
||||
|
||||
iframe.sandbox.add('allow-same-origin', 'allow-scripts', 'allow-popups')
|
||||
iframe.sandbox.add('allow-same-origin', 'allow-scripts', 'allow-popups', 'allow-forms')
|
||||
|
||||
const mainElement = document.querySelector('#host')
|
||||
mainElement.appendChild(iframe)
|
||||
|
@ -27,6 +27,8 @@ window.addEventListener('load', async () => {
|
|||
(window as any)['player'] = player
|
||||
|
||||
logger.info('Awaiting player ready...')
|
||||
await player.setVideoPassword('toto')
|
||||
|
||||
await player.ready
|
||||
logger.info('Player is ready.')
|
||||
|
||||
|
@ -41,10 +43,12 @@ window.addEventListener('load', async () => {
|
|||
player.addEventListener(e as PlayerEventType, (param) => logger.info(`PLAYER: event '${e}' received`, { param }))
|
||||
logger.info(`PLAYER: now listening for event '${e}'`)
|
||||
|
||||
player.getCurrentPosition()
|
||||
.then(position => {
|
||||
document.getElementById('playlist-position').innerHTML = position + ''
|
||||
})
|
||||
if (isPlaylist) {
|
||||
player.getCurrentPosition()
|
||||
.then(position => {
|
||||
document.getElementById('playlist-position').innerHTML = position + ''
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let playbackRates: number[] = []
|
||||
|
|
|
@ -154,6 +154,21 @@ Enable embed JavaScript API (see methods below).
|
|||
|
||||
Value must be `0` or `1`.
|
||||
|
||||
### waitPasswordFromEmbedAPI
|
||||
|
||||
**PeerTube >= 6.0**
|
||||
|
||||
If the video requires a password, PeerTube will wait a password provided by `setVideoPassword` method before loading the video.
|
||||
|
||||
Until you provide a password, `player.ready` is not resolved.
|
||||
|
||||
|
||||
## Embed attributes
|
||||
|
||||
### `ready: Promise<void>`
|
||||
|
||||
This promise is resolved when the video is loaded an the player is ready.
|
||||
|
||||
|
||||
## Embed methods
|
||||
|
||||
|
@ -237,6 +252,15 @@ Play previous video in playlist.
|
|||
|
||||
Get current position in playlist (starts from 1).
|
||||
|
||||
|
||||
### `setVideoPassword(): Promise<void>`
|
||||
|
||||
**PeerTube >= 6.0**
|
||||
|
||||
Set the video password so the user doesn't have to manually fill it.
|
||||
`waitPasswordFromEmbedAPI=1` is required in embed URL.
|
||||
|
||||
|
||||
## Embed events
|
||||
|
||||
You can subscribe to events by using `addEventListener()`. See above for details.
|
||||
|
|
Loading…
Reference in New Issue