mirror of https://github.com/Chocobozzz/PeerTube
Add ability to set password from embed API
parent
4c07200d64
commit
b13460a10a
|
@ -49,20 +49,6 @@ function isMobile () {
|
||||||
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
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[]) {
|
function videoFileMaxByResolution (files: VideoFile[]) {
|
||||||
let max = files[0]
|
let max = files[0]
|
||||||
|
|
||||||
|
@ -106,7 +92,6 @@ export {
|
||||||
isWebRTCDisabled,
|
isWebRTCDisabled,
|
||||||
isP2PEnabled,
|
isP2PEnabled,
|
||||||
|
|
||||||
buildVideoOrPlaylistEmbed,
|
|
||||||
videoFileMaxByResolution,
|
videoFileMaxByResolution,
|
||||||
videoFileMinByResolution,
|
videoFileMinByResolution,
|
||||||
isMobile,
|
isMobile,
|
||||||
|
|
|
@ -195,6 +195,15 @@ export class PeerTubePlayer {
|
||||||
return this.sendMessage<undefined, number>('getCurrentPosition')
|
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 () {
|
private constructChannel () {
|
||||||
this.channel = Channel.build({
|
this.channel = Channel.build({
|
||||||
window: this.embedElement.contentWindow,
|
window: this.embedElement.contentWindow,
|
||||||
|
|
|
@ -25,16 +25,15 @@ export class PeerTubeEmbedApi {
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
this.constructChannel()
|
this.constructChannel()
|
||||||
this.setupStateTracking()
|
|
||||||
|
|
||||||
// We're ready!
|
|
||||||
|
|
||||||
this.notifyReady()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reInit () {
|
initWithVideo () {
|
||||||
this.disposeStateTracking()
|
this.disposeStateTracking()
|
||||||
this.setupStateTracking()
|
this.setupStateTracking()
|
||||||
|
|
||||||
|
if (!this.isReady) {
|
||||||
|
this.notifyReady()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private get element () {
|
private get element () {
|
||||||
|
@ -44,6 +43,8 @@ export class PeerTubeEmbedApi {
|
||||||
private constructChannel () {
|
private constructChannel () {
|
||||||
const channel = Channel.build({ window: window.parent, origin: '*', scope: this.embed.getScope() })
|
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('play', (txn, params) => this.embed.player.play())
|
||||||
channel.bind('pause', (txn, params) => this.embed.player.pause())
|
channel.bind('pause', (txn, params) => this.embed.player.pause())
|
||||||
channel.bind('seek', (txn, time) => this.embed.player.currentTime(time))
|
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('playNextVideo', (txn, params) => this.embed.playNextPlaylistVideo())
|
||||||
channel.bind('playPreviousVideo', (txn, params) => this.embed.playPreviousPlaylistVideo())
|
channel.bind('playPreviousVideo', (txn, params) => this.embed.playPreviousPlaylistVideo())
|
||||||
channel.bind('getCurrentPosition', (txn, params) => this.embed.getCurrentPlaylistPosition())
|
channel.bind('getCurrentPosition', (txn, params) => this.embed.getCurrentPlaylistPosition())
|
||||||
|
|
||||||
this.channel = channel
|
this.channel = channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ export class PeerTubeEmbed {
|
||||||
private alreadyPlayed = false
|
private alreadyPlayed = false
|
||||||
|
|
||||||
private videoPassword: string
|
private videoPassword: string
|
||||||
|
private videoPasswordFromAPI: string
|
||||||
|
private onVideoPasswordFromAPIResolver: (value: string) => void
|
||||||
private requiresPassword: boolean
|
private requiresPassword: boolean
|
||||||
|
|
||||||
constructor (videoWrapperId: string) {
|
constructor (videoWrapperId: string) {
|
||||||
|
@ -142,17 +144,33 @@ export class PeerTubeEmbed {
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeApi () {
|
private initializeApi () {
|
||||||
if (this.playerOptionsBuilder.hasAPIEnabled()) {
|
if (!this.playerOptionsBuilder.hasAPIEnabled()) return
|
||||||
if (this.api) {
|
if (this.api) return
|
||||||
this.api.reInit()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.api = new PeerTubeEmbedApi(this)
|
this.api = new PeerTubeEmbedApi(this)
|
||||||
this.api.initialize()
|
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 () {
|
async playNextPlaylistVideo () {
|
||||||
|
@ -191,6 +209,9 @@ export class PeerTubeEmbed {
|
||||||
}) {
|
}) {
|
||||||
const { uuid, forceAutoplay } = options
|
const { uuid, forceAutoplay } = options
|
||||||
|
|
||||||
|
this.playerOptionsBuilder.loadCommonParams()
|
||||||
|
this.initializeApi()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
videoResponse,
|
videoResponse,
|
||||||
|
@ -218,7 +239,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
const videoInfoPromise = videoResponse.json()
|
const videoInfoPromise = videoResponse.json()
|
||||||
.then(async (videoInfo: VideoDetails) => {
|
.then(async (videoInfo: VideoDetails) => {
|
||||||
this.playerOptionsBuilder.loadParams(this.config, videoInfo)
|
this.playerOptionsBuilder.loadVideoParams(this.config, videoInfo)
|
||||||
|
|
||||||
const live = videoInfo.isLive
|
const live = videoInfo.isLive
|
||||||
? await this.videoFetcher.loadLive(videoInfo)
|
? await this.videoFetcher.loadLive(videoInfo)
|
||||||
|
@ -287,7 +308,8 @@ export class PeerTubeEmbed {
|
||||||
(window as any)['videojsPlayer'] = this.player
|
(window as any)['videojsPlayer'] = this.player
|
||||||
|
|
||||||
this.buildCSS()
|
this.buildCSS()
|
||||||
this.initializeApi()
|
|
||||||
|
if (this.api) this.api.initWithVideo()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.alreadyInitialized = true
|
this.alreadyInitialized = true
|
||||||
|
@ -360,10 +382,30 @@ export class PeerTubeEmbed {
|
||||||
if (incorrectPassword === null) return false
|
if (incorrectPassword === null) return false
|
||||||
|
|
||||||
this.requiresPassword = true
|
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({
|
this.videoPassword = await this.playerHTML.askVideoPassword({
|
||||||
incorrectPassword,
|
incorrectPassword,
|
||||||
translations: await this.translationsPromise
|
translations: await this.translationsPromise
|
||||||
})
|
})
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ export class PlayerOptionsBuilder {
|
||||||
private bigPlayBackgroundColor: string
|
private bigPlayBackgroundColor: string
|
||||||
private foregroundColor: string
|
private foregroundColor: string
|
||||||
|
|
||||||
|
private waitPasswordFromEmbedAPI = false
|
||||||
|
|
||||||
private mode: PlayerMode
|
private mode: PlayerMode
|
||||||
private scope = 'peertube'
|
private scope = 'peertube'
|
||||||
|
|
||||||
|
@ -106,18 +108,16 @@ export class PlayerOptionsBuilder {
|
||||||
return this.scope
|
return this.scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mustWaitPasswordFromEmbedAPI () {
|
||||||
|
return this.waitPasswordFromEmbedAPI
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
loadParams (config: HTMLServerConfig, video: VideoDetails) {
|
loadCommonParams () {
|
||||||
try {
|
try {
|
||||||
const params = new URL(window.location.toString()).searchParams
|
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.controls = getParamToggle(params, 'controls', true)
|
||||||
this.controlBar = getParamToggle(params, 'controlBar', true)
|
this.controlBar = getParamToggle(params, 'controlBar', true)
|
||||||
|
|
||||||
|
@ -125,9 +125,9 @@ export class PlayerOptionsBuilder {
|
||||||
this.loop = getParamToggle(params, 'loop', false)
|
this.loop = getParamToggle(params, 'loop', false)
|
||||||
this.title = getParamToggle(params, 'title', true)
|
this.title = getParamToggle(params, 'title', true)
|
||||||
this.enableApi = getParamToggle(params, 'api', this.enableApi)
|
this.enableApi = getParamToggle(params, 'api', this.enableApi)
|
||||||
|
this.waitPasswordFromEmbedAPI = getParamToggle(params, 'waitPasswordFromEmbedAPI', this.waitPasswordFromEmbedAPI)
|
||||||
this.warningTitle = getParamToggle(params, 'warningTitle', true)
|
this.warningTitle = getParamToggle(params, 'warningTitle', true)
|
||||||
this.peertubeLink = getParamToggle(params, 'peertubeLink', true)
|
this.peertubeLink = getParamToggle(params, 'peertubeLink', true)
|
||||||
this.p2pEnabled = getParamToggle(params, 'p2p', this.isP2PEnabled(config, video))
|
|
||||||
|
|
||||||
this.scope = getParamString(params, 'scope', this.scope)
|
this.scope = getParamString(params, 'scope', this.scope)
|
||||||
this.subtitle = getParamString(params, 'subtitle')
|
this.subtitle = getParamString(params, 'subtitle')
|
||||||
|
@ -137,6 +137,22 @@ export class PlayerOptionsBuilder {
|
||||||
|
|
||||||
this.bigPlayBackgroundColor = getParamString(params, 'bigPlayBackgroundColor')
|
this.bigPlayBackgroundColor = getParamString(params, 'bigPlayBackgroundColor')
|
||||||
this.foregroundColor = getParamString(params, 'foregroundColor')
|
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')
|
const modeParam = getParamString(params, 'mode')
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class VideoFetcher {
|
||||||
}
|
}
|
||||||
if (videoResponse?.status === HttpStatusCode.FORBIDDEN_403) {
|
if (videoResponse?.status === HttpStatusCode.FORBIDDEN_403) {
|
||||||
const res = await videoResponse.json()
|
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.')
|
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')
|
const iframe = document.createElement('iframe')
|
||||||
iframe.src = isPlaylist
|
iframe.src = isPlaylist
|
||||||
? `/video-playlists/embed/${elementId}?api=1`
|
? `/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')
|
const mainElement = document.querySelector('#host')
|
||||||
mainElement.appendChild(iframe)
|
mainElement.appendChild(iframe)
|
||||||
|
@ -27,6 +27,8 @@ window.addEventListener('load', async () => {
|
||||||
(window as any)['player'] = player
|
(window as any)['player'] = player
|
||||||
|
|
||||||
logger.info('Awaiting player ready...')
|
logger.info('Awaiting player ready...')
|
||||||
|
await player.setVideoPassword('toto')
|
||||||
|
|
||||||
await player.ready
|
await player.ready
|
||||||
logger.info('Player is 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 }))
|
player.addEventListener(e as PlayerEventType, (param) => logger.info(`PLAYER: event '${e}' received`, { param }))
|
||||||
logger.info(`PLAYER: now listening for event '${e}'`)
|
logger.info(`PLAYER: now listening for event '${e}'`)
|
||||||
|
|
||||||
player.getCurrentPosition()
|
if (isPlaylist) {
|
||||||
.then(position => {
|
player.getCurrentPosition()
|
||||||
document.getElementById('playlist-position').innerHTML = position + ''
|
.then(position => {
|
||||||
})
|
document.getElementById('playlist-position').innerHTML = position + ''
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let playbackRates: number[] = []
|
let playbackRates: number[] = []
|
||||||
|
|
|
@ -154,6 +154,21 @@ Enable embed JavaScript API (see methods below).
|
||||||
|
|
||||||
Value must be `0` or `1`.
|
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
|
## Embed methods
|
||||||
|
|
||||||
|
@ -237,6 +252,15 @@ Play previous video in playlist.
|
||||||
|
|
||||||
Get current position in playlist (starts from 1).
|
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
|
## Embed events
|
||||||
|
|
||||||
You can subscribe to events by using `addEventListener()`. See above for details.
|
You can subscribe to events by using `addEventListener()`. See above for details.
|
||||||
|
|
Loading…
Reference in New Issue