20 Commits

Author SHA1 Message Date
21ecdf77c6 I don't think it worked 2024-08-05 21:49:12 -04:00
cfe2ac0607 maybeee?? 2024-08-05 21:46:02 -04:00
74566a895a fix duplicate requires 2024-08-05 21:28:09 -04:00
587334a3e1 separate the nigbot generation and normal avatar generation 2024-08-05 21:26:11 -04:00
30cce2ec03 probably fix issue with Nigbot avatar generation 2024-08-05 21:10:10 -04:00
24f48788ab wheee 2024-08-05 21:04:55 -04:00
bed00aa4c5 niggers are so black tbh 2024-08-05 20:44:04 -04:00
fd16c95b8f add nigbot build job 2024-08-05 20:29:46 -04:00
39f6e4c637 maybe fr fr? 2024-08-05 20:12:46 -04:00
f8c34213cb maybe fr fr fix it? 2024-08-05 19:46:09 -04:00
eb889711f5 fix invalid-avatar set 2024-08-05 19:32:57 -04:00
8dd6ed7888 hopefully fix avatar generation for nigbot avatar 2024-08-05 19:25:45 -04:00
0cc38ac575 update index.md 2024-08-05 19:20:28 -04:00
cde9b3f74a add options in config 2024-08-05 17:54:22 -04:00
75245c0858 add nigbot avatar 2024-08-05 17:42:01 -04:00
be59329581 from 30 to 800 kb for emojis 2024-08-01 21:17:31 -04:00
6d103af5c9 Merge tag 'v10.3.3' of https://github.com/JohnXLivingston/peertube-plugin-livechat
v10.3.3

Minor changes and fixes:

* Fix #481: Moderation bot was not able to connect when remote chat was disabled.
* Some cleaning in code generating Prosody configuration file.
2024-07-29 19:44:23 -04:00
e57d39c8ab Fix #481:
* Moderation bot was not able to connect when remote chat was disabled.
* Some cleaning in code generating Prosody configuration file.
* Bump version 10.3.3
2024-07-25 12:09:55 +02:00
9526a19aab what the fuck 2024-07-20 22:45:58 -04:00
db1993f97e Fix #477: ended polls never disappear when archiving is disabled (and no more than 20 new messages). 2024-07-18 10:24:54 +02:00
55 changed files with 210 additions and 314 deletions

View File

@ -1,10 +1,17 @@
# Changelog
## 11.0.0 (Not Released Yet)
## 10.3.3
### New features
### Minor changes and fixes
* Updating ConverseJS, to use upstream (v11 WIP). This comes with many improvments and new features.
* Fix #481: Moderation bot was not able to connect when remote chat was disabled.
* Some cleaning in code generating Prosody configuration file.
## 10.3.2
### Minor changes and fixes
* Fix #477: ended polls never disappear when archiving is disabled (and no more than 20 new messages).
## 10.3.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
#peertube-plugin-livechat-container {
#peertube-plugin-livechat-container {
display: flex;
flex-direction: column;
height: 100%;
@ -28,7 +28,7 @@
height: 100%;
converse-muc {
min-height: max(58vh, 400px);
min-height: max(59vh, 400px);
}
}

View File

