diff --git a/README.md b/README.md index b0fd8e16..58a642e9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# PeerTube plugin livechat * ALPHA VERSION * +# PeerTube plugin livechat *ALPHA VERSION* Work In Progress diff --git a/client/videowatch-client-plugin.js b/client/videowatch-client-plugin.js index b4d1a319..710def18 100644 --- a/client/videowatch-client-plugin.js +++ b/client/videowatch-client-plugin.js @@ -1,3 +1,16 @@ +"use strict" + +const logger = { + log: (s) => console.log('[peertube-plugin-livechat] ' + s), + info: (s) => console.info('[peertube-plugin-livechat] ' + s), + error: (s) => console.error('[peertube-plugin-livechat] ' + s), + warn: (s) => console.warn('[peertube-plugin-livechat] ' + s) +} + +const videoCache = {} +let lastUUID = null +let settings = {} + function parseUUIDs (s) { if (!s) { return [] @@ -11,49 +24,173 @@ function parseUUIDs (s) { return a.filter(line => line !== '') } +function getIframeUri (uuid) { + if (!settings) { + logger.error('Settings are not initialized, too soon to compute the iframeUri') + return null + } + let iframeUri = settings['chat-uri'] || '' + if (iframeUri === '') { + logger.error('No iframe uri') + return null + } + iframeUri = iframeUri.replace('{{VIDEO_UUID}}', uuid) + if (!/^https?:\/\//.test(iframeUri)) { + logger.error('The webchaturi must begin with https://') + return null + } + return iframeUri +} + +function displayButton (buttons, name, label, callback) { + const button = document.createElement('button') + button.setAttribute('class', 'action-button peertube-plugin-livechat-button-' + name) + button.setAttribute('type', 'button') + button.textContent = label + button.onclick = callback + buttons.prepend(button) +} + +function displayChatButtons (peertubeHelpers, uuid) { + logger.log('Adding buttons in the DOM...') + const p = new Promise((resolve, reject) => { + Promise.all([ + peertubeHelpers.translate('Open chat'), + peertubeHelpers.translate('Open chat in a new window'), + peertubeHelpers.translate('Close chat') + ]).then(labels => { + const labelOpen = labels[0] + const labelOpenBlank = labels[1] + const labelClose = labels[2] + const buttons = document.querySelector('.video-actions') + + displayButton(buttons, 'openblank', labelOpenBlank, () => { + closeChat() + window.open(getIframeUri(uuid)) + }) + displayButton(buttons, 'open', labelOpen, () => openChat()) + displayButton(buttons, 'close', labelClose, () => closeChat()) + + toggleShowHideButtons(null) + }) + resolve() + }) + return p +} + +function toggleShowHideButtons (chatOpened) { + // showing/hiding buttons... + document.querySelectorAll('.peertube-plugin-livechat-button-open') + .forEach(button => button.style.display = (chatOpened === false || chatOpened === null ? 'none' : '')) + + document.querySelectorAll('.peertube-plugin-livechat-button-close') + .forEach(button => button.style.display = (chatOpened === true || chatOpened === null ? 'none' : '')) +} + +function openChat () { + const p = new Promise((resolve, reject) => { + const uuid = lastUUID + if (!uuid) { + logger.log('No current uuid.') + return reject() + } + + logger.info('Trying to load the chat for video ' + uuid + '.') + const iframeUri = getIframeUri(uuid) + if (!iframeUri) { + logger.error('Incorrect iframe uri') + return reject() + } + const additionalStyles = settings['chat-style'] || '' + + logger.info('Opening the chat...') + const videoWrapper = document.querySelector('#video-wrapper') + + // Adding a class=row element + const row = document.createElement('div') + row.setAttribute('class', 'row peertube-plugin-livechat-stuff') + videoWrapper.after(row) + + // Creating the iframe... + const iframe = document.createElement('iframe') + iframe.setAttribute('src', iframeUri) + iframe.setAttribute('class', 'peertube-plugin-livechat peertube-plugin-livechat-stuff') + iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups') + iframe.setAttribute('frameborder', '0') + if (additionalStyles) { + iframe.setAttribute('style', additionalStyles) + } + row.prepend(iframe) + + // showing/hiding buttons... + toggleShowHideButtons(true) + + resolve() + }) +} + +function closeChat () { + document.querySelectorAll('.peertube-plugin-livechat-stuff') + .forEach(dom => dom.remove()) + + // showing/hiding buttons... + toggleShowHideButtons(false) +} + function register ({ registerHook, peertubeHelpers }) { registerHook({ - target: 'action:video-watch.player.loaded', - handler: ({player, videojs, video}) => { + target: 'filter:api.video-watch.video.get.result', + handler: (video) => { + // For now, hooks for action:video-watch... did not receive the video object + // So we store video objects in videoCache + videoCache[video.uuid] = video + lastUUID = video.uuid + return video + } + }) + registerHook({ + target: 'action:video-watch.video.loaded', + handler: () => { peertubeHelpers.getSettings().then(s => { - const liveOn = !!s['chat-all-lives'] - const nonLiveOn = !!s['chat-all-non-lives'] - const uuids = parseUUIDs(s['chat-videos-list']) - const iframeUri = s['chat-uri'] || '' + settings = s + const liveOn = !!settings['chat-all-lives'] + const nonLiveOn = !!settings['chat-all-non-lives'] + const uuids = parseUUIDs(settings['chat-videos-list']) + const iframeUri = settings['chat-uri'] || '' if ( iframeUri === '' ) { - console.log('[peertube-plugin-livechat] no uri, can\'t add chat.') + logger.log('no uri, can\'t add chat.') return } if (!uuids.length && !liveOn && !nonLiveOn) { - console.log('[peertube-plugin-livechat] not activated.') + logger.log('not activated.') + return + } + + logger.log('Checking if this video should have a chat...') + const uuid = lastUUID + const video = videoCache[uuid] + if (!video) { + logger.error('Can\'t find the video ' + uuid + ' in the videoCache') return } - - console.log('[peertube-plugin-livechat] Checking if this video should have a chat...') - const uuid = video.uuid if (uuids.indexOf(uuid) >= 0) { - console.log('[peertube-plugin-livechat] This video is in the list for chats.') + logger.log('This video is in the list for chats.') } else if (video.isLive && liveOn) { - console.log('[peertube-plugin-livechat] This video is live and we want all lives.') + logger.log('This video is live and we want all lives.') } else if (!video.isLive && nonLiveOn) { - console.log('[peertube-plugin-livechat] This video is not live and we want all non-lives.') + logger.log('This video is not live and we want all non-lives.') } else { - console.log('[peertube-plugin-livechat] This video will not have a chat.') + logger.log('This video will not have a chat.') return } - console.info('[peertube-plugin-livechat] Trying to load the chat for video ' + uuid + '.') - const chatUrl = iframeUri.replace('{{VIDEO_UUID}}', uuid) - if (!/^https?:\/\//.test(chatUrl)) { - console.error('[peertube-plugin-livechat] The webchaturi must begin with https://') - return - } - const parent = document.querySelector('.video-info') - const iframe = document.createElement('iframe') - iframe.setAttribute('src', chatUrl) - iframe.setAttribute('class', 'peertube-plugin-livechat') - iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups') - iframe.setAttribute('frameborder', '0') - parent.prepend(iframe) + + displayChatButtons(peertubeHelpers, uuid).then(() => { + if (settings['chat-auto-display']) { + openChat() + } else { + toggleShowHideButtons(false) + } + }) }) } }) diff --git a/languages/fr.json b/languages/fr.json index 76a8eb73..2a9a9479 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -1,3 +1,5 @@ { - "Hello world": "Hello le monde" + "Open chat": "Ouvrir le salon de discussion", + "Open chat in a new window": "Ouvrir le salon de discussion dans une nouvelle fenĂȘtre", + "Close chat": "Fermer le salon de discussion" } diff --git a/main.js b/main.js index 24bd33eb..efb7c020 100644 --- a/main.js +++ b/main.js @@ -7,6 +7,13 @@ async function register ({ videoLicenceManager, videoLanguageManager }) { + registerSetting({ + name: 'chat-auto-display', + label: 'Automatically open the chat', + type: 'input-checkbox', + default: false, + private: false + }) registerSetting({ name: 'chat-all-lives', label: 'Activate chat for all lives', @@ -44,7 +51,15 @@ async function register ({ 'Example : https://my_domain/conversejs.html?room=video_{{VIDEO_UUID}}.', private: false }) - + registerSetting({ + name: 'chat-style', + label: 'Webchat iframe style attribute', + type: 'input-textarea', + default: '', + descriptionHTML: 'Additional styles to be added on the iframe style attribute.
' + + 'Example: height:400px;', + private: false + }) } async function unregister () {