New fullscreen chat WIP:
* Fullscreen chat: now uses a custom page (in other words: when opening the chat in a new tab, you will have the Peertube menu). WIP * some code refactoring (getBaseRoute moved to util/uri, ...)
This commit is contained in:
parent
17bd8a0716
commit
bd695bdb27
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
TODO: replace commit_id by a tag in build-conversejs
|
TODO: replace commit_id by a tag in build-conversejs
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
* #143: User colors: implementing [XEP-0392](https://xmpp.org/extensions/xep-0392.html) to have random colors on users nicknames
|
* #143: User colors: implementing [XEP-0392](https://xmpp.org/extensions/xep-0392.html) to have random colors on users nicknames
|
||||||
|
* Fullscreen chat: now uses a custom page (in other words: when opening the chat in a new tab, you will have the Peertube menu).
|
||||||
|
|
||||||
## 8.4.0
|
## 8.4.0
|
||||||
|
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
||||||
import type { Video } from '@peertube/peertube-types'
|
import type { Video } from '@peertube/peertube-types'
|
||||||
import type { ProsodyListRoomsResult } from 'shared/lib/types'
|
import type { ProsodyListRoomsResult } from 'shared/lib/types'
|
||||||
|
import { getBaseRoute } from './utils/uri'
|
||||||
|
|
||||||
interface ActionPluginSettingsParams {
|
interface ActionPluginSettingsParams {
|
||||||
npmName: string
|
npmName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function register ({ registerHook, registerSettingsScript, peertubeHelpers }: RegisterClientOptions): void {
|
function register (clientOptions: RegisterClientOptions): void {
|
||||||
function getBaseRoute (): string {
|
const { registerHook, registerSettingsScript, peertubeHelpers } = clientOptions
|
||||||
// NB: this will come with Peertube > 3.2.1 (3.3.0?)
|
|
||||||
if (peertubeHelpers.getBaseRouterRoute) {
|
|
||||||
return peertubeHelpers.getBaseRouterRoute()
|
|
||||||
}
|
|
||||||
// We are guessing the route with the correct plugin version with this trick:
|
|
||||||
const staticBase = peertubeHelpers.getBaseStaticRoute()
|
|
||||||
// we can't use '/plugins/livechat/router', because the loaded html page needs correct relative paths.
|
|
||||||
return staticBase.replace(/\/static.*$/, '/router')
|
|
||||||
}
|
|
||||||
|
|
||||||
registerHook({
|
registerHook({
|
||||||
target: 'action:admin-plugin-settings.init',
|
target: 'action:admin-plugin-settings.init',
|
||||||
@ -30,7 +22,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
|||||||
diagButtons.forEach(diagButton => {
|
diagButtons.forEach(diagButton => {
|
||||||
if (diagButton.hasAttribute('href')) { return }
|
if (diagButton.hasAttribute('href')) { return }
|
||||||
// TODO: use a modal instead of a target=_blank
|
// TODO: use a modal instead of a target=_blank
|
||||||
diagButton.setAttribute('href', getBaseRoute() + '/settings/diagnostic')
|
diagButton.setAttribute('href', getBaseRoute(clientOptions) + '/settings/diagnostic')
|
||||||
diagButton.setAttribute('target', '_blank')
|
diagButton.setAttribute('target', '_blank')
|
||||||
})
|
})
|
||||||
console.log('[peertube-plugin-livechat] Initializing prosody-list-rooms button')
|
console.log('[peertube-plugin-livechat] Initializing prosody-list-rooms button')
|
||||||
@ -71,7 +63,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
|||||||
container.textContent = '...'
|
container.textContent = '...'
|
||||||
listRoomsButton.after(container)
|
listRoomsButton.after(container)
|
||||||
|
|
||||||
const response = await fetch(getBaseRoute() + '/webchat/prosody-list-rooms', {
|
const response = await fetch(getBaseRoute(clientOptions) + '/webchat/prosody-list-rooms', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: peertubeHelpers.getAuthHeader()
|
headers: peertubeHelpers.getAuthHeader()
|
||||||
})
|
})
|
||||||
@ -168,7 +160,8 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
|||||||
// Here we have a channel chat room
|
// Here we have a channel chat room
|
||||||
// The backend should have added informations here
|
// The backend should have added informations here
|
||||||
// (because the Peertube API can't work with channelId...)
|
// (because the Peertube API can't work with channelId...)
|
||||||
const href = getBaseRoute() + '/webchat/room/' + encodeURIComponent(localpart) + '?forcetype=1'
|
const href = getBaseRoute(clientOptions) +
|
||||||
|
'/webchat/room/' + encodeURIComponent(localpart) + '?forcetype=1'
|
||||||
if (room.channel?.name) {
|
if (room.channel?.name) {
|
||||||
aEl.href = href // here we know that the channel still exists, so we can open the webchat.
|
aEl.href = href // here we know that the channel still exists, so we can open the webchat.
|
||||||
const aVideoEl = document.createElement('a')
|
const aVideoEl = document.createElement('a')
|
||||||
@ -183,7 +176,8 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
|||||||
} else if (/^[a-zA-A0-9-]+$/.test(localpart)) {
|
} else if (/^[a-zA-A0-9-]+$/.test(localpart)) {
|
||||||
// localpart must be a video uuid.
|
// localpart must be a video uuid.
|
||||||
const uuid = localpart
|
const uuid = localpart
|
||||||
const href = getBaseRoute() + '/webchat/room/' + encodeURIComponent(uuid) + '?forcetype=1'
|
const href = getBaseRoute(clientOptions) +
|
||||||
|
'/webchat/room/' + encodeURIComponent(uuid) + '?forcetype=1'
|
||||||
const p = fetch('/api/v1/videos/' + uuid, {
|
const p = fetch('/api/v1/videos/' + uuid, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: peertubeHelpers.getAuthHeader()
|
headers: peertubeHelpers.getAuthHeader()
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
||||||
|
import type { InitConverseJSParams } from 'shared/lib/types'
|
||||||
import { renderConfigurationHome } from './templates/home'
|
import { renderConfigurationHome } from './templates/home'
|
||||||
import { renderConfigurationChannel } from './templates/channel'
|
import { renderConfigurationChannel } from './templates/channel'
|
||||||
|
import { getBaseRoute } from '../../utils/uri'
|
||||||
|
import { loadConverseJS } from '../../utils/conversejs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers stuff related to the user's configuration pages.
|
* Registers stuff related to the user's configuration pages.
|
||||||
@ -12,6 +15,42 @@ async function registerConfiguration (clientOptions: RegisterClientOptions): Pro
|
|||||||
const settings = await peertubeHelpers.getSettings()
|
const settings = await peertubeHelpers.getSettings()
|
||||||
if (settings['disable-channel-configuration']) { return }
|
if (settings['disable-channel-configuration']) { return }
|
||||||
|
|
||||||
|
registerClientRoute({
|
||||||
|
route: 'livechat/room',
|
||||||
|
onMount: async ({ rootEl }) => {
|
||||||
|
try {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
|
const roomKey = urlParams.get('room')
|
||||||
|
if (!roomKey) {
|
||||||
|
throw new Error('missing room parameter')
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
getBaseRoute(clientOptions) + '/api/configuration/room/' + encodeURIComponent(roomKey),
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
headers: peertubeHelpers.getAuthHeader()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Can\'t get channel configuration options.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const converseJSParams: InitConverseJSParams = await (response).json()
|
||||||
|
await loadConverseJS(converseJSParams)
|
||||||
|
|
||||||
|
rootEl.innerHTML = `<div class="converse-fullscreen theme-peertube">
|
||||||
|
<div id="conversejs-bg" class="theme-peertube">
|
||||||
|
</div>`
|
||||||
|
|
||||||
|
window.initConverse(converseJSParams)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[peertube-plugin-livechat] ' + (err as string))
|
||||||
|
rootEl.innerText = await peertubeHelpers.translate(LOC_NOT_FOUND)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
registerClientRoute({
|
registerClientRoute({
|
||||||
route: 'livechat/configuration',
|
route: 'livechat/configuration',
|
||||||
onMount: async ({ rootEl }) => {
|
onMount: async ({ rootEl }) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
||||||
import type { ChannelConfiguration, ChannelConfigurationOptions } from 'shared/lib/types'
|
import type { ChannelConfiguration, ChannelConfigurationOptions } from 'shared/lib/types'
|
||||||
import { getBaseRoute } from '../../../../videowatch/uri'
|
import { getBaseRoute } from '../../../../utils/uri'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the data that can be feed into the template view
|
* Returns the data that can be feed into the template view
|
||||||
|
58
client/utils/conversejs.ts
Normal file
58
client/utils/conversejs.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import type { InitConverseJSParams } from 'shared/lib/types'
|
||||||
|
|
||||||
|
// declare global {
|
||||||
|
// interface Window {
|
||||||
|
// converse?: {
|
||||||
|
// initialize: (args: any) => void
|
||||||
|
// plugins: {
|
||||||
|
// add: (name: string, plugin: any) => void
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
converse?: any
|
||||||
|
initConverse: Function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadCSS (url: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const css = document.createElement('link')
|
||||||
|
css.onerror = () => reject(new URIError(`CSS ${url} didn't load correctly.`))
|
||||||
|
css.onload = () => resolve()
|
||||||
|
css.setAttribute('type', 'text/css')
|
||||||
|
css.setAttribute('rel', 'stylesheet')
|
||||||
|
css.setAttribute('href', url)
|
||||||
|
document.head.appendChild(css)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadScript (url: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.onerror = () => reject(new URIError(`Script ${url} didn't load correctly.`))
|
||||||
|
script.onload = () => resolve()
|
||||||
|
script.async = true
|
||||||
|
script.src = url
|
||||||
|
document.head.appendChild(script)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadConverseJS (converseJSParams: InitConverseJSParams): Promise<void> {
|
||||||
|
if (!window.converse) {
|
||||||
|
await Promise.all([
|
||||||
|
loadCSS(converseJSParams.staticBaseUrl + 'conversejs/converse.min.css'),
|
||||||
|
loadScript(converseJSParams.staticBaseUrl + 'conversejs/converse.min.js')
|
||||||
|
])
|
||||||
|
}
|
||||||
|
if (!window.initConverse) {
|
||||||
|
await loadScript(converseJSParams.staticBaseUrl + 'static/builtin.js')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
loadConverseJS
|
||||||
|
}
|
18
client/utils/uri.ts
Normal file
18
client/utils/uri.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
||||||
|
|
||||||
|
function getBaseRoute ({ peertubeHelpers }: RegisterClientOptions, permanent: boolean = false): string {
|
||||||
|
if (permanent) {
|
||||||
|
return '/plugins/livechat/router'
|
||||||
|
}
|
||||||
|
// NB: this will come with Peertube > 3.2.1 (3.3.0?)
|
||||||
|
if (peertubeHelpers.getBaseRouterRoute) {
|
||||||
|
return peertubeHelpers.getBaseRouterRoute()
|
||||||
|
}
|
||||||
|
// We are guessing the route with the correct plugin version with this trick:
|
||||||
|
const staticBase = peertubeHelpers.getBaseStaticRoute()
|
||||||
|
return staticBase.replace(/\/static.*$/, '/router')
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getBaseRoute
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
||||||
import type { Video } from '@peertube/peertube-types'
|
import type { Video } from '@peertube/peertube-types'
|
||||||
import { AutoColors, isAutoColorsAvailable } from 'shared/lib/autocolors'
|
import { AutoColors, isAutoColorsAvailable } from 'shared/lib/autocolors'
|
||||||
|
import { getBaseRoute } from '../utils/uri'
|
||||||
import { logger } from './logger'
|
import { logger } from './logger'
|
||||||
import { computeAutoColors } from './colors'
|
import { computeAutoColors } from './colors'
|
||||||
|
|
||||||
@ -11,19 +12,6 @@ interface UriOptions {
|
|||||||
permanent?: boolean
|
permanent?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBaseRoute ({ peertubeHelpers }: RegisterClientOptions, permanent: boolean = false): string {
|
|
||||||
if (permanent) {
|
|
||||||
return '/plugins/livechat/router'
|
|
||||||
}
|
|
||||||
// NB: this will come with Peertube > 3.2.1 (3.3.0?)
|
|
||||||
if (peertubeHelpers.getBaseRouterRoute) {
|
|
||||||
return peertubeHelpers.getBaseRouterRoute()
|
|
||||||
}
|
|
||||||
// We are guessing the route with the correct plugin version with this trick:
|
|
||||||
const staticBase = peertubeHelpers.getBaseStaticRoute()
|
|
||||||
return staticBase.replace(/\/static.*$/, '/router')
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIframeUri (
|
function getIframeUri (
|
||||||
registerOptions: RegisterClientOptions, settings: any, video: Video, uriOptions: UriOptions = {}
|
registerOptions: RegisterClientOptions, settings: any, video: Video, uriOptions: UriOptions = {}
|
||||||
): string | null {
|
): string | null {
|
||||||
@ -98,7 +86,6 @@ export type {
|
|||||||
UriOptions
|
UriOptions
|
||||||
}
|
}
|
||||||
export {
|
export {
|
||||||
getBaseRoute,
|
|
||||||
getIframeUri,
|
getIframeUri,
|
||||||
getXMPPAddr
|
getXMPPAddr
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { RegisterServerOptions, MVideoThumbnail, SettingEntries } from '@peertube/peertube-types'
|
import type { RegisterServerOptions, MVideoThumbnail, SettingEntries } from '@peertube/peertube-types'
|
||||||
import type { ConverseJSTheme, InitConverseJSParams } from '../../../shared/lib/types'
|
import type { ConverseJSTheme, InitConverseJSParams, InitConverseJSParamsError } from '../../../shared/lib/types'
|
||||||
import type { RegisterServerOptionsV5 } from '../helpers'
|
import type { RegisterServerOptionsV5 } from '../helpers'
|
||||||
import type { LiveChatJSONLDAttributeV1 } from '../federation/types'
|
import type { LiveChatJSONLDAttributeV1 } from '../federation/types'
|
||||||
import { getChannelInfosById, getChannelNameById } from '../database/channel'
|
import { getChannelInfosById, getChannelNameById } from '../database/channel'
|
||||||
@ -11,12 +11,6 @@ import { getBaseRouterRoute, getBaseStaticRoute } from '../helpers'
|
|||||||
import { getProsodyDomain } from '../prosody/config/domain'
|
import { getProsodyDomain } from '../prosody/config/domain'
|
||||||
import { getBoshUri, getWSUri } from '../uri/webchat'
|
import { getBoshUri, getWSUri } from '../uri/webchat'
|
||||||
|
|
||||||
interface InitConverseJSParamsError {
|
|
||||||
isError: true
|
|
||||||
code: 404 | 403 | 500
|
|
||||||
message: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GetConverseJSParamsParams {
|
interface GetConverseJSParamsParams {
|
||||||
readonly?: boolean | 'noscroll'
|
readonly?: boolean | 'noscroll'
|
||||||
transparent?: boolean
|
transparent?: boolean
|
||||||
|
@ -10,10 +10,24 @@ import {
|
|||||||
storeChannelConfigurationOptions
|
storeChannelConfigurationOptions
|
||||||
} from '../../configuration/channel/storage'
|
} from '../../configuration/channel/storage'
|
||||||
import { sanitizeChannelConfigurationOptions } from '../../configuration/channel/sanitize'
|
import { sanitizeChannelConfigurationOptions } from '../../configuration/channel/sanitize'
|
||||||
|
import { getConverseJSParams } from '../../../lib/conversejs/params'
|
||||||
|
|
||||||
async function initConfigurationApiRouter (options: RegisterServerOptions, router: Router): Promise<void> {
|
async function initConfigurationApiRouter (options: RegisterServerOptions, router: Router): Promise<void> {
|
||||||
const logger = options.peertubeHelpers.logger
|
const logger = options.peertubeHelpers.logger
|
||||||
|
|
||||||
|
router.get('/configuration/room/:roomKey', asyncMiddleware(
|
||||||
|
async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
|
||||||
|
const roomKey = req.params.roomKey
|
||||||
|
const initConverseJSParam = await getConverseJSParams(options, roomKey, {})
|
||||||
|
if (('isError' in initConverseJSParam) && initConverseJSParam.isError) {
|
||||||
|
res.sendStatus(initConverseJSParam.code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.status(200)
|
||||||
|
res.json(initConverseJSParam)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
router.get('/configuration/channel/:channelId', asyncMiddleware([
|
router.get('/configuration/channel/:channelId', asyncMiddleware([
|
||||||
checkConfigurationEnabledMiddleware(options),
|
checkConfigurationEnabledMiddleware(options),
|
||||||
getCheckConfigurationChannelMiddleware(options),
|
getCheckConfigurationChannelMiddleware(options),
|
||||||
|
@ -21,6 +21,12 @@ interface InitConverseJSParams {
|
|||||||
forceDefaultHideMucParticipants?: boolean
|
forceDefaultHideMucParticipants?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface InitConverseJSParamsError {
|
||||||
|
isError: true
|
||||||
|
code: 404 | 403 | 500
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
interface ProsodyListRoomsResultError {
|
interface ProsodyListRoomsResultError {
|
||||||
ok: false
|
ok: false
|
||||||
error: string
|
error: string
|
||||||
@ -87,6 +93,7 @@ interface ChannelConfiguration {
|
|||||||
export type {
|
export type {
|
||||||
ConverseJSTheme,
|
ConverseJSTheme,
|
||||||
InitConverseJSParams,
|
InitConverseJSParams,
|
||||||
|
InitConverseJSParamsError,
|
||||||
ProsodyListRoomsResult,
|
ProsodyListRoomsResult,
|
||||||
ProsodyListRoomsResultRoom,
|
ProsodyListRoomsResultRoom,
|
||||||
ChannelInfos,
|
ChannelInfos,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user