@ -58,6 +58,9 @@ const avatarPartsDef = {
fur: 10,
eyes: 15,
mouth: 10
},
'nctv': {
body: null,
}
}
@ -169,6 +172,23 @@ async function generateAvatars (part) {
}
}
const generateNigbotAvatar = async () => {
console.log('Starting generating nigbot avatar');
const inputDir = './assets/images/avatars/nctv/';
const outputDir = './dist/server/avatars/nctv/';
fs.mkdirSync(outputDir, { recursive: true });
const buff = await sharp(path.join(inputDir, 'nigbot.png')).toBuffer();
await sharp(buff)
.resize(60, 60)
.png({ palette: true })
.toFile(path.join(outputDir, '1.png'));
}
async function generateBotsAvatars () {
{
// Moderation bot avatar: choosing some parts, and turning it so it is facing left.
@ -294,6 +314,21 @@ async function generateBotsAvatars () {
})
.toFile(path.join(botOutputDir, '1.png'))
}
{
// Nigbot avatar for users
const inputDir = './assets/images/avatars/nctv'
const botOutputDir = './dist/server/bot_avatars/nctv/'
fs.mkdirSync(botOutputDir, { recursive: true })
const buff = await sharp(path.join(inputDir, 'nigbot.png'))
.toBuffer()
await sharp(buff)
// .resize(60, 60)
.png()
.toFile(path.join(botOutputDir, '1.png'))
}
}
if (isMainThread) {
@ -337,6 +372,9 @@ if (isMainThread) {
throw err
}
)
} else if (part === 'nctv') {
generateNigbotAvatar();
parentPort.postMessage('done');
} else {
generateAvatars(part).then(
() => {

View File

@ -15,21 +15,32 @@ set -x
# Set CONVERSE_VERSION and CONVERSE_REPO to select which repo and tag/commit/branch use.
# Defaults values:
CONVERSE_VERSION="v11.0.0"
CONVERSE_VERSION="v10.1.6"
CONVERSE_REPO="https://github.com/conversejs/converse.js.git"
# You can eventually set CONVERSE_COMMIT to a specific commit ID, if you want to apply some patches.
# 2024-07-15: using Converse upstream (v11 WIP).
CONVERSE_COMMIT="46313ad92c1a861bcb50b9653859cfa9a960ae4a"
# 2024-07-15, FIXME: the following commit includes a quick fix for Converse/#3443, waiting for upstream to be fixed.
CONVERSE_COMMIT="7d65ef8d30a1f3949dbc590b6d27a9d786bf819f"
CONVERSE_COMMIT=""
# It is possible to use another repository, if we want some customization that are not upstream (yet):
# CONVERSE_VERSION="livechat"
# # CONVERSE_COMMIT="4402fcc3fc60f6c9334f86528c33a0b463371d12"
# 2014-01-16: we are using a custom version, to wait for some PR to be apply upstream.
# This version includes following changes:
# - #converse.js/3300: Adding the maxWait option for `debouncedPruneHistory`
# - #converse.js/3302: debounce MUC sidebar rendering
# - Fix: refresh the MUC sidebar when participants collection is sorted
# - Fix: MUC occupant list does not sort itself on nicknames or roles changes
# - Fix inconsistency between browsers on textarea outlines
# - Fix: room information not correctly refreshed when modifications are made by other users
# This version already includes following changes that will not be merged in ConverseJS upstream:
# - Don't load vCards for all room occupants when the right menu is closed
# - Changing the default avatar, for something very light (to mitigate blinking effect when vCards are loaded)
# - Custom settings livechat_load_all_vcards for the readonly mode
# - Adding "users" icon in the menu toggle button
# - Removing unecessary plugins: headless/pubsub, minimize, notifications, profile, omemo, push, roomlist, dragresize.
# - Destroy room: remove the challenge, and the new JID
# - New config option [colorize_username](https://conversejs.org/docs/html/configuration.html#colorize_username)
# - New loadEmojis hook, to customize emojis at runtime.
# - Fix custom emojis path when assets_path is not the default path.
CONVERSE_VERSION="livechat-10.1.0"
# CONVERSE_COMMIT="4402fcc3fc60f6c9334f86528c33a0b463371d12"
CONVERSE_REPO="https://github.com/JohnXLivingston/converse.js"
# 2024-07-15, fix MUC save.
CONVERSE_COMMIT="58c682b9ba09038beb961e9d8f804c270408ea69"
CONVERSE_COMMIT="bbee0e4e8d2dc43636385cf4cca34f3604f59520"
rootdir="$(pwd)"
src_dir="$rootdir/conversejs"

View File

@ -8,11 +8,12 @@
* @description This files will override the original ConverseJS index.js file.
*/
import '@converse/headless'
import './i18n/index.js'
import 'shared/registry.js'
import { CustomElement } from 'shared/components/element'
import { VIEW_PLUGINS } from './shared/constants.js'
import { _converse, converse } from '@converse/headless'
import { _converse, converse } from '@converse/headless/core'
import 'shared/styles/index.scss'
@ -49,9 +50,6 @@ import '../custom/plugins/terms/index.js'
import '../custom/plugins/poll/index.js'
/* END: Removable components */
// Running some specific livechat patches:
import '../custom/livechat-patch-vcard.js'
import { CORE_PLUGINS } from './headless/shared/constants.js'
import { ROOM_FEATURES } from './headless/plugins/muc/constants.js'
// We must add our custom plugins to CORE_PLUGINS (so it is white listed):
@ -63,7 +61,7 @@ CORE_PLUGINS.push('livechat-converse-poll')
// (see headless/plugins/muc, getDiscoInfoFeatures, which loops on this const)
ROOM_FEATURES.push('x_peertubelivechat_mute_anonymous')
_converse.exports.CustomElement = CustomElement
_converse.CustomElement = CustomElement
const initialize = converse.initialize

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { api } from '@converse/headless/index.js'
import { api } from '@converse/headless/core.js'
import { CustomElement } from 'shared/components/element.js'
import { tplExternalLoginModal } from 'templates/livechat-external-login-modal.js'
import { __ } from 'i18n'

View File

@ -1,61 +0,0 @@
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
//
// SPDX-License-Identifier: AGPL-3.0-only
// Here we are patching the vCard plugin, to add some specific optimizations.
import { _converse, api } from '@converse/headless/index.js'
import {
onOccupantAvatarChanged,
setVCardOnModel,
setVCardOnOccupant
} from '@converse/headless/plugins/vcard/utils.js'
const pluginDefinition = _converse.pluggable.plugins['converse-vcard']
const originalInitialize = pluginDefinition.initialize
pluginDefinition.initialize = function initialize () {
const previousListeners = _converse._events.chatRoomInitialized ?? []
originalInitialize.apply(this)
_converse.api.settings.extend({
livechat_load_all_vcards: false
})
// Now we must detect the new chatRoomInitialized listener, and remove it:
const listenersToRemove = []
for (const def of _converse._events.chatRoomInitialized ?? []) {
if (def.callback && !previousListeners.includes(def.callback)) {
listenersToRemove.push(def.callback)
}
}
for (const callback of listenersToRemove) {
console.debug('Livechat patching vcard: we must remove this listener', callback)
api.listen.not('chatRoomInitialized', callback)
}
// Adding the new listener:
api.listen.on('chatRoomInitialized', (m) => {
console.debug('Patched version of the vcard chatRoomInitialized event.')
setVCardOnModel(m)
// loadAll: when in readonly mode (ie: OBS integration), always load all avatars.
const loadAll = api.settings.get('livechat_load_all_vcards') === true
let hiddenOccupants = m.get('hidden_occupants')
if (hiddenOccupants !== true || loadAll) {
m.occupants.forEach(setVCardOnOccupant)
}
m.listenTo(m.occupants, 'add', (occupant) => {
if (hiddenOccupants !== true || loadAll) {
setVCardOnOccupant(occupant)
}
})
m.on('change:hidden_occupants', () => {
hiddenOccupants = m.get('hidden_occupants')
if (hiddenOccupants !== true || loadAll) {
m.occupants.forEach(setVCardOnOccupant)
}
})
m.listenTo(m.occupants, 'change:image_hash', o => onOccupantAvatarChanged(o))
})
}

View File

@ -4,7 +4,7 @@
import { XMLNS_POLL } from '../constants.js'
import { tplPollForm } from '../templates/poll-form.js'
import { CustomElement } from 'shared/components/element.js'
import { converse, api, parsers } from '@converse/headless'
import { converse, api } from '@converse/headless/core'
import { webForm2xForm } from '@converse/headless/utils/form'
import { __ } from 'i18n'
import '../styles/poll-form.scss'
@ -18,6 +18,7 @@ export default class MUCPollFormView extends CustomElement {
return {
model: { type: Object, attribute: true },
modal: { type: Object, attribute: true },
form_fields: { type: Object, attribute: false },
alert_message: { type: Object, attribute: false },
title: { type: String, attribute: false },
instructions: { type: String, attribute: false }
@ -26,8 +27,6 @@ export default class MUCPollFormView extends CustomElement {
_fieldTranslationMap = new Map()
xform = undefined
async initialize () {
this.alert_message = undefined
if (!this.model) {
@ -37,18 +36,20 @@ export default class MUCPollFormView extends CustomElement {
try {
this._initFieldTranslations()
const stanza = await this._fetchPollForm()
const xform = parsers.parseXForm(stanza)
const query = stanza.querySelector('query')
const xform = sizzle(`x[xmlns="${Strophe.NS.XFORM}"]`, query)[0]
if (!xform) {
throw Error('Missing xform in stanza')
}
xform.fields?.map(f => this._translateField(f))
this.xform = xform
// eslint-disable-next-line no-undef
this.title = __(LOC_poll_title) // xform.querySelector('title')?.textContent ?? ''
// eslint-disable-next-line no-undef
this.instructions = __(LOC_poll_instructions) // xform.querySelector('instructions')?.textContent ?? ''
this.form_fields = Array.from(xform.querySelectorAll('field')).map(field => {
this._translateField(field)
return u.xForm2TemplateResult(field, stanza)
})
} catch (err) {
console.error(err)
this.alert_message = __('Error')
@ -85,10 +86,10 @@ export default class MUCPollFormView extends CustomElement {
}
_translateField (field) {
const v = field.var
const v = field.getAttribute('var')
const label = this._fieldTranslationMap.get(v)
if (label) {
field.label = label
field.setAttribute('label', label)
}
}

View File

@ -4,7 +4,7 @@
import { tplPoll } from '../templates/poll.js'
import { CustomElement } from 'shared/components/element.js'
import { converse, _converse, api } from '@converse/headless'
import { converse, _converse, api } from '@converse/headless/core'
import '../styles/poll.scss'
export default class MUCPollView extends CustomElement {

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, converse } from '../../../src/headless/index.js'
import { _converse, converse } from '../../../src/headless/core.js'
import { getHeadingButtons } from './utils.js'
import { POLL_MESSAGE_TAG, POLL_QUESTION_TAG, POLL_CHOICE_TAG } from './constants.js'
import { __ } from 'i18n'
@ -12,6 +12,8 @@ import './components/poll-form-view.js'
const { sizzle } = converse.env
const delayedTimeout = 2 // for delayed poll message, how long must the be considered as valid.
converse.plugins.add('livechat-converse-poll', {
dependencies: ['converse-muc', 'converse-disco'],
@ -97,6 +99,23 @@ converse.plugins.add('livechat-converse-poll', {
if (attrs.is_archived) {
return this.__super__.onMessage(attrs)
}
if (attrs.is_delayed) {
// When archiving is disabled, the "history" mechanism is still available:
// Last X (20 by default) messages will be kept, and sent to users.
// The only thing that differentiates such messages is that they are delayed.
// We can't just ignore all delayed messages, because if one day we enable SMACKS
// (to handle deconnections on poor network), there could be some legitimate delayed messages.
// So we will only ignore the poll if it was sent more than X minutes ago.
console.debug('Got a delayed poll message, checking if old or not')
const d = new Date()
d.setMinutes(d.getMinutes() - delayedTimeout)
if (attrs.time < d.toISOString()) {
console.debug(
`Poll message was delayed fore more than ${delayedTimeout} minutes (${attrs.time} < ${d.toISOString()}).`
)
return this.__super__.onMessage(attrs)
}
}
console.info('Got a poll message, setting it as the current_poll')
// this will be displayed by the livechat-converse-muc-poll custom element,

View File

@ -4,7 +4,7 @@
import { __ } from 'i18n'
import BaseModal from 'plugins/modal/modal.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { modal_close_button as ModalCloseButton } from 'plugins/modal/templates/buttons.js'
import { html } from 'lit'

View File

@ -5,10 +5,6 @@
import { converseLocalizedHelpUrl } from '../../../shared/lib/help'
import { html } from 'lit'
import { __ } from 'i18n'
import { converse } from '@converse/headless'
const u = converse.env.utils
export function tplPollForm (el) {
const i18nOk = __('Ok')
// eslint-disable-next-line no-undef
@ -17,18 +13,10 @@ export function tplPollForm (el) {
page: 'documentation/user/streamers/polls'
})
let formFieldTemplates
if (el.xform) {
const fields = el.xform.fields
formFieldTemplates = fields.map(field => {
return u.xFormField2TemplateResult(field)
})
}
return html`
${el.alert_message ? html`<div class="error">${el.alert_message}</div>` : ''}
${
formFieldTemplates
el.form_fields
? html`
<form class="converse-form" @submit=${ev => el.formSubmit(ev)}>
<p class="title">
@ -42,7 +30,7 @@ export function tplPollForm (el) {
<p class="form-help instructions">${el.instructions}</p>
<div class="form-errors hidden"></div>
${formFieldTemplates}
${el.form_fields}
<fieldset class="buttons form-group">
<input type="submit" class="btn btn-primary" value="${i18nOk}" />

View File

@ -63,7 +63,7 @@ function _tplChoice (el, currentPoll, choice, canVote) {
<div class="livechat-progress-bar">
<div
role="progressbar"
style=${'width: ' + percent + '%;'}
style="width: ${percent}%;"
aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"
></div>
<p>

View File

@ -3,12 +3,12 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { XMLNS_POLL } from './constants.js'
import { _converse, api } from '../../../src/headless/index.js'
import { _converse, api } from '../../../src/headless/core.js'
import { __ } from 'i18n'
export function getHeadingButtons (view, buttons) {
const muc = view.model
if (muc.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (muc.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, converse, api } from '../../../src/headless/index.js'
import { _converse, converse, api } from '../../../src/headless/core.js'
/**
* This plugin computes the available width of converse-root, and adds classes

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { CustomElement } from 'shared/components/element.js'
import { tplMUCTaskApp } from '../templates/muc-task-app.js'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import tplMucTaskList from '../templates/muc-task-list'
import { __ } from 'i18n'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import tplMucTaskLists from '../templates/muc-task-lists'
import { __ } from 'i18n'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { tplMucTask } from '../templates/muc-task'
import { __ } from 'i18n'

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, converse } from '../../../src/headless/index.js'
import { _converse, converse } from '../../../src/headless/core.js'
import { ChatRoomTaskLists } from './task-lists.js'
import { ChatRoomTaskList } from './task-list.js'
import { ChatRoomTasks } from './tasks.js'
@ -18,14 +18,9 @@ converse.plugins.add('livechat-converse-tasks', {
dependencies: ['converse-muc', 'converse-disco', 'converse-pubsub'],
initialize () {
Object.assign(
_converse.exports,
{
ChatRoomTaskLists,
ChatRoomTaskList,
ChatRoomTasks
}
)
_converse.ChatRoomTaskLists = ChatRoomTaskLists
_converse.ChatRoomTaskList = ChatRoomTaskList
_converse.ChatRoomTasks = ChatRoomTasks
_converse.api.settings.extend({
livechat_task_app_enabled: false,

View File

@ -4,7 +4,7 @@
import BaseModal from 'plugins/modal/modal.js'
import tplPickTaskList from './templates/pick-task-list.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { __ } from 'i18n'
export default class PickTaskListModal extends BaseModal {

View File

@ -7,7 +7,7 @@ import { Model } from '@converse/skeletor/src/model.js'
/**
* A chat room task list.
* @class
* @namespace _converse.exports.ChatRoomTaskList
* @namespace _converse.ChatRoomTaskList
* @memberof _converse
*/
class ChatRoomTaskList extends Model {

View File

@ -7,9 +7,9 @@ import { ChatRoomTaskList } from './task-list'
import { initStorage } from '@converse/headless/utils/storage.js'
/**
* A list of {@link _converse.exports.ChatRoomTaskList} instances, representing task lists associated to a MUC.
* A list of {@link _converse.ChatRoomTaskList} instances, representing task lists associated to a MUC.
* @class
* @namespace _converse.exports.ChatRoomTaskLists
* @namespace _converse.ChatRoomTaskLists
* @memberOf _converse
*/
class ChatRoomTaskLists extends Collection {

View File

@ -7,7 +7,7 @@ import { Model } from '@converse/skeletor/src/model.js'
/**
* A chat room task.
* @class
* @namespace _converse.exports.ChatRoomTask
* @namespace _converse.ChatRoomTask
* @memberof _converse
*/
class ChatRoomTask extends Model {

View File

@ -7,9 +7,9 @@ import { ChatRoomTask } from './task'
import { initStorage } from '@converse/headless/utils/storage.js'
/**
* A list of {@link _converse.exports.ChatRoomTask} instances, representing all tasks associated to a MUC.
* A list of {@link _converse.ChatRoomTask} instances, representing all tasks associated to a MUC.
* @class
* @namespace _converse.exports.ChatRoomTasks
* @namespace _converse.ChatRoomTasks
* @memberOf _converse
*/
class ChatRoomTasks extends Collection {

View File

@ -4,12 +4,12 @@
import { XMLNS_TASKLIST, XMLNS_TASK } from './constants.js'
import { PubSubManager } from '../../shared/lib/pubsub-manager.js'
import { converse, _converse, api } from '../../../src/headless/index.js'
import { converse, _converse, api } from '../../../src/headless/core.js'
import { __ } from 'i18n'
export function getHeadingButtons (view, buttons) {
const muc = view.model
if (muc.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (muc.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}
@ -74,8 +74,8 @@ function _initChatRoomTaskLists (mucModel) {
return
}
mucModel.tasklists = new _converse.exports.ChatRoomTaskLists(undefined, { chatroom: mucModel })
mucModel.tasks = new _converse.exports.ChatRoomTasks(undefined, { chatroom: mucModel })
mucModel.tasklists = new _converse.ChatRoomTaskLists(undefined, { chatroom: mucModel })
mucModel.tasks = new _converse.ChatRoomTasks(undefined, { chatroom: mucModel })
mucModel.taskManager = new PubSubManager(
mucModel.get('jid'),
@ -127,7 +127,7 @@ function _destroyChatRoomTaskLists (mucModel) {
}
export function initOrDestroyChatRoomTaskLists (mucModel) {
if (mucModel.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (mucModel.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return _destroyChatRoomTaskLists(mucModel)
}

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { html } from 'lit'
import { __ } from 'i18n'

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { converse, api } from '../../../src/headless/index.js'
import { converse, api } from '../../../src/headless/core.js'
import './components/muc-terms.js'
const { sizzle } = converse.env

View File

@ -4,7 +4,7 @@
/* eslint-disable max-len */
import { html } from 'lit'
import tplIcons from '../../../src/shared/components/templates/icons.js'
import tplIcons from '../../../src/shared/templates/icons.js'
export default () => {
// Here we are adding some additonal icons to ConverseJS defaults

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { converse, _converse, api } from '../../../src/headless/index.js'
import { converse, _converse, api } from '../../../src/headless/core.js'
const { $build, Strophe, $iq, sizzle } = converse.env
/**
@ -50,7 +50,7 @@ export class PubSubManager {
async start () {
// FIXME: handle errors. Find a way to display to user that this failed.
this.stanzaHandler = api.connection.get().addHandler(
this.stanzaHandler = _converse.connection.addHandler(
(message) => {
try {
this._handleMessage(message)
@ -79,7 +79,7 @@ export class PubSubManager {
// Note: no need to unsubscribe from the pubsub node, the backend will do when users leave the room.
if (this.stanzaHandler) {
api.connection.get().deleteHandler(this.stanzaHandler)
_converse.connection.deleteHandler(this.stanzaHandler)
this.stanzaHandler = undefined
}
}

View File

@ -4,7 +4,7 @@
import { __ } from 'i18n'
import BaseModal from 'plugins/modal/modal.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { html } from 'lit'
import 'livechat-external-login-content.js'

View File

@ -52,16 +52,15 @@
.emoji-picker__header {
color: var(--peertube-main-background);
background-color: var(--peertube-main-background);
background-color: var(--peertube-main-foreground);
ul {
.emoji-category {
color: var(--peertube-main-background);
background-color: #2d2d2d;
border-bottom: 1px solid var(--peertube-main-foreground);
background-color: var(--peertube-main-foreground);
a {
color: white;
color: currentcolor;
}
&.picked {
@ -135,19 +134,17 @@
// Changing size for emojis, to have bigger custom emojis
img.emoji {
width: 3.5rem !important;
height: 3.5rem !important;
// max-height: 4.25em !important; // and no max-width
width: unset !important;
height: unset !important;
max-height: 3em !important; // and no max-width
}
// underline links in chat messages
a[href] {
text-decoration: none !important;
color: #f57200 !important;
text-decoration: underline;
&:hover {
text-decoration: underline !important;
color: #D16100 !important;
text-decoration: underline;
}
}
}
@ -191,12 +188,6 @@
}
}
/* NCTV custom */
.emoji-category__heading {
color: white !important;
}
// Bigger occupants sidebar when width is not big enough.
@media screen and (max-width: 576px) {
.chatroom .box-flyout .chatroom-body .occupants {

View File

@ -64,8 +64,8 @@ body.converse-embedded converse-root.theme-peertube {
--message-avatar-height: 36px;
--chat-background-color: var(--peertube-main-background);
--chat-textarea-color: var(--peertube-input-foreground);
--chat-textarea-background-color: var(--peertube-main-background);
--chat-textarea-height: 38px;
--chat-textarea-background-color: var(--peertube-input-background);
--chat-textarea-height: 60px;
--send-button-height: 27px;
--send-button-margin: 3px;
--inline-action-margin: 0.75em;
@ -140,8 +140,8 @@ body.converse-embedded converse-root.theme-peertube {
--fullpage-chatbox-button-size: 24px;
--font-size-tiny: 10px;
--font-size-small: 12px;
--font-size: 16px;
--font-size-large: 18px;
--font-size: 14px;
--font-size-large: 16px;
--font-size-huge: 20px;
--message-font-size: var(--font-size);
--separator-text-color: var(--peertube-grey-foreground);

View File

@ -171,9 +171,7 @@ body.converse-embedded {
#peertube-plugin-livechat-container {
converse-muc-message-form {
// For an unknown reason, message field in truncated... so adding a bottom margin.
max-height: unset !important;
margin-bottom: 0.5rem !important;
margin-top: 0.4rem !important;
margin-bottom: 6px;
}
}

View File

@ -5,7 +5,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { html } from 'lit'
import { api } from '@converse/headless/index.js'
import { api } from '@converse/headless/core.js'
export default () => html`
<div class="inner-content converse-brand row">

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, api } from '@converse/headless'
import { _converse, api } from '@converse/headless/core'
import { __ } from 'i18n'
import { html } from 'lit'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { __ } from 'i18n'
import { _converse, api } from '@converse/headless'
import { _converse, api } from '@converse/headless/core'
import { html } from 'lit'
import tplMucBottomPanel from '../../src/plugins/muc-views/templates/muc-bottom-panel.js'
import { CustomElement } from 'shared/components/element.js'
@ -79,7 +79,7 @@ class SlowMode extends CustomElement {
api.elements.define('livechat-slow-mode', SlowMode)
const tplSlowMode = (o) => {
if (!o.can_post) { return html`` }
if (!o.can_edit) { return html`` }
return html`<livechat-slow-mode jid=${o.model.get('jid')}>`
}
@ -128,9 +128,17 @@ const tplViewerMode = (o) => {
}
export default (o) => {
// ConverseJS 10.x does not handle properly the visitor role in unmoderated rooms.
// See https://github.com/conversejs/converse.js/issues/3428 for more info.
// So we will do a dirty hack here to fix this case.
// Note: ConverseJS 11.x has changed the code, and could be fixed more cleanly (or will be fixed if #3428 is fixed).
if (o.can_edit && o.model.getOwnRole() === 'visitor') {
o.can_edit = false
}
let mutedAnonymousMessage
if (
!o.can_post &&
!o.can_edit &&
o.model.features?.get?.('x_peertubelivechat_mute_anonymous') &&
_converse.api.settings.get('livechat_specific_is_anonymous') === true
) {

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import tplMUCChatarea from '../../src/plugins/muc-views/templates/muc-chatarea.js'
import { html } from 'lit'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { html } from 'lit'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { until } from 'lit/directives/until.js'
import { repeat } from 'lit/directives/repeat.js'
import { unsafeHTML } from 'lit/directives/unsafe-html.js'

View File

@ -44,7 +44,7 @@ module.exports = merge(prod, {
'../../templates/background_logo.js$': path.resolve(__dirname, 'custom/templates/background_logo.js'),
'./templates/muc-chatarea.js': path.resolve('custom/templates/muc-chatarea.js'),
'./templates/icons.js': path.resolve(__dirname, 'custom/shared/components/font-awesome.js'),
'../templates/icons.js': path.resolve(__dirname, 'custom/shared/components/font-awesome.js'),
'shared/styles/index.scss$': path.resolve(__dirname, 'custom/shared/styles/livechat.scss'),

View File

@ -97,7 +97,6 @@ function defaultConverseParams (
pruning_behavior: 'unscrolled',
colorize_username: true,
send_chat_markers: [],
reuse_scram_keys: false, // for now we don't use this.
// This is a specific settings, that is used in ConverseJS customization, to force avatars loading in readonly mode.
livechat_load_all_vcards: !!forceReadonly,

View File

@ -16,7 +16,7 @@ export const livechatMiniMucHeadPlugin = {
})
_converse.api.listen.on('getHeadingButtons', (view: any, buttons: any[]) => {
if (view.model.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (view.model.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}

View File

@ -15,7 +15,7 @@ export const livechatSpecificsPlugin = {
})
_converse.api.listen.on('getHeadingButtons', (view: any, buttons: any[]) => {
if (view.model.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (view.model.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}
@ -53,71 +53,6 @@ export const livechatSpecificsPlugin = {
return buttons
})
_converse.api.listen.on('getToolbarButtons', (toolbarEl: any, buttons: any[]) => {
// We will replace the toggle occupant button, to change its appearance.
// First, we must find it. We search from the end, because usually it is the last one.
let toggleOccupantButton: any
for (const button of buttons.reverse()) {
if (button.strings?.find((s: string) => s.includes('toggle_occupants'))) { // searching the classname
console.debug('[livechatSpecificsPlugin] found the toggle occupants button', button)
toggleOccupantButton = button
break
}
}
if (!toggleOccupantButton) {
console.debug('[livechatSpecificsPlugin] Did not found the toggle occupants button')
return buttons
}
buttons = buttons.filter(b => b !== toggleOccupantButton)
// Replacing by the new button...
// Note: we don't need to test conditions, we know the button was here.
const i18nHideOccupants = _converse.__('Hide participants')
const i18nShowOccupants = _converse.__('Show participants')
const html = window.converse.env.html
const icon = toolbarEl.hidden_occupants
? html`<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa fa-angle-double-left"
size="1em">
</converse-icon>
<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa users"
size="1em">
</converse-icon>`
: html`<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa users"
size="1em">
</converse-icon>
<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa fa-angle-double-right"
size="1em">
</converse-icon>`
buttons.push(html`
<button class="toggle_occupants right"
title="${toolbarEl.hidden_occupants ? i18nShowOccupants : i18nHideOccupants}"
@click=${toolbarEl.toggleOccupants}>
${icon}
</button>`
)
return buttons
})
// Overriding the MUCHeading custom element, to customize the destroyMUC function:
const MUCHeading = _converse.api.elements.registry['converse-muc-heading']
if (MUCHeading) {
class MUCHeadingOverloaded extends MUCHeading {
async destroy (ev: Event): Promise<void> {
ev.preventDefault()
await destroyMUC(_converse, this.model) // here we call a custom version of destroyMUC
}
}
_converse.api.elements.define('converse-muc-heading', MUCHeadingOverloaded)
}
_converse.api.listen.on('chatRoomViewInitialized', function (this: any, _model: any): void {
// Remove the spinner if present...
document.getElementById('livechat-loading-spinner')?.remove()
@ -182,7 +117,7 @@ export const livechatSpecificsPlugin = {
},
overrides: {
ChatRoom: {
getActionInfoMessage: function getActionInfoMessage (this: any, code: string, nick: string, actor: any): any {
getActionInfoMessage: function (this: any, code: string, nick: string, actor: any): any {
if (code === '303') {
// When there is numerous anonymous users joining at the same time,
// they can all change their nicknames at the same time, generating a log of action messages.
@ -195,12 +130,6 @@ export const livechatSpecificsPlugin = {
}
}
return this.__super__.getActionInfoMessage(code, nick, actor)
},
canPostMessages: function canPostMessages (this: any) {
// ConverseJS does not handle properly the visitor role in unmoderated rooms.
// See https://github.com/conversejs/converse.js/issues/3428 for more info.
// FIXME: if #3428 is fixed, remove this override.
return this.isEntered() && this.getOwnRole() !== 'visitor'
}
},
ChatRoomMessage: {
@ -254,26 +183,3 @@ function getOpenPromise (): any {
)
return promise
}
async function destroyMUC (_converse: any, model: any): Promise<void> {
const __ = _converse.__
const messages = [__('Are you sure you want to destroy this groupchat?')]
// Note: challenge and newjid make no sens for peertube-plugin-livechat,
// we remove them comparing to the original function.
let fields = [
{
name: 'reason',
label: __('Optional reason for destroying this groupchat'),
placeholder: __('Reason'),
value: undefined
}
]
try {
fields = await _converse.api.confirm(__('Confirm'), messages, fields)
const reason = fields.filter(f => f.name === 'reason').pop()?.value
const newjid = undefined
return model.sendDestroyIQ(reason, newjid).then(() => model.close())
} catch (e) {
console.error(e)
}
}

View File

@ -17,11 +17,11 @@ export const livechatViewerModePlugin = {
livechat_external_auth_reconnect_mode: undefined
})
const originalGetDefaultMUCNickname = _converse.exports.getDefaultMUCNickname
const originalGetDefaultMUCNickname = _converse.getDefaultMUCNickname
if (!originalGetDefaultMUCNickname) {
console.error('[livechatViewerModePlugin] getDefaultMUCNickname is not initialized.')
} else {
Object.assign(_converse.exports, {
Object.assign(_converse, {
getDefaultMUCNickname: function (this: any): any {
if (!_converse.api.settings.get('livechat_enable_viewer_mode')) {
return originalGetDefaultMUCNickname.apply(this, arguments)

View File

@ -175,6 +175,7 @@ avatar_set_description: |
Please refer to the documentation:
<a href="https://livingston.frama.io/peertube-plugin-livechat/documentation/admin/settings/" target="_blank">Settings</a>.
avatar_set_option_sepia: "Sepia (Peertube mascot)"
avatar_set_option_nctv: "NCTV Branded"
avatar_set_option_cat: "Cats"
avatar_set_option_bird: "Birds"
avatar_set_option_fenec: "Fenecs (Mobilizon mascot)"

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "peertube-plugin-livechat",
"version": "10.3.1",
"version": "10.3.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "peertube-plugin-livechat",
"version": "10.3.1",
"version": "10.3.3",
"license": "AGPL-3.0",
"dependencies": {
"@xmpp/jid": "^0.13.1",

View File

@ -1,13 +1,13 @@
{
"name": "peertube-plugin-livechat",
"description": "NCTV fork of the peertube-plugin-livechat plugin, containing styling and other shit. This will be maintained with upstream.",
"version": "10.3.1",
"description": "PeerTube plugin livechat: create chat rooms for your Peertube lives! Comes with many features: federation, moderation tools, chat bot, chat persistence, OBS integration, ...",
"version": "10.3.3",
"license": "AGPL-3.0",
"author": {
"name": "Matty Boombalatty",
"url": "https://gitea.nicecrew.digital/matty"
"name": "John Livingston",
"url": "https://github.com/JohnXLivingston"
},
"bugs": "https://gitea.nicecrew.digital/matty/peertube-plugin-livechat/issues",
"bugs": "https://github.com/JohnXLivingston/peertube-plugin-livechat/issues",
"clientScripts": [
{
"script": "dist/client/common-client-plugin.js",
@ -82,8 +82,8 @@
"engines": {
"npm": ">=7"
},
"homepage": "https://gitea.nicecrew.digital/matty/peertube-plugin-livechat",
"repository": "https://gitea.nicecrew.digital/matty/peertube-plugin-livechat",
"homepage": "https://livingston.frama.io/peertube-plugin-livechat/",
"repository": "github:JohnXLivingston/peertube-plugin-livechat",
"keywords": [
"peertube",
"plugin"

View File

@ -102,7 +102,7 @@ async function getProsodyFilePaths (options: RegisterServerOptions): Promise<Pro
}
let avatarSet: AvatarSet = (settings['avatar-set'] ?? 'sepia') as AvatarSet
if (!['sepia', 'cat', 'bird', 'fenec', 'abstract', 'legacy'].includes(avatarSet)) {
if (!['sepia', 'cat', 'bird', 'fenec', 'abstract', 'legacy', 'nctv'].includes(avatarSet)) {
logger.error('Invalid avatar-set setting, using sepia as default')
avatarSet = 'sepia'
}

View File

@ -93,7 +93,7 @@ abstract class ProsodyConfigBlock {
this.entries.set(name, value)
}
add (name: string, value: ConfigEntryValue): void {
add (name: string, value: ConfigEntryValue, allowDuplicate?: boolean): void {
if (!this.entries.has(name)) {
this.entries.set(name, [])
}
@ -101,6 +101,9 @@ abstract class ProsodyConfigBlock {
if (!Array.isArray(entry)) {
entry = [entry]
}
if (!allowDuplicate && entry.includes(value)) {
return
}
entry.push(value)
this.entries.set(name, entry)
}
@ -239,7 +242,7 @@ class ProsodyConfigContent {
this.muc.set('muc_room_default_history_length', 20)
this.muc.add('modules_enabled', 'muc_slow_mode')
this.muc.add('slow_mode_duration_form_position', 120)
this.muc.set('slow_mode_duration_form_position', 120)
this.muc.add('modules_enabled', 'pubsub_peertubelivechat')
this.muc.add('modules_enabled', 'muc_peertubelivechat_roles')
@ -251,7 +254,7 @@ class ProsodyConfigContent {
}
this.muc.add('modules_enabled', 'muc_moderation_delay')
this.muc.add('moderation_delay_form_position', 118)
this.muc.set('moderation_delay_form_position', 118)
}
useAnonymous (autoBanIP: boolean): void {
@ -445,7 +448,7 @@ class ProsodyConfigContent {
useMucHttpDefault (url: string): void {
this.muc.add('modules_enabled', 'muc_http_defaults')
this.muc.add('muc_create_api_url', url)
this.muc.set('muc_create_api_url', url)
// restrict_room_creation: we can override the 'local' value.
// Indeed, when muc_http_default is used, room creation will be managed by api.
@ -517,7 +520,7 @@ class ProsodyConfigContent {
*/
useBotsVirtualHost (botAvatarPath: string, botAvatarFiles: string[]): void {
this.bot = new ProsodyConfigVirtualHost('bot.' + this.prosodyDomain)
this.bot.set('modules_enabled', ['ping'])
this.bot.set('modules_enabled', ['ping', 'tls'])
this.bot.set('authentication', 'peertubelivechat_bot')
// For now, just using random_vcard_peertubelivechat to set bot avatar

View File

@ -13,7 +13,7 @@ import { LivechatProsodyAuth } from './prosody/auth'
import { loc } from './loc'
const escapeHTML = require('escape-html')
type AvatarSet = 'sepia' | 'cat' | 'bird' | 'fenec' | 'abstract' | 'legacy'
type AvatarSet = 'sepia' | 'cat' | 'bird' | 'fenec' | 'abstract' | 'legacy' | 'nctv'
async function initSettings (options: RegisterServerOptions): Promise<void> {
const { peertubeHelpers, settingsManager } = options
@ -506,6 +506,7 @@ function initThemingSettings ({ registerSetting }: RegisterServerOptions): void
private: true,
options: [
{ value: 'sepia', label: loc('avatar_set_option_sepia') },
{ value: 'nctv', label: loc('avatar_set_option_nctv') },
{ value: 'cat', label: loc('avatar_set_option_cat') },
{ value: 'bird', label: loc('avatar_set_option_bird') },
{ value: 'fenec', label: loc('avatar_set_option_fenec') },

View File

@ -5,7 +5,7 @@
// Note: API request body size is limited to 100Kb (expressjs body-parser defaut limit, and Peertube nginx config).
// So we must be sure to never send more than 100Kb. The front end sends new emojis by batch, but maxSize must remain
// as little as possible, so that we never reach 100Kb in JSON/base64 format.
export const maxSize: number = 30 * 1024
export const maxSize: number = 800 * 1024
export const allowedExtensions = ['png', 'jpg', 'jpeg', 'gif']
export const inputFileAccept = ['image/jpg', 'image/png', 'image/gif']
export const allowedMimeTypes = ['image/jpg', 'image/png', 'image/gif']

View File

@ -28,6 +28,7 @@ These files are used to generate multiple avatars (see the `build-avatars.js` sc
* `assets/images/avatars/bird` contains new birds avatar set, based on the work of David Revoy (see copyright informations)
* `assets/images/avatars/fenec` contains new fenecs avatar set, based on the work of David Revoy (see copyright informations)
* `assets/images/avatars/abstract` contains new abstract avatar set, based on the work of David Revoy (see copyright informations)
* `assets/images/avatars/nctv` contains NCTV avatar, based on the work of The Almighty Kek
### assets/styles

View File

@ -8,11 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-07-10 16:54+0200\n"
"PO-Revision-Date: 2024-07-12 09:10+0000\n"
"Last-Translator: Victor Hampel <v.hampel@users.noreply.weblate.framasoft.org>"
"\n"
"Language-Team: German <https://weblate.framasoft.org/projects/"
"peertube-livechat/peertube-plugin-livechat-documentation/de/>\n"
"PO-Revision-Date: 2024-07-05 19:12+0000\n"
"Last-Translator: Victor Hampel <v.hampel@users.noreply.weblate.framasoft.org>\n"
"Language-Team: German <https://weblate.framasoft.org/projects/peertube-livechat/peertube-plugin-livechat-documentation/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -3274,30 +3272,25 @@ msgstr "Um den Wert für einen bereits bestehenden Raum zu ändern, öffnen Sie
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
msgid "Currently, this feature has one known bug: users that join the chat will get all messages, even messages that are still pending for other participants. However, messages sent after they joined will be delayed correctly."
msgstr ""
"Derzeit gibt es bei dieser Funktion einen bekannten Fehler: Benutzer, die "
"dem Chat beitreten, erhalten alle Nachrichten, auch solche, die noch für "
"andere Teilnehmer ausstehen. Allerdings werden Nachrichten, die nach dem "
"Beitritt gesendet werden, korrekt verzögert."
#. type: Title ##
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
#, no-wrap
#, fuzzy, no-wrap
#| msgid "Share the chat"
msgid "In the chat"
msgstr "Im Chat"
msgstr "Teilen Sie den Chat"
#. type: Plain text
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
msgid "As a moderator, you will see the remaining time (in seconds) before the message is broadcasted, just besides the message datetime."
msgstr ""
"Als Moderator sehen Sie neben dem Datum der Nachricht auch die verbleibende "
"Zeit (in Sekunden), bevor die Nachricht veröffentlicht wird."
#. type: Plain text
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
#, fuzzy
#| msgid "![Channel configuration / Moderation delay](/peertube-plugin-livechat/images/moderation_delay_channel_option.png?classes=shadow,border&height=400px)"
msgid "![Moderation delay timer](/peertube-plugin-livechat/images/moderation_delay_timer.png?classes=shadow,border)"
msgstr ""
"![Moderationsverzögerungstimer](/peertube-plugin-livechat/images/"
"moderation_delay_timer.png?classes=shadow,border)"
msgstr "![Kanalkonfiguration / Moderationsverzögerung](/peertube-plugin-livechat/images/moderation_delay_channel_option.png?classes=shadow,border&height=400px)"
#. type: Yaml Front Matter Hash Value: description
#: build/documentation/pot_in/documentation/user/streamers/moderation.md
@ -3344,11 +3337,10 @@ msgstr "Über das [Chat Dropdown Menü](/peertube-plugin-livechat/de/documentati
#. type: Plain text
#: build/documentation/pot_in/documentation/user/streamers/moderation.md
#, fuzzy
#| msgid "The video owner will be owner of the chat room. This means he can configure the room, delete it, promote other users as admins, ..."
msgid "The video owner will be owner of the chat room. This means they can configure the room, delete it, promote other users as admins, ..."
msgstr ""
"Der Videobesitzer ist der Besitzer des Chatraums. Das bedeutet, er kann den "
"Raum konfigurieren, löschen, andere Benutzer als Administratoren befördern, "
"..."
msgstr "Der Videobesitzer ist der Besitzer des Chatraums. Das bedeutet, er kann den Raum konfigurieren, löschen, andere Benutzer als Administratoren befördern, ..."
#. type: Plain text
#: build/documentation/pot_in/documentation/user/streamers/moderation.md