Merge remote-tracking branch 'remotes/upstream/v2.6.x-release' into tldrawpdfexport
This commit is contained in:
commit
283cd6be67
7
.github/workflows/automated-tests.yml
vendored
7
.github/workflows/automated-tests.yml
vendored
@ -16,6 +16,7 @@ jobs:
|
||||
- run: ./build/setup.sh bbb-apps-akka
|
||||
- run: ./build/setup.sh bbb-config
|
||||
- run: ./build/setup.sh bbb-etherpad
|
||||
- run: ./build/setup.sh bbb-export-annotations
|
||||
- run: ./build/setup.sh bbb-freeswitch-core
|
||||
- run: ./build/setup.sh bbb-freeswitch-sounds
|
||||
- run: ./build/setup.sh bbb-fsesl-akka
|
||||
@ -109,8 +110,8 @@ jobs:
|
||||
- name: Install BBB
|
||||
run: |
|
||||
sudo sh -c '
|
||||
cd /root/ && wget -q https://ubuntu.bigbluebutton.org/bbb-install-2.5.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v focal-25-dev -s bbb-ci.test -d /certs/
|
||||
cd /root/ && wget -q https://ubuntu.bigbluebutton.org/bbb-install-2.6.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v focal-26-dev -s bbb-ci.test -d /certs/
|
||||
bbb-conf --salt bbbci
|
||||
echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt" >> /usr/share/meteor/bundle/bbb-html5-with-roles.conf
|
||||
bbb-conf --restart
|
||||
@ -137,4 +138,4 @@ jobs:
|
||||
name: tests-report
|
||||
path: |
|
||||
bigbluebutton-tests/playwright/playwright-report
|
||||
bigbluebutton-tests/playwright/test-results
|
||||
bigbluebutton-tests/playwright/test-results
|
||||
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2017 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.core.record.events
|
||||
|
||||
import org.bigbluebutton.common2.domain.SimpleVoteOutVO
|
||||
import scala.collection.immutable.List
|
||||
import scala.collection.Map
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import spray.json._
|
||||
import DefaultJsonProtocol._
|
||||
|
||||
class AddTldrawShapeWhiteboardRecordEvent extends AbstractWhiteboardRecordEvent {
|
||||
import AddTldrawShapeWhiteboardRecordEvent._
|
||||
|
||||
implicit object AnyJsonFormat extends JsonFormat[Any] {
|
||||
def write(x: Any) = x match {
|
||||
case n: Int => JsNumber(n)
|
||||
case s: String => JsString(s)
|
||||
case d: Double => JsNumber(d)
|
||||
case m: scala.collection.immutable.Map[String, _] => mapFormat[String, Any].write(m)
|
||||
case l: List[_] => listFormat[Any].write(l)
|
||||
case b: Boolean if b == true => JsTrue
|
||||
case b: Boolean if b == false => JsFalse
|
||||
}
|
||||
|
||||
def read(value: JsValue) = {}
|
||||
}
|
||||
|
||||
setEvent("AddTldrawShapeEvent")
|
||||
|
||||
def setUserId(id: String) {
|
||||
eventMap.put(USER_ID, id)
|
||||
}
|
||||
|
||||
def setAnnotationId(id: String) {
|
||||
eventMap.put(SHAPE_ID, id)
|
||||
}
|
||||
|
||||
def addAnnotation(annotation: scala.collection.immutable.Map[String, Any]) {
|
||||
eventMap.put(SHAPE_DATA, annotation.toJson.compactPrint)
|
||||
}
|
||||
}
|
||||
|
||||
object AddTldrawShapeWhiteboardRecordEvent {
|
||||
protected final val USER_ID = "userId"
|
||||
protected final val SHAPE_ID = "shapeId"
|
||||
protected final val SHAPE_DATA = "shapeData"
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2017 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.core.record.events
|
||||
|
||||
class DeleteTldrawShapeRecordEvent extends AbstractWhiteboardRecordEvent {
|
||||
import DeleteTldrawShapeRecordEvent._
|
||||
|
||||
setEvent("DeleteTldrawShapeEvent")
|
||||
|
||||
def setUserId(userId: String) {
|
||||
eventMap.put(USER_ID, userId)
|
||||
}
|
||||
|
||||
def setShapeId(shapeId: String) {
|
||||
eventMap.put(SHAPE_ID, shapeId)
|
||||
}
|
||||
}
|
||||
|
||||
object DeleteTldrawShapeRecordEvent {
|
||||
protected final val USER_ID = "userId"
|
||||
protected final val SHAPE_ID = "shapeId"
|
||||
}
|
@ -32,23 +32,28 @@ class ResizeAndMoveSlideRecordEvent extends AbstractPresentationRecordEvent {
|
||||
eventMap.put(ID, id)
|
||||
}
|
||||
|
||||
def setXCamera(xCamera: Double) {
|
||||
eventMap.put(X_CAMERA, xCamera.toString)
|
||||
def setXOffset(offset: Double) {
|
||||
eventMap.put(X_OFFSET, offset.toString)
|
||||
}
|
||||
|
||||
def setYCamera(yCamera: Double) {
|
||||
eventMap.put(Y_CAMERA, yCamera.toString)
|
||||
def setYOffset(offset: Double) {
|
||||
eventMap.put(Y_OFFSET, offset.toString)
|
||||
}
|
||||
|
||||
def setZoom(zoom: Double) {
|
||||
eventMap.put(ZOOM, zoom.toString)
|
||||
def setWidthRatio(ratio: Double) {
|
||||
eventMap.put(WIDTH_RATIO, ratio.toString)
|
||||
}
|
||||
|
||||
def setHeightRatio(ratio: Double) {
|
||||
eventMap.put(HEIGHT_RATIO, ratio.toString)
|
||||
}
|
||||
}
|
||||
|
||||
object ResizeAndMoveSlideRecordEvent {
|
||||
protected final val PRES_NAME = "presentationName"
|
||||
protected final val ID = "id"
|
||||
protected final val X_CAMERA = "xCamera"
|
||||
protected final val Y_CAMERA = "yCamera"
|
||||
protected final val ZOOM = "zoom"
|
||||
protected final val X_OFFSET = "xOffset"
|
||||
protected final val Y_OFFSET = "yOffset"
|
||||
protected final val WIDTH_RATIO = "widthRatio"
|
||||
protected final val HEIGHT_RATIO = "heightRatio"
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2017 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.core.record.events
|
||||
|
||||
class TldrawCameraChangedRecordEvent extends AbstractPresentationRecordEvent {
|
||||
import TldrawCameraChangedRecordEvent._
|
||||
|
||||
setEvent("TldrawCameraChangedEvent")
|
||||
|
||||
def setPresentationName(name: String) {
|
||||
eventMap.put(PRES_NAME, name)
|
||||
}
|
||||
|
||||
def setId(id: String) {
|
||||
eventMap.put(ID, id)
|
||||
}
|
||||
|
||||
def setXCamera(xCamera: Double) {
|
||||
eventMap.put(X_CAMERA, xCamera.toString)
|
||||
}
|
||||
|
||||
def setYCamera(yCamera: Double) {
|
||||
eventMap.put(Y_CAMERA, yCamera.toString)
|
||||
}
|
||||
|
||||
def setZoom(zoom: Double) {
|
||||
eventMap.put(ZOOM, zoom.toString)
|
||||
}
|
||||
}
|
||||
|
||||
object TldrawCameraChangedRecordEvent {
|
||||
protected final val PRES_NAME = "presentationName"
|
||||
protected final val ID = "id"
|
||||
protected final val X_CAMERA = "xCamera"
|
||||
protected final val Y_CAMERA = "yCamera"
|
||||
protected final val ZOOM = "zoom"
|
||||
}
|
@ -184,7 +184,7 @@ class RedisRecorderActor(
|
||||
}
|
||||
|
||||
private def handleResizeAndMovePageEvtMsg(msg: ResizeAndMovePageEvtMsg) {
|
||||
val ev = new ResizeAndMoveSlideRecordEvent()
|
||||
val ev = new TldrawCameraChangedRecordEvent()
|
||||
ev.setMeetingId(msg.header.meetingId)
|
||||
ev.setPodId(msg.body.podId)
|
||||
ev.setPresentationName(msg.body.presentationId)
|
||||
@ -280,7 +280,7 @@ class RedisRecorderActor(
|
||||
|
||||
private def handleSendWhiteboardAnnotationsEvtMsg(msg: SendWhiteboardAnnotationsEvtMsg) {
|
||||
msg.body.annotations.foreach(annotation => {
|
||||
val ev = new AddShapeWhiteboardRecordEvent()
|
||||
val ev = new AddTldrawShapeWhiteboardRecordEvent()
|
||||
ev.setMeetingId(msg.header.meetingId)
|
||||
ev.setPresentation(getPresentationId(annotation.wbId))
|
||||
ev.setPageNumber(getPageNum(annotation.wbId))
|
||||
@ -320,7 +320,7 @@ class RedisRecorderActor(
|
||||
|
||||
private def handleDeleteWhiteboardAnnotationsEvtMsg(msg: DeleteWhiteboardAnnotationsEvtMsg) {
|
||||
msg.body.annotationsIds.foreach(annotationId => {
|
||||
val ev = new UndoAnnotationRecordEvent()
|
||||
val ev = new DeleteTldrawShapeRecordEvent()
|
||||
ev.setMeetingId(msg.header.meetingId)
|
||||
ev.setPresentation(getPresentationId(msg.body.whiteboardId))
|
||||
ev.setPageNumber(getPageNum(msg.body.whiteboardId))
|
||||
|
@ -3,6 +3,7 @@ Description=BigBlueButton Apps (Akka)
|
||||
Requires=network.target
|
||||
Wants=redis-server.service
|
||||
After=redis-server.service
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -22,5 +23,4 @@ PermissionsStartOnly=true
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -3,6 +3,7 @@ Description=BigBlueButton FS-ESL (Akka)
|
||||
Requires=network.target
|
||||
Wants=redis-server.service
|
||||
After=redis-server.service
|
||||
PartOf= bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -22,5 +23,5 @@ PermissionsStartOnly=true
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -7,7 +7,7 @@ const { Worker } = require('worker_threads');
|
||||
const path = require('path');
|
||||
|
||||
const logger = new Logger('presAnn Master');
|
||||
logger.info("Running export-annotations");
|
||||
logger.info("Running bbb-export-annotations");
|
||||
|
||||
const kickOffCollectorWorker = (jobId) => {
|
||||
return new Promise((resolve, reject) => {
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "export-annotations",
|
||||
"name": "bbb-export-annotations",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "export-annotations",
|
||||
"name": "bbb-export-annotations",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.0",
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "export-annotations",
|
||||
"name": "bbb-export-annotations",
|
||||
"version": "0.0.1",
|
||||
"description": "BigBlueButton's Presentation Annotation Exporter",
|
||||
"scripts": {
|
@ -1 +1 @@
|
||||
git clone --branch v2.9.0-alpha.3 --depth 1 https://github.com/bigbluebutton/bbb-webrtc-sfu bbb-webrtc-sfu
|
||||
git clone --branch v2.9.0-alpha.4 --depth 1 https://github.com/bigbluebutton/bbb-webrtc-sfu bbb-webrtc-sfu
|
||||
|
@ -342,35 +342,11 @@ uncomment () {
|
||||
stop_bigbluebutton () {
|
||||
echo "Stopping BigBlueButton"
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-html5.service ]; then
|
||||
HTML5="mongod bbb-html5 bbb-webrtc-sfu kurento-media-server"
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-webhooks.service ]; then
|
||||
WEBHOOKS=bbb-webhooks
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-pads.service ]; then
|
||||
PADS=bbb-pads
|
||||
fi
|
||||
|
||||
if [ -f /usr/share/etherpad-lite/settings.json ]; then
|
||||
ETHERPAD=etherpad
|
||||
fi
|
||||
|
||||
if [ -f /lib/systemd/system/bbb-web.service ]; then
|
||||
BBB_WEB=bbb-web
|
||||
fi
|
||||
|
||||
if [ -f /usr/share/bbb-lti/WEB-INF/classes/lti-config.properties ]; then
|
||||
BBB_LTI=bbb-lti
|
||||
fi
|
||||
|
||||
if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then
|
||||
TOMCAT_SERVICE=$TOMCAT_USER
|
||||
fi
|
||||
|
||||
systemctl stop $TOMCAT_SERVICE nginx freeswitch $REDIS_SERVICE bbb-apps-akka bbb-fsesl-akka bbb-rap-resque-worker.service bbb-rap-starter.service bbb-rap-caption-inbox.service $HTML5 $WEBHOOKS $PADS $ETHERPAD $BBB_WEB $BBB_LTI
|
||||
systemctl stop $TOMCAT_SERVICE bigbluebutton.target
|
||||
}
|
||||
|
||||
start_bigbluebutton () {
|
||||
@ -392,44 +368,24 @@ start_bigbluebutton () {
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Reloading NginX configuration"
|
||||
systemctl reload nginx
|
||||
|
||||
echo "Starting BigBlueButton"
|
||||
if [ -f /usr/lib/systemd/system/bbb-html5.service ]; then
|
||||
HTML5="mongod bbb-html5 bbb-webrtc-sfu kurento-media-server"
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-webhooks.service ]; then
|
||||
WEBHOOKS=bbb-webhooks
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-pads.service ]; then
|
||||
PADS=bbb-pads
|
||||
fi
|
||||
|
||||
if [ -f /usr/share/etherpad-lite/settings.json ]; then
|
||||
ETHERPAD=etherpad
|
||||
fi
|
||||
|
||||
if [ -f /lib/systemd/system/bbb-web.service ]; then
|
||||
BBB_WEB=bbb-web
|
||||
fi
|
||||
|
||||
if [ -f /usr/share/bbb-lti/WEB-INF/classes/lti-config.properties ]; then
|
||||
BBB_LTI=bbb-lti
|
||||
fi
|
||||
|
||||
if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then
|
||||
TOMCAT_SERVICE=$TOMCAT_USER
|
||||
|
||||
systemctl start $TOMCAT_SERVICE || {
|
||||
echo
|
||||
echo "# Warning: $TOMCAT_SERVICE could not be started. Please, check BBB-LTI or BBB-Demo."
|
||||
echo "# Run the command:"
|
||||
echo "# sudo journalctl -u $TOMCAT_SERVICE"
|
||||
echo "# To better understand the ERROR"
|
||||
}
|
||||
fi
|
||||
|
||||
systemctl start $TOMCAT_SERVICE || {
|
||||
echo
|
||||
echo "# Warning: $TOMCAT_SERVICE could not be started. Please, check BBB-LTI or BBB-Demo."
|
||||
echo "# Run the command:"
|
||||
echo "# sudo journalctl -u $TOMCAT_SERVICE"
|
||||
echo "# To better understand the ERROR"
|
||||
}
|
||||
|
||||
systemctl start nginx freeswitch $REDIS_SERVICE bbb-apps-akka bbb-fsesl-akka bbb-rap-resque-worker bbb-rap-starter.service bbb-rap-caption-inbox.service $HTML5 $WEBHOOKS $ETHERPAD $PADS $BBB_WEB $BBB_LTI
|
||||
systemctl start bigbluebutton.target
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-html5.service ]; then
|
||||
systemctl start mongod
|
||||
@ -492,6 +448,10 @@ display_bigbluebutton_status () {
|
||||
units="$units bbb-pads"
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/systemd/system/bbb-export-annotations.service ]; then
|
||||
units="$units bbb-export-annotations"
|
||||
fi
|
||||
|
||||
if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then
|
||||
TOMCAT_SERVICE=$TOMCAT_USER
|
||||
fi
|
||||
@ -1142,17 +1102,19 @@ check_state() {
|
||||
fi
|
||||
|
||||
if bbb-conf --status | grep -q inactive; then
|
||||
if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then
|
||||
TOMCAT_SERVICE=$TOMCAT_USER
|
||||
|
||||
if bbb-conf --status | grep -q tomcat9; then
|
||||
echo "# Warning: $TOMCAT_SERVICE is not started correctly"
|
||||
echo "#"
|
||||
echo "# $(bbb-conf --status | grep inactive | grep $TOMCAT_SERVICE)"
|
||||
echo "#"
|
||||
if bbb-conf --status | grep -q inactive | grep -q $TOMCAT_SERVICE; then
|
||||
echo "# Warning: $TOMCAT_SERVICE is not started correctly"
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
if bbb-conf --status | grep inactive | grep -vq tomcat9; then
|
||||
|
||||
if bbb-conf --status | grep inactive; then
|
||||
echo "# Error: Detected some processes have not started correctly"
|
||||
echo "#"
|
||||
echo "# $(bbb-conf --status | grep inactive | grep -v $TOMCAT_SERVICE)"
|
||||
echo "# $(bbb-conf --status | grep inactive)"
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
@ -1721,7 +1683,7 @@ String BigBlueButtonURL = \"$BBB_WEB_URL/bigbluebutton/\";
|
||||
sudo xmlstarlet edit --inplace --update 'configuration/settings//param[@name="password"]/@value' --value $ESL_PASSWORD /opt/freeswitch/etc/freeswitch/autoload_configs/event_socket.conf.xml
|
||||
|
||||
|
||||
echo "Restarting the BigBlueButton $BIGBLUEBUTTON_RELEASE ..."
|
||||
echo "Restarting BigBlueButton $BIGBLUEBUTTON_RELEASE ..."
|
||||
stop_bigbluebutton
|
||||
start_bigbluebutton
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
meteor-base@1.5.1
|
||||
mobile-experience@1.1.0
|
||||
mongo@1.14.6
|
||||
mongo@1.15.0
|
||||
reactive-var@1.0.11
|
||||
|
||||
standard-minifier-css@1.8.1
|
||||
|
@ -1 +1 @@
|
||||
METEOR@2.7.1
|
||||
METEOR@2.7.3
|
||||
|
@ -1,10 +1,10 @@
|
||||
allow-deny@1.1.1
|
||||
autoupdate@1.8.0
|
||||
babel-compiler@7.9.0
|
||||
babel-runtime@1.5.0
|
||||
babel-runtime@1.5.1
|
||||
base64@1.0.12
|
||||
binary-heap@1.0.11
|
||||
blaze-tools@1.1.2
|
||||
blaze-tools@1.1.3
|
||||
boilerplate-generator@1.7.1
|
||||
caching-compiler@1.2.2
|
||||
caching-html-compiler@1.2.1
|
||||
@ -25,7 +25,7 @@ es5-shim@4.8.0
|
||||
fetch@0.1.1
|
||||
geojson-utils@1.0.10
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.1.2
|
||||
html-tools@1.1.3
|
||||
htmljs@1.1.1
|
||||
http@2.0.0
|
||||
id-map@1.1.1
|
||||
@ -43,11 +43,11 @@ minifier-js@2.7.4
|
||||
minimongo@1.8.0
|
||||
mobile-experience@1.1.0
|
||||
mobile-status-bar@1.1.0
|
||||
modern-browsers@0.1.7
|
||||
modern-browsers@0.1.8
|
||||
modules@0.18.0
|
||||
modules-runtime@0.13.0
|
||||
mongo@1.14.6
|
||||
mongo-decimal@0.1.2
|
||||
mongo@1.15.0
|
||||
mongo-decimal@0.1.3
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.8
|
||||
npm-mongo@4.3.1
|
||||
@ -55,7 +55,7 @@ ordered-dict@1.1.0
|
||||
promise@0.12.0
|
||||
random@1.2.0
|
||||
react-fast-refresh@0.2.3
|
||||
react-meteor-data@2.4.0
|
||||
react-meteor-data@2.5.1
|
||||
reactive-dict@1.3.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.3.1
|
||||
@ -64,12 +64,12 @@ rocketchat:streamer@1.1.0
|
||||
routepolicy@1.1.1
|
||||
session@1.2.0
|
||||
shell-server@0.5.0
|
||||
socket-stream-client@0.4.0
|
||||
spacebars-compiler@1.3.0
|
||||
socket-stream-client@0.5.0
|
||||
spacebars-compiler@1.3.1
|
||||
standard-minifier-css@1.8.1
|
||||
standard-minifier-js@2.8.0
|
||||
static-html@1.3.2
|
||||
templating-tools@1.2.1
|
||||
templating-tools@1.2.2
|
||||
tracker@1.2.0
|
||||
typescript@4.5.4
|
||||
underscore@1.0.10
|
||||
|
@ -21,6 +21,7 @@ import React from 'react';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { render } from 'react-dom';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import '/imports/ui/services/mobile-app';
|
||||
import Base from '/imports/startup/client/base';
|
||||
import JoinHandler from '/imports/ui/components/join-handler/component';
|
||||
import AuthenticatedHandler from '/imports/ui/components/authenticated-handler/component';
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
import { SCREENSHARING_ERRORS } from '/imports/api/screenshare/client/bridge/errors';
|
||||
|
||||
const { isMobile } = deviceInfo;
|
||||
const { isSafari } = browserInfo;
|
||||
const { isSafari, isMobileApp } = browserInfo;
|
||||
|
||||
const propTypes = {
|
||||
intl: PropTypes.objectOf(Object).isRequired,
|
||||
@ -167,7 +167,7 @@ const ScreenshareButton = ({
|
||||
? intlMessages.stopDesktopShareDesc : intlMessages.desktopShareDesc;
|
||||
|
||||
const shouldAllowScreensharing = enabled
|
||||
&& !isMobile
|
||||
&& ( !isMobile || isMobileApp)
|
||||
&& amIPresenter;
|
||||
|
||||
const dataTest = !screenshareDataSavingSetting ? 'screenshareLocked'
|
||||
|
@ -289,17 +289,24 @@ const LayoutEngine = ({ layoutType }) => {
|
||||
isMobile,
|
||||
isTablet,
|
||||
};
|
||||
|
||||
const layout = document.getElementById('layout');
|
||||
|
||||
switch (layoutType) {
|
||||
case LAYOUT_TYPE.CUSTOM_LAYOUT:
|
||||
layout?.setAttribute("data-layout", LAYOUT_TYPE.CUSTOM_LAYOUT);
|
||||
return <CustomLayout {...common} />;
|
||||
case LAYOUT_TYPE.SMART_LAYOUT:
|
||||
layout?.setAttribute("data-layout", LAYOUT_TYPE.SMART_LAYOUT);
|
||||
return <SmartLayout {...common} />;
|
||||
case LAYOUT_TYPE.PRESENTATION_FOCUS:
|
||||
layout?.setAttribute("data-layout", LAYOUT_TYPE.PRESENTATION_FOCUS);
|
||||
return <PresentationFocusLayout {...common} />;
|
||||
case LAYOUT_TYPE.VIDEO_FOCUS:
|
||||
layout?.setAttribute("data-layout",LAYOUT_TYPE.VIDEO_FOCUS);
|
||||
return <VideoFocusLayout {...common} />;
|
||||
default:
|
||||
layout?.setAttribute("data-layout", LAYOUT_TYPE.CUSTOM_LAYOUT);
|
||||
return <CustomLayout {...common} />;
|
||||
}
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ import AudioService from '/imports/ui/components/audio/service';
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import MediaStreamUtils from '/imports/utils/media-stream-utils';
|
||||
import ConnectionStatusService from '/imports/ui/components/connection-status/service';
|
||||
import browserInfo from '/imports/utils/browserInfo';
|
||||
|
||||
const VOLUME_CONTROL_ENABLED = Meteor.settings.public.kurento.screenshare.enableVolumeControl;
|
||||
const SCREENSHARE_MEDIA_ELEMENT_NAME = 'screenshareVideo';
|
||||
@ -122,6 +123,11 @@ const getVolume = () => KurentoBridge.getVolume();
|
||||
const shouldEnableVolumeControl = () => VOLUME_CONTROL_ENABLED && screenshareHasAudio();
|
||||
|
||||
const attachLocalPreviewStream = (mediaElement) => {
|
||||
const {isMobileApp} = browserInfo;
|
||||
if (isMobileApp) {
|
||||
// We don't show preview for mobile app, as the stream is only available in native code
|
||||
return;
|
||||
}
|
||||
const stream = KurentoBridge.gdmStream;
|
||||
if (stream && mediaElement) {
|
||||
// Always muted, presenter preview.
|
||||
|
@ -118,6 +118,7 @@ const VideoListItem = (props) => {
|
||||
onHandleVideoFocus={onHandleVideoFocus}
|
||||
focused={focused}
|
||||
onHandleMirror={() => setIsMirrored((value) => !value)}
|
||||
isRTL={isRTL}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -141,6 +142,7 @@ const VideoListItem = (props) => {
|
||||
onHandleVideoFocus={onHandleVideoFocus}
|
||||
focused={focused}
|
||||
onHandleMirror={() => setIsMirrored((value) => !value)}
|
||||
isRTL={isRTL}
|
||||
/>
|
||||
<UserStatus
|
||||
voiceUser={voiceUser}
|
||||
@ -186,6 +188,7 @@ const VideoListItem = (props) => {
|
||||
onHandleVideoFocus={onHandleVideoFocus}
|
||||
focused={focused}
|
||||
onHandleMirror={() => setIsMirrored((value) => !value)}
|
||||
isRTL={isRTL}
|
||||
/>
|
||||
<UserStatus
|
||||
voiceUser={voiceUser}
|
||||
@ -203,50 +206,6 @@ const VideoListItem = (props) => {
|
||||
animations={animations}
|
||||
{...makeDragOperations(onVirtualBgDrop, user?.userId)}
|
||||
>
|
||||
{
|
||||
videoIsReady
|
||||
? (
|
||||
<>
|
||||
<Styled.TopBar>
|
||||
<PinArea
|
||||
user={user}
|
||||
/>
|
||||
<ViewActions
|
||||
videoContainer={videoContainer}
|
||||
name={name}
|
||||
cameraId={cameraId}
|
||||
isFullscreenContext={isFullscreenContext}
|
||||
layoutContextDispatch={layoutContextDispatch}
|
||||
/>
|
||||
</Styled.TopBar>
|
||||
<Styled.BottomBar>
|
||||
<UserActions
|
||||
name={name}
|
||||
user={user}
|
||||
cameraId={cameraId}
|
||||
numOfStreams={numOfStreams}
|
||||
onHandleVideoFocus={onHandleVideoFocus}
|
||||
focused={focused}
|
||||
onHandleMirror={() => setIsMirrored((value) => !value)}
|
||||
isRTL={isRTL}
|
||||
/>
|
||||
<UserStatus
|
||||
voiceUser={voiceUser}
|
||||
/>
|
||||
</Styled.BottomBar>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<Styled.WebcamConnecting
|
||||
data-test="webcamConnecting"
|
||||
talking={talking}
|
||||
animations={animations}
|
||||
>
|
||||
<Styled.LoadingText>{name}</Styled.LoadingText>
|
||||
</Styled.WebcamConnecting>
|
||||
)
|
||||
}
|
||||
|
||||
<Styled.VideoContainer>
|
||||
<Styled.Video
|
||||
mirrored={isMirrored}
|
||||
|
@ -71,6 +71,9 @@ const WebcamComponent = ({
|
||||
);
|
||||
Storage.setItem('webcamSize', { width: newCameraMaxWidth, height: lastHeight });
|
||||
}
|
||||
|
||||
const cams = document.getElementById('cameraDock');
|
||||
cams?.setAttribute("data-position", cameraDock.position);
|
||||
}, [cameraDock.position, cameraDock.maxWidth, isPresenter, displayPresentation]);
|
||||
|
||||
const handleVideoFocus = (id) => {
|
||||
@ -122,6 +125,8 @@ const WebcamComponent = ({
|
||||
setIsDragging(false);
|
||||
setDraggedAtLeastOneTime(false);
|
||||
document.body.style.overflow = 'auto';
|
||||
const layout = document.getElementById('layout');
|
||||
layout?.setAttribute("data-cam-position", e?.target?.id);
|
||||
|
||||
if (Object.values(CAMERADOCK_POSITION).includes(e.target.id) && draggedAtLeastOneTime) {
|
||||
layoutContextDispatch({
|
||||
|
@ -184,7 +184,7 @@ export default function Whiteboard(props) {
|
||||
tldrawAPI?.setCamera(camera.point, camera.zoom);
|
||||
}
|
||||
}
|
||||
}, [presentationBounds, curPageId]);
|
||||
}, [presentationBounds, curPageId, document?.documentElement?.dir]);
|
||||
|
||||
// change tldraw page when presentation page changes
|
||||
React.useEffect(() => {
|
||||
@ -228,7 +228,7 @@ export default function Whiteboard(props) {
|
||||
isMultiUserActive={isMultiUserActive}
|
||||
>
|
||||
<Tldraw
|
||||
key={`wb-${!hasWBAccess && !isPresenter}`}
|
||||
key={`wb-${!hasWBAccess && !isPresenter}-${document?.documentElement?.dir}`}
|
||||
document={doc}
|
||||
// disable the ability to drag and drop files onto the whiteboard
|
||||
// until we handle saving of assets in akka.
|
||||
|
@ -1,6 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { _ } from "lodash";
|
||||
|
||||
const RESIZE_HANDLE_HEIGHT = 8;
|
||||
const RESIZE_HANDLE_WIDTH = 18;
|
||||
const BOTTOM_CAM_HANDLE_HEIGHT = 10;
|
||||
|
||||
function usePrevious(value) {
|
||||
const ref = React.useRef();
|
||||
React.useEffect(() => {
|
||||
@ -80,7 +84,7 @@ const PositionLabel = (props) => {
|
||||
isMultiUserActive,
|
||||
} = props;
|
||||
|
||||
const { name, color, userId, presenter } = currentUser;
|
||||
const { name, color } = currentUser;
|
||||
const prevCurrentPoint = usePrevious(currentPoint);
|
||||
|
||||
React.useEffect(() => {
|
||||
@ -121,14 +125,15 @@ export default function Cursors(props) {
|
||||
isViewersCursorLocked,
|
||||
hasMultiUserAccess,
|
||||
isMultiUserActive,
|
||||
application,
|
||||
} = props;
|
||||
|
||||
const start = () => setActive(true);
|
||||
|
||||
const end = () => {
|
||||
publishCursorUpdate({
|
||||
xPercent: null,
|
||||
yPercent: null,
|
||||
xPercent: -1.0,
|
||||
yPercent: -1.0,
|
||||
whiteboardId: whiteboardId,
|
||||
});
|
||||
setActive(false);
|
||||
@ -136,15 +141,78 @@ export default function Cursors(props) {
|
||||
|
||||
const moved = (event) => {
|
||||
const { type } = event;
|
||||
const yOffset = parseFloat(document.getElementById('Navbar')?.style?.height);
|
||||
const nav = document.getElementById('Navbar');
|
||||
let yOffset = parseFloat(nav?.style?.height);
|
||||
const getSibling = (el) => el?.previousSibling || null;
|
||||
const panel = getSibling(document.getElementById('Navbar'));
|
||||
const panel = getSibling(nav);
|
||||
const webcams = document.getElementById('cameraDock');
|
||||
const subPanel = panel && getSibling(panel);
|
||||
const xOffset = (parseFloat(panel?.style?.width) || 0) + (parseFloat(subPanel?.style?.width) || 0);
|
||||
let xOffset = (parseFloat(panel?.style?.width) || 0) + (parseFloat(subPanel?.style?.width) || 0);
|
||||
const camPosition = document.getElementById('layout')?.getAttribute('data-cam-position') || null;
|
||||
|
||||
const sl = document.getElementById('layout')?.getAttribute('data-layout');
|
||||
if (type === 'touchmove') {
|
||||
!active && setActive(true);
|
||||
return setPos({ x: event?.changedTouches[0]?.clientX - xOffset, y: event?.changedTouches[0]?.clientY - yOffset });
|
||||
}
|
||||
|
||||
const handleCustomYOffsets = () => {
|
||||
if (camPosition === 'contentTop' || !camPosition) {
|
||||
yOffset += (parseFloat(webcams?.style?.height) + RESIZE_HANDLE_HEIGHT);
|
||||
}
|
||||
if (camPosition === 'contentBottom') {
|
||||
yOffset -= BOTTOM_CAM_HANDLE_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (document?.documentElement?.dir === 'rtl') {
|
||||
xOffset = 0;
|
||||
if (webcams && sl?.includes('custom')) {
|
||||
handleCustomYOffsets();
|
||||
if (camPosition === 'contentRight') {
|
||||
xOffset += (parseFloat(webcams?.style?.width) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
}
|
||||
if (webcams && sl?.includes('smart')) {
|
||||
if (panel || subPanel) {
|
||||
const dockPos = webcams?.getAttribute("data-position");
|
||||
if (dockPos === 'contentRight') {
|
||||
xOffset += (parseFloat(webcams?.style?.width) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
if (dockPos === 'contentTop') {
|
||||
yOffset += (parseFloat(webcams?.style?.height) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (!panel && !subPanel) {
|
||||
xOffset = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (webcams && sl?.includes('custom')) {
|
||||
handleCustomYOffsets();
|
||||
if (camPosition === 'contentLeft') {
|
||||
xOffset += (parseFloat(webcams?.style?.width) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (webcams && sl?.includes('smart')) {
|
||||
if (panel || subPanel) {
|
||||
const dockPos = webcams?.getAttribute("data-position");
|
||||
if (dockPos === 'contentLeft') {
|
||||
xOffset += (parseFloat(webcams?.style?.width) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
if (dockPos === 'contentTop') {
|
||||
yOffset += (parseFloat(webcams?.style?.height) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (!panel && !subPanel) {
|
||||
xOffset = (parseFloat(webcams?.style?.width) + RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return setPos({ x: event.x - xOffset, y: event.y - yOffset });
|
||||
}
|
||||
|
||||
@ -167,18 +235,22 @@ export default function Cursors(props) {
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
cursorWrapper.removeEventListener('mouseenter', start);
|
||||
cursorWrapper.removeEventListener('mouseleave', end);
|
||||
cursorWrapper.removeEventListener('mousemove', moved);
|
||||
cursorWrapper.removeEventListener('touchend', end);
|
||||
cursorWrapper.removeEventListener('touchmove', moved);
|
||||
if (cursorWrapper) {
|
||||
cursorWrapper.removeEventListener('mouseenter', start);
|
||||
cursorWrapper.removeEventListener('mouseleave', end);
|
||||
cursorWrapper.removeEventListener('mousemove', moved);
|
||||
cursorWrapper.removeEventListener('touchend', end);
|
||||
cursorWrapper.removeEventListener('touchmove', moved);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
});
|
||||
|
||||
const multiUserAccess = hasMultiUserAccess(whiteboardId, currentUser?.userId);
|
||||
|
||||
return (
|
||||
<span disabled={true} ref={(r) => (cursorWrapper = r)}>
|
||||
<div style={{ height: "100%", cursor: "none" }}>
|
||||
{active && (
|
||||
<div style={{ height: "100%", cursor: multiUserAccess || currentUser?.presenter ? "none" : "default" }}>
|
||||
{(active && multiUserAccess || (active && currentUser?.presenter)) && (
|
||||
<PositionLabel
|
||||
pos={pos}
|
||||
otherCursors={otherCursors}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { withTracker } from "meteor/react-meteor-data";
|
||||
import React from "react";
|
||||
import SettingsService from '/imports/ui/services/settings';
|
||||
import Cursors from "./component";
|
||||
import Service from "./service";
|
||||
|
||||
@ -10,6 +11,7 @@ const CursorsContainer = (props) => {
|
||||
export default
|
||||
withTracker((params) => {
|
||||
return {
|
||||
application: SettingsService?.application,
|
||||
currentUser: params.currentUser,
|
||||
publishCursorUpdate: Service.publishCursorUpdate,
|
||||
otherCursors: Service.getCurrentCursors(params.whiteboardId),
|
||||
|
296
bigbluebutton-html5/imports/ui/services/mobile-app/index.js
Normal file
296
bigbluebutton-html5/imports/ui/services/mobile-app/index.js
Normal file
@ -0,0 +1,296 @@
|
||||
import browserInfo from '/imports/utils/browserInfo';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
(function (){
|
||||
// This function must be executed during the import time, that's why it's not exported to the caller component.
|
||||
// It's needed because it changes some functions provided by browser, and these functions are verified during
|
||||
// import time (like in ScreenshareBridgeService)
|
||||
if(browserInfo.isMobileApp) {
|
||||
logger.debug(`BBB-MOBILE - Mobile APP detected`);
|
||||
|
||||
const WEBRTC_CALL_TYPE_FULL_AUDIO = 'full_audio';
|
||||
const WEBRTC_CALL_TYPE_SCREEN_SHARE = 'screen_share';
|
||||
const WEBRTC_CALL_TYPE_STANDARD = 'standard';
|
||||
|
||||
// This function detects if the call happened to publish a screenshare
|
||||
function detectWebRtcCallType(caller, peerConnection = null, args = null) {
|
||||
// Keep track of how many webRTC evaluations was done
|
||||
if(!peerConnection.detectWebRtcCallTypeEvaluations)
|
||||
peerConnection.detectWebRtcCallTypeEvaluations = 0;
|
||||
|
||||
peerConnection.detectWebRtcCallTypeEvaluations ++;
|
||||
|
||||
// If already successfully evaluated, reuse
|
||||
if(peerConnection && peerConnection.webRtcCallType !== undefined ) {
|
||||
logger.info(`BBB-MOBILE - detectWebRtcCallType (already evaluated as ${peerConnection.webRtcCallType})`, {caller, peerConnection});
|
||||
return peerConnection.webRtcCallType;
|
||||
}
|
||||
|
||||
// Evaluate context otherwise
|
||||
const e = new Error('dummy');
|
||||
const stackTrace = e.stack;
|
||||
logger.info(`BBB-MOBILE - detectWebRtcCallType (evaluating)`, {caller, peerConnection, stackTrace: stackTrace.split('\n'), detectWebRtcCallTypeEvaluations: peerConnection.detectWebRtcCallTypeEvaluations, args});
|
||||
|
||||
// addTransceiver is the first call for screensharing and it has a startScreensharing in its stackTrace
|
||||
if( peerConnection.detectWebRtcCallTypeEvaluations == 1) {
|
||||
if(caller == 'addTransceiver' && stackTrace.indexOf('startScreensharing') !== -1) {
|
||||
peerConnection.webRtcCallType = WEBRTC_CALL_TYPE_SCREEN_SHARE; // this uses mobile app broadcast upload extension
|
||||
} else if(caller == 'addEventListener' && stackTrace.indexOf('invite') !== -1) {
|
||||
peerConnection.webRtcCallType = WEBRTC_CALL_TYPE_FULL_AUDIO; // this uses mobile app webRTC
|
||||
} else {
|
||||
peerConnection.webRtcCallType = WEBRTC_CALL_TYPE_STANDARD; // this uses the webview webRTC
|
||||
}
|
||||
|
||||
return peerConnection.webRtcCallType;
|
||||
}
|
||||
|
||||
}
|
||||
// Store the method call sequential
|
||||
const sequenceHolder = {sequence: 0};
|
||||
|
||||
// Store the promise for each method call
|
||||
const promisesHolder = {};
|
||||
|
||||
// Call a method in the mobile application, returning a promise for its execution
|
||||
function callNativeMethod(method, args=[]) {
|
||||
try {
|
||||
const sequence = ++sequenceHolder.sequence;
|
||||
|
||||
return new Promise ( (resolve, reject) => {
|
||||
promisesHolder[sequence] = {
|
||||
resolve, reject
|
||||
};
|
||||
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({
|
||||
sequence: sequenceHolder.sequence,
|
||||
method: method,
|
||||
arguments: args,
|
||||
}));
|
||||
} );
|
||||
} catch(e) {
|
||||
logger.error(`Error on callNativeMethod ${e.message}`, e);
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called from the mobile app to notify us about a method invocation result
|
||||
window.nativeMethodCallResult = (sequence, isResolve, resultOrException) => {
|
||||
|
||||
const promise = promisesHolder[sequence];
|
||||
if(promise) {
|
||||
if(isResolve) {
|
||||
promise.resolve( resultOrException );
|
||||
delete promisesHolder[sequence];
|
||||
} else {
|
||||
promise.reject( resultOrException );
|
||||
delete promisesHolder[sequence];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// WebRTC replacement functions
|
||||
const buildVideoTrack = function () {}
|
||||
const stream = {};
|
||||
|
||||
// Navigator
|
||||
navigator.getDisplayMedia = function() {
|
||||
logger.info(`BBB-MOBILE - getDisplayMedia called`, arguments);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
callNativeMethod('initializeScreenShare').then(
|
||||
() => {
|
||||
const fakeVideoTrack = {};
|
||||
fakeVideoTrack.applyConstraints = function (constraints) {
|
||||
return new Promise(
|
||||
(resolve, reject) => {
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
};
|
||||
fakeVideoTrack.onended = null; // callbacks added from screenshare (we can use it later)
|
||||
fakeVideoTrack.oninactive = null; // callbacks added from screenshare (we can use it later)
|
||||
fakeVideoTrack.addEventListener = function() {}; // skip listeners
|
||||
|
||||
const videoTracks = [
|
||||
fakeVideoTrack
|
||||
];
|
||||
stream.getTracks = stream.getVideoTracks = function () {
|
||||
return videoTracks;
|
||||
};
|
||||
stream.active=true;
|
||||
resolve(stream);
|
||||
}
|
||||
).catch(
|
||||
(e) => {
|
||||
logger.error(`Failure calling native initializeScreenShare`, e.message)
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// RTCPeerConnection
|
||||
const prototype = window.RTCPeerConnection.prototype;
|
||||
|
||||
prototype.originalCreateOffer = prototype.createOffer;
|
||||
prototype.createOffer = function (options) {
|
||||
const webRtcCallType = detectWebRtcCallType('createOffer', this);
|
||||
|
||||
if(webRtcCallType === WEBRTC_CALL_TYPE_STANDARD){
|
||||
return prototype.originalCreateOffer.call(this, ...arguments);
|
||||
}
|
||||
logger.info(`BBB-MOBILE - createOffer called`, {options});
|
||||
|
||||
const createOfferMethod = (webRtcCallType === WEBRTC_CALL_TYPE_SCREEN_SHARE) ? 'createScreenShareOffer' : 'createFullAudioOffer';
|
||||
|
||||
return new Promise( (resolve, reject) => {
|
||||
callNativeMethod(createOfferMethod).then ( sdp => {
|
||||
logger.info(`BBB-MOBILE - createOffer resolved`, {sdp});
|
||||
|
||||
// send offer to BBB code
|
||||
resolve({
|
||||
type: 'offer',
|
||||
sdp
|
||||
});
|
||||
});
|
||||
} );
|
||||
};
|
||||
|
||||
prototype.originalAddEventListener = prototype.addEventListener;
|
||||
prototype.addEventListener = function (event, callback) {
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addEventListener', this, arguments)){
|
||||
return prototype.originalAddEventListener.call(this, ...arguments);
|
||||
}
|
||||
|
||||
logger.info(`BBB-MOBILE - addEventListener called`, {event, callback});
|
||||
|
||||
switch(event) {
|
||||
case 'icecandidate':
|
||||
window.bbbMobileScreenShareIceCandidateCallback = function () {
|
||||
logger.info("Received a bbbMobileScreenShareIceCandidateCallback call with arguments", arguments);
|
||||
if(callback){
|
||||
callback.apply(this, arguments);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'signalingstatechange':
|
||||
window.bbbMobileScreenShareSignalingStateChangeCallback = function (newState) {
|
||||
this.signalingState = newState;
|
||||
callback();
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
prototype.originalSetLocalDescription = prototype.setLocalDescription;
|
||||
prototype.setLocalDescription = function (description, successCallback, failureCallback) {
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('setLocalDescription', this)){
|
||||
return prototype.originalSetLocalDescription.call(this, ...arguments);
|
||||
}
|
||||
logger.info(`BBB-MOBILE - setLocalDescription called`, {description, successCallback, failureCallback});
|
||||
|
||||
// store the value
|
||||
this._localDescription = JSON.parse(JSON.stringify(description));
|
||||
// replace getter of localDescription to return this value
|
||||
Object.defineProperty(this, 'localDescription', {get: function() {return this._localDescription;},set: function(newValue) {}});
|
||||
|
||||
// return a promise that resolves immediately
|
||||
return new Promise( (resolve, reject) => {
|
||||
resolve();
|
||||
})
|
||||
}
|
||||
|
||||
prototype.originalSetRemoteDescription = prototype.setRemoteDescription;
|
||||
prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
|
||||
const webRtcCallType = detectWebRtcCallType('setRemoteDescription', this);
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === webRtcCallType){
|
||||
return prototype.originalSetRemoteDescription.call(this, ...arguments);
|
||||
}
|
||||
|
||||
logger.info(`BBB-MOBILE - setRemoteDescription called`, {description, successCallback, failureCallback});
|
||||
|
||||
this._remoteDescription = JSON.parse(JSON.stringify(description));
|
||||
Object.defineProperty(this, 'remoteDescription', {get: function() {return this._remoteDescription;},set: function(newValue) {}});
|
||||
|
||||
const setRemoteDescriptionMethod = (webRtcCallType === WEBRTC_CALL_TYPE_SCREEN_SHARE) ? 'setScreenShareRemoteSDP' : 'setFullAudioRemoteSDP';
|
||||
|
||||
return new Promise( (resolve, reject) => {
|
||||
callNativeMethod(setRemoteDescriptionMethod, [description]).then ( () => {
|
||||
logger.info(`BBB-MOBILE - setRemoteDescription resolved`);
|
||||
|
||||
resolve();
|
||||
|
||||
if(webRtcCallType === WEBRTC_CALL_TYPE_FULL_AUDIO) {
|
||||
Object.defineProperty(this, "iceGatheringState", {get: function() { return "complete" }, set: ()=>{} });
|
||||
Object.defineProperty(this, "iceConnectionState", {get: function() { return "completed" }, set: ()=>{} });
|
||||
this.onicegatheringstatechange && this.onicegatheringstatechange({target: this});
|
||||
this.oniceconnectionstatechange && this.oniceconnectionstatechange({target: this});
|
||||
}
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
prototype.originalAddTrack = prototype.addTrack;
|
||||
prototype.addTrack = function (description, successCallback, failureCallback) {
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addTrack', this)){
|
||||
return prototype.originalAddTrack.call(this, ...arguments);
|
||||
}
|
||||
|
||||
logger.info(`BBB-MOBILE - addTrack called`, {description, successCallback, failureCallback});
|
||||
}
|
||||
|
||||
prototype.originalGetLocalStreams = prototype.getLocalStreams;
|
||||
prototype.getLocalStreams = function() {
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('getLocalStreams', this)){
|
||||
return prototype.originalGetLocalStreams.call(this, ...arguments);
|
||||
}
|
||||
logger.info(`BBB-MOBILE - getLocalStreams called`, arguments);
|
||||
|
||||
//
|
||||
return [
|
||||
stream
|
||||
];
|
||||
}
|
||||
|
||||
prototype.originalAddTransceiver = prototype.addTransceiver;
|
||||
prototype.addTransceiver = function() {
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addTransceiver', this)){
|
||||
return prototype.originalAddTransceiver.call(this, ...arguments);
|
||||
}
|
||||
logger.info(`BBB-MOBILE - addTransceiver called`, arguments);
|
||||
}
|
||||
|
||||
prototype.originalAddIceCandidate = prototype.addIceCandidate;
|
||||
prototype.addIceCandidate = function (candidate) {
|
||||
if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addIceCandidate', this)){
|
||||
return prototype.originalAddIceCandidate.call(this, ...arguments);
|
||||
}
|
||||
logger.info(`BBB-MOBILE - addIceCandidate called`, {candidate});
|
||||
|
||||
return new Promise( (resolve, reject) => {
|
||||
callNativeMethod('addRemoteIceCandidate', [candidate]).then ( () => {
|
||||
logger.info("BBB-MOBILE - addRemoteIceCandidate resolved");
|
||||
|
||||
resolve();
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
// Handle screenshare stop
|
||||
const KurentoScreenShareBridge = require('/imports/api/screenshare/client/bridge/index.js').default;
|
||||
//Kurento Screen Share
|
||||
var stopOriginal = KurentoScreenShareBridge.stop.bind(KurentoScreenShareBridge);
|
||||
KurentoScreenShareBridge.stop = function(){
|
||||
callNativeMethod('stopScreenShare')
|
||||
logger.debug(`BBB-MOBILE - Click on stop screen share`);
|
||||
stopOriginal()
|
||||
}
|
||||
|
||||
// Handle screenshare stop requested by application (i.e. stopped the broadcast extension)
|
||||
window.bbbMobileScreenShareBroadcastFinishedCallback = function () {
|
||||
document.querySelector('[data-test="stopScreenShare"]')?.click();
|
||||
}
|
||||
|
||||
}
|
||||
})();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Bowser from 'bowser';
|
||||
|
||||
const BOWSER_RESULTS = Bowser.parse(window.navigator.userAgent);
|
||||
const userAgent = window.navigator.userAgent;
|
||||
const BOWSER_RESULTS = Bowser.parse(userAgent);
|
||||
|
||||
const isChrome = BOWSER_RESULTS.browser.name === 'Chrome';
|
||||
const isSafari = BOWSER_RESULTS.browser.name === 'Safari';
|
||||
@ -11,10 +12,12 @@ const isFirefox = BOWSER_RESULTS.browser.name === 'Firefox';
|
||||
const browserName = BOWSER_RESULTS.browser.name;
|
||||
const versionNumber = BOWSER_RESULTS.browser.version;
|
||||
|
||||
const isValidSafariVersion = Bowser.getParser(window.navigator.userAgent).satisfies({
|
||||
const isValidSafariVersion = Bowser.getParser(userAgent).satisfies({
|
||||
safari: '>12',
|
||||
});
|
||||
|
||||
const isMobileApp = !!(userAgent.match(/BBBMobile/i));
|
||||
|
||||
const browserInfo = {
|
||||
isChrome,
|
||||
isSafari,
|
||||
@ -24,6 +27,7 @@ const browserInfo = {
|
||||
browserName,
|
||||
versionNumber,
|
||||
isValidSafariVersion,
|
||||
isMobileApp
|
||||
};
|
||||
|
||||
export default browserInfo;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Bowser from 'bowser';
|
||||
|
||||
const BOWSER_RESULTS = Bowser.parse(window.navigator.userAgent);
|
||||
const userAgent = window.navigator.userAgent;
|
||||
const BOWSER_RESULTS = Bowser.parse(userAgent);
|
||||
|
||||
const isPhone = BOWSER_RESULTS.platform.type === 'mobile';
|
||||
// we need a 'hack' to correctly detect ipads with ios > 13
|
||||
@ -11,7 +12,7 @@ const osName = BOWSER_RESULTS.os.name;
|
||||
const osVersion = BOWSER_RESULTS.os.version;
|
||||
const isIos = osName === 'iOS';
|
||||
const isMacos = osName === 'macOS';
|
||||
const isIphone = !!(window.navigator.userAgent.match(/iPhone/i));
|
||||
const isIphone = !!(userAgent.match(/iPhone/i));
|
||||
|
||||
const SUPPORTED_IOS_VERSION = 12.2;
|
||||
const isIosVersionSupported = () => parseFloat(osVersion) >= SUPPORTED_IOS_VERSION;
|
||||
|
41
bigbluebutton-html5/package-lock.json
generated
41
bigbluebutton-html5/package-lock.json
generated
@ -3595,24 +3595,6 @@
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
|
||||
"dev": true
|
||||
},
|
||||
"is-extendable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
|
||||
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
|
||||
"requires": {
|
||||
"is-plain-object": "^2.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
|
||||
"requires": {
|
||||
"isobject": "^3.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@ -3733,11 +3715,6 @@
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
||||
"dev": true
|
||||
},
|
||||
"isobject": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
@ -5337,14 +5314,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"object.omit": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-3.0.0.tgz",
|
||||
"integrity": "sha512-EO+BCv6LJfu+gBIF3ggLicFebFLN5zqzz/WWJlMFfkMyGth+oBkhxzDl0wx2W4GkLzuQs/FsSkXZb2IMWQqmBQ==",
|
||||
"requires": {
|
||||
"is-extendable": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"object.values": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
|
||||
@ -5913,16 +5882,6 @@
|
||||
"tinycolor2": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"react-cursor-position": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-cursor-position/-/react-cursor-position-3.0.3.tgz",
|
||||
"integrity": "sha512-jrmHFKQtfNdvfJ5hIH+FOb2h9+mgcD8/POOY7LngmsYCJNlg6IYdnGdbMGMTeyue/iUvY+t20t20RDrH+qW5dw==",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.1",
|
||||
"object.omit": "^3.0.0",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
|
@ -363,7 +363,7 @@
|
||||
"app.endMeeting.noLabel": "لا",
|
||||
"app.about.title": "حول",
|
||||
"app.about.version": "نسخة التطبيق:",
|
||||
"app.about.version_label": "إصدار BigBlueButton:",
|
||||
"app.about.version_label": "إصدار بك بلو بتن:",
|
||||
"app.about.copyright": "حقوق الملكية :",
|
||||
"app.about.confirmLabel": "موافق",
|
||||
"app.about.confirmDesc": "موافق",
|
||||
@ -613,7 +613,7 @@
|
||||
"app.guest.errorSeeConsole": "خطأ: مزيد من التفاصيل في وحدة التحكم.",
|
||||
"app.guest.noModeratorResponse": "لا يوجد رد من المشرف.",
|
||||
"app.guest.noSessionToken": "لم يتم استلام رمز جلسة.",
|
||||
"app.guest.windowTitle": "BigBlueButton - ردهة الضيوف",
|
||||
"app.guest.windowTitle": "بك بلو بتن - ردهة الضيوف",
|
||||
"app.guest.missingToken": "الضيف يفتقد رمز الجلسة.",
|
||||
"app.guest.missingSession": "الضيف فقد الجلسة.",
|
||||
"app.guest.missingMeeting": "الاجتماع غير موجود.",
|
||||
@ -859,8 +859,8 @@
|
||||
"app.whiteboard.toolbar.fontSize": "قائمة حجم الخط",
|
||||
"app.whiteboard.toolbarAriaLabel": "أدوات العرض",
|
||||
"app.feedback.title": "قمت بتسجيل الخروج من المؤتمر",
|
||||
"app.feedback.subtitle": "نود أن نسمع عن تجربتك مع BigBlueButton (اختياري)",
|
||||
"app.feedback.textarea": "كيف يمكننا جعل BigBlueButton أفضل؟",
|
||||
"app.feedback.subtitle": "نود أن نسمع عن تجربتك مع بك بلو بتن (اختياري)",
|
||||
"app.feedback.textarea": "كيف يمكننا جعل بك بلو بتن أفضل؟",
|
||||
"app.feedback.sendFeedback": "ارسل رأيك",
|
||||
"app.feedback.sendFeedbackDesc": "أرسل ملاحظاتك وغادر الاجتماع",
|
||||
"app.videoDock.webcamMirrorLabel": "عكس",
|
||||
@ -1050,7 +1050,7 @@
|
||||
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "أو استخدم خادمنا التجريبي.",
|
||||
"mobileApp.portals.list.add.button.label": "أضف بوابة",
|
||||
"mobileApp.portals.fields.name.label": "اسم البوابة",
|
||||
"mobileApp.portals.fields.name.placeholder": "BigBlueButton التجريبي",
|
||||
"mobileApp.portals.fields.name.placeholder": "بك بلو بتن التجريبي",
|
||||
"mobileApp.portals.fields.url.label": "عنوان رابط للخادم",
|
||||
"mobileApp.portals.addPortalPopup.confirm.button.label": "حفظ",
|
||||
"mobileApp.portals.drawerNavigation.button.label": "البوابات",
|
||||
|
@ -132,6 +132,8 @@
|
||||
"app.userList.userOptions.savedNames.title": "Llista dels usuaris en la reunió {0} a {1}",
|
||||
"app.userList.userOptions.sortedFirstName.heading": "Ordenat pel nom:",
|
||||
"app.userList.userOptions.sortedLastName.heading": "Ordenat pel cognom:",
|
||||
"app.userList.userOptions.hideViewersCursor": "Els cursors de l'espectador estan bloquejats",
|
||||
"app.userList.userOptions.showViewersCursor": "Els cursors de l'espectador estan desbloquejats",
|
||||
"app.media.label": "Media",
|
||||
"app.media.autoplayAlertDesc": "Permet accés",
|
||||
"app.media.screenshare.start": "Inici de pantalla compartida",
|
||||
@ -171,6 +173,7 @@
|
||||
"app.presentation.options.fullscreen": "Pantalla completa",
|
||||
"app.presentation.options.exitFullscreen": "Surt de la pantalla completa",
|
||||
"app.presentation.options.minimize": "Minimitzar",
|
||||
"app.presentation.options.snapshot": "Instantània de la diapositiva actual",
|
||||
"app.presentation.options.downloading": "Descarregant...",
|
||||
"app.presentation.options.downloaded": "S'ha descarregat la presentació actual",
|
||||
"app.presentation.options.downloadFailed": "No s'ha pogut descarregar la presentació actual",
|
||||
@ -503,6 +506,8 @@
|
||||
"app.breakoutJoinConfirmation.freeJoinMessage": "Escull la sala separada per a unir-se",
|
||||
"app.breakoutTimeRemainingMessage": "Temps restant a la sala separada: {0}",
|
||||
"app.breakoutWillCloseMessage": "Temps finalitzat. La reunió separada es tancarà aviat",
|
||||
"app.breakout.dropdown.manageDuration": "Canviar la durada",
|
||||
"app.breakout.dropdown.destroyAll": "Finalitza les sales externes",
|
||||
"app.breakout.dropdown.options": "Opcions de sales externes",
|
||||
"app.calculatingBreakoutTimeRemaining": "Calculant temps restant ...",
|
||||
"app.audioModal.ariaTitle": "Entra a l'àudio modal",
|
||||
@ -559,6 +564,7 @@
|
||||
"app.audio.audioSettings.descriptionLabel": "Tingueu en compte que apareixerà un diàleg al navegador que requereix que accepteu compartir el micròfon.",
|
||||
"app.audio.audioSettings.microphoneSourceLabel": "Font del micròfon",
|
||||
"app.audio.audioSettings.speakerSourceLabel": "Font d'altaveu",
|
||||
"app.audio.audioSettings.testSpeakerLabel": "Prova l'altaveu",
|
||||
"app.audio.audioSettings.microphoneStreamLabel": "El seu volum d'emissió",
|
||||
"app.audio.audioSettings.retryLabel": "Reintentar",
|
||||
"app.audio.listenOnly.backLabel": "Enrere",
|
||||
@ -597,6 +603,7 @@
|
||||
"app.error.500": "Oh oh, quelcom ha anat malament",
|
||||
"app.error.userLoggedOut": "L'usuari té un sessionToken no vàlid a causa del tancament de sessió",
|
||||
"app.error.ejectedUser": "L'usuari té un sessionToken no vàlid a causa de l'expulsió",
|
||||
"app.error.joinedAnotherWindow": "Aquesta sessió sembla estar oberta en una altra finestra del navegador.",
|
||||
"app.error.userBanned": "L'usuari ha estat expulsat",
|
||||
"app.error.leaveLabel": "Inicieu la sessió de nou",
|
||||
"app.error.fallback.presentation.title": "Hi ha hagut un error",
|
||||
@ -677,6 +684,10 @@
|
||||
"app.shortcut-help.toggleFullscreen": "Alternar la pantalla completa (Presentador)",
|
||||
"app.shortcut-help.nextSlideDesc": "Diapositiva següent (presentador)",
|
||||
"app.shortcut-help.previousSlideDesc": "Diapositiva anterior (presentador)",
|
||||
"app.shortcut-help.togglePanKey": "Barra espaiadora",
|
||||
"app.shortcut-help.toggleFullscreenKey": "Enter",
|
||||
"app.shortcut-help.nextSlideKey": "Fletxa dreta",
|
||||
"app.shortcut-help.previousSlideKey": "Fletxa esquerra",
|
||||
"app.lock-viewers.title": "Bloqueja espectadors",
|
||||
"app.lock-viewers.description": "Aquestes opcions permeten restringir els espectadors a l'ús de funcions específiques.",
|
||||
"app.lock-viewers.featuresLable": "Característica",
|
||||
@ -692,6 +703,7 @@
|
||||
"app.lock-viewers.button.apply": "Aplica",
|
||||
"app.lock-viewers.button.cancel": "Cancel·la",
|
||||
"app.lock-viewers.locked": "Bloquejat/da",
|
||||
"app.lock-viewers.hideViewersCursor": "Veure altres cursors dels espectadors",
|
||||
"app.guest-policy.ariaTitle": "Modalitat de configuració de la política de convidats",
|
||||
"app.guest-policy.title": "Política de convidats",
|
||||
"app.guest-policy.description": "Canviar la configuració de la política de convidats a les reunions",
|
||||
@ -795,6 +807,7 @@
|
||||
"app.video.virtualBackground.genericError": "No s'ha pogut aplicar l'efecte de càmara. Intenta-ho de nou.",
|
||||
"app.video.virtualBackground.camBgAriaDesc": "Estableix el fons virtual de la càmera web en {0}",
|
||||
"app.video.camCapReached": "No es poden compartir més càmeres",
|
||||
"app.video.meetingCamCapReached": "La reunió ha arribat al límit de càmeres simultànies",
|
||||
"app.video.dropZoneLabel": "Deixar caure aquí",
|
||||
"app.fullscreenButton.label": "Fer {0} a pantalla completa",
|
||||
"app.fullscreenUndoButton.label": "Desfés {0} pantalla completa",
|
||||
@ -918,6 +931,8 @@
|
||||
"app.externalVideo.refreshLabel": "Actualitzar el reproductor de vídeo",
|
||||
"app.externalVideo.fullscreenLabel": "Reproductor de vídeo",
|
||||
"app.externalVideo.noteLabel": "Nota: els vídeos externs compartits no apareixeran en l'enregistrament. No s'hi admeten vídeos de YouTube, Vimeo, Instructure Media, Twithc, Dailymotion ni URL de fitxers multimèdia (p. ex. https://example.com/xy.mp4).",
|
||||
"app.externalVideo.subtitlesOn": "Apagar",
|
||||
"app.externalVideo.subtitlesOff": "Encendre (si està disponible)",
|
||||
"app.actionsBar.actionsDropdown.shareExternalVideo": "Comparteix un vídeo extern",
|
||||
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Deixa de compartir els vídeos externs",
|
||||
"app.iOSWarning.label": "Actualitzeu a iOS 12.2 o superior",
|
||||
@ -947,6 +962,7 @@
|
||||
"playback.button.search.aria": "Cerca",
|
||||
"playback.button.section.aria": "Secció lateral",
|
||||
"playback.button.swap.aria": "Intercanviar continguts",
|
||||
"playback.button.theme.aria": "Alternar el tema",
|
||||
"playback.error.wrapper.aria": "Àrea d'error",
|
||||
"playback.loader.wrapper.aria": "Àrea de càrrega",
|
||||
"playback.player.wrapper.aria": "Àrea de jugadors",
|
||||
@ -1030,10 +1046,17 @@
|
||||
"app.learningDashboard.statusTimelineTable.thumbnail": "Presentació en miniatura.",
|
||||
"app.learningDashboard.errors.invalidToken": "Token de sessió no vàlid",
|
||||
"app.learningDashboard.errors.dataUnavailable": "Les dades ja no estan disponibles",
|
||||
"mobileApp.portals.list.empty.addFirstPortal.label": "Afegeix el teu primer portal utilitzant el botó de dalt,",
|
||||
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "o utilitza el nostre servidor de demostració.",
|
||||
"mobileApp.portals.list.add.button.label": "Afegir portal",
|
||||
"mobileApp.portals.fields.name.label": "Nom del portal",
|
||||
"mobileApp.portals.fields.name.placeholder": "BigBlueButton demo",
|
||||
"mobileApp.portals.fields.url.label": "URL del servidor",
|
||||
"mobileApp.portals.drawerNavigation.button.label": "Portals"
|
||||
"mobileApp.portals.addPortalPopup.confirm.button.label": "Guardar",
|
||||
"mobileApp.portals.drawerNavigation.button.label": "Portals",
|
||||
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Camps obligatoris",
|
||||
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Nom ja utilitzat",
|
||||
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Error en intentar carregar la pàgina - comprovi la URL i la connexió de xarxa"
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
"app.home.greeting": "Zure aurkezpena laster hasiko da...",
|
||||
"app.chat.submitLabel": "Bidali mezua",
|
||||
"app.chat.loading": "Kargatutako txat mezuak: {0}%",
|
||||
"app.chat.errorMaxMessageLength": "Mezua luzeegia da, {0} karaktere soberan ditu",
|
||||
"app.chat.errorMaxMessageLength": "Mezua luzeegia da, {0} karaktere soberan d(it)u",
|
||||
"app.chat.disconnected": "Deskonektatuta zaude, mezuak ezin dira bidali",
|
||||
"app.chat.locked": "Txata blokeatuta dago, mezuak ezin dira bidali",
|
||||
"app.chat.inputLabel": "Txatean {0} mezu sartu dira",
|
||||
|
@ -40,8 +40,16 @@
|
||||
"app.captions.menu.backgroundColor": "צבע רקע",
|
||||
"app.captions.menu.previewLabel": "תצוגה מקדימה",
|
||||
"app.captions.menu.cancelLabel": "ביטול",
|
||||
"app.captions.hide": "הסתרת כתוביות",
|
||||
"app.captions.ownership": "לקיחת שליטה",
|
||||
"app.captions.dictationStart": "התחלת הכתבה",
|
||||
"app.captions.dictationStop": "הפסקת הכתבה",
|
||||
"app.textInput.sendLabel": "נשלח",
|
||||
"app.title.defaultViewLabel": "ברירת מחדל לצפייה במצגת",
|
||||
"app.notes.title": "פתקים משותפים",
|
||||
"app.notes.label": "פתקים",
|
||||
"app.notes.hide": "הסתרת פתקים",
|
||||
"app.notes.locked": "נעול",
|
||||
"app.user.activityCheck": "בדיקת זמינות משתמש",
|
||||
"app.user.activityCheck.label": "בדיקה אם המשתמש עדיין במפגש ({0})",
|
||||
"app.user.activityCheck.check": "בדיקה",
|
||||
@ -49,12 +57,16 @@
|
||||
"app.userList.participantsTitle": "משתתפים",
|
||||
"app.userList.messagesTitle": "הודעות",
|
||||
"app.userList.notesTitle": "הערות",
|
||||
"app.userList.notesListItem.unreadContent": "תוכן חדש זמין באזור הערות משותפות",
|
||||
"app.userList.captionsTitle": "כתוביות",
|
||||
"app.userList.presenter": "מנחה",
|
||||
"app.userList.you": "את/ה",
|
||||
"app.userList.locked": "נעול",
|
||||
"app.userList.byModerator": "מאת (מנחה)",
|
||||
"app.userList.label": "משתתפים",
|
||||
"app.userList.toggleCompactView.label": "מעבר למצב צפיה מצומצם",
|
||||
"app.userList.moderator": "מנהל/ת",
|
||||
"app.userList.mobile": "מכשיר סלולרי",
|
||||
"app.userList.guest": "אורח",
|
||||
"app.userList.sharingWebcam": "מצלמה",
|
||||
"app.userList.menuTitleContext": "אפשרויות",
|
||||
@ -64,9 +76,11 @@
|
||||
"app.userList.menu.clearStatus.label": "איפוס מצב",
|
||||
"app.userList.menu.removeUser.label": "הוצאת משתתף",
|
||||
"app.userList.menu.removeConfirmation.label": "הסרת משתתף ({0})",
|
||||
"app.userlist.menu.removeConfirmation.desc": "מניעת משתמש זה מלהצטרף שוב להפעלה.",
|
||||
"app.userList.menu.muteUserAudio.label": "השתקה",
|
||||
"app.userList.menu.unmuteUserAudio.label": "ביטול השתקת משתמש",
|
||||
"app.userList.menu.giveWhiteboardAccess.label" : "מתן גישה ללוח־ציור משותף",
|
||||
"app.userList.menu.ejectUserCameras.label": "סגירת מצלמות",
|
||||
"app.userList.userAriaLabel": "{0} {1} {2} במצב {3}",
|
||||
"app.userList.menu.promoteUser.label": "עדכון תפקיד למנחה",
|
||||
"app.userList.menu.demoteUser.label": "עדכון תפקיד לצופה",
|
||||
@ -84,6 +98,9 @@
|
||||
"app.userList.userOptions.unmuteAllLabel": "ביטול השתקה במפגש",
|
||||
"app.userList.userOptions.unmuteAllDesc": "ביטול השתקה במפגש",
|
||||
"app.userList.userOptions.lockViewersLabel": "נעילת מצב צופים",
|
||||
"app.userList.userOptions.lockViewersDesc": "נעילת פונקציות מסוימות עבור המשתתפים במפגש",
|
||||
"app.userList.userOptions.guestPolicyLabel": "מדיניות אורחים",
|
||||
"app.userList.userOptions.guestPolicyDesc": "שינוי הגדרת המדיניות עבור אורחים במפגש",
|
||||
"app.userList.userOptions.disableCam": "מצלמות הצופים בוטלו",
|
||||
"app.userList.userOptions.disableMic": "כל הצופים הושתקו",
|
||||
"app.userList.userOptions.disablePrivChat": "שיחה פרטית מבוטלת",
|
||||
@ -97,22 +114,44 @@
|
||||
"app.userList.userOptions.enablePubChat": "רב־שיח ציבורי מאופשר",
|
||||
"app.userList.userOptions.showUserList": "רשימת המשתתפים גלויה לצופים",
|
||||
"app.userList.userOptions.enableOnlyModeratorWebcam": "ניתן להדליק את מצלמת הרשת שלך כעת! כולם יראו אותך",
|
||||
"app.userList.userOptions.sortedFirstName.heading": "ממוין לפי שם פרטי:",
|
||||
"app.userList.userOptions.sortedLastName.heading": "ממומין לפי שם משפחה:",
|
||||
"app.media.label": "מדיה",
|
||||
"app.media.autoplayAlertDesc": "אפשרות גישה",
|
||||
"app.media.screenshare.start": "שיתוף מסך החל",
|
||||
"app.media.screenshare.end": "שיתוף מסך הסתיים",
|
||||
"app.media.screenshare.endDueToDataSaving": "שיתוף המסך הופסק עקב שמירת נתונים",
|
||||
"app.media.screenshare.unavailable": "שיתוף מסך לא זמין",
|
||||
"app.media.screenshare.notSupported": "שיתוף מסך אינו נתמך ע\"י דפדפן זה.",
|
||||
"app.media.screenshare.autoplayBlockedDesc": "נדרש אישור להצגת מסך המנחה.",
|
||||
"app.media.screenshare.autoplayAllowLabel": "צפייה בשיתוף מסך",
|
||||
"app.screenshare.presenterLoadingLabel": "שיתוף המסך שלך באמצע טעינה",
|
||||
"app.screenshare.viewerLoadingLabel": "מסך המגיש באמצע טעינה",
|
||||
"app.screenshare.presenterSharingLabel": "שיתוף המסך שלך מתבצע כעת",
|
||||
"app.meeting.ended": "המפגש הסתיים",
|
||||
"app.meeting.meetingTimeRemaining": "זמן נותר למפגש: {0}",
|
||||
"app.meeting.meetingTimeHasEnded": "המפגש הסתיים ויסגר בקרוב",
|
||||
"app.meeting.endedByUserMessage": "מפגש זה הסתיים ע\"י {0}",
|
||||
"app.meeting.endedByNoModeratorMessageSingular": "הפגישה הסתיימה עקב אי נוכחות המנחה לאחר דקה אחת",
|
||||
"app.meeting.endedByNoModeratorMessagePlural": "הפגישה הסתיימה בגלל שאין מנחה נוכח לאחר {0} אחת",
|
||||
"app.meeting.endedMessage": "הפניה למסך הבית",
|
||||
"app.meeting.alertMeetingEndsUnderMinutesSingular": "הפגישה עומדת להסתיים עוד דקה אחת.",
|
||||
"app.meeting.alertMeetingEndsUnderMinutesPlural": "הפגישה עומדת להסתיים עוד {0} אחת.",
|
||||
"app.meeting.alertBreakoutEndsUnderMinutesPlural": "ההפסקה עומדת להסתיים עוד {0} אחת.",
|
||||
"app.meeting.alertBreakoutEndsUnderMinutesSingular": "ההפסקה עומדת להסתיים עוד דקה אחת.",
|
||||
"app.presentation.hide": "הסתרת מצגת",
|
||||
"app.presentation.notificationLabel": "מצגת נוכחית",
|
||||
"app.presentation.downloadLabel": "הורדת קובץ",
|
||||
"app.presentation.slideContent": "תוכן עמוד המצגת",
|
||||
"app.presentation.startSlideContent": "התחלת המצגת",
|
||||
"app.presentation.endSlideContent": "סיום המצגת",
|
||||
"app.presentation.emptySlideContent": "עמוד מצגת נוכחי ללא תוכן",
|
||||
"app.presentation.options.fullscreen": "מסך מלא",
|
||||
"app.presentation.options.exitFullscreen": "יציאה ממסך מלא",
|
||||
"app.presentation.options.snapshot": "תמונת מצב של התמונה הנוכחית במצגת",
|
||||
"app.presentation.options.downloading": "הורדת קובץ ...",
|
||||
"app.presentation.options.downloaded": "התבצעה הורדה של המצגת הנוכחית ",
|
||||
"app.presentation.options.downloadFailed": " הורדה של המצגת הנוכחית נכשלה",
|
||||
"app.presentation.presentationToolbar.noNextSlideDesc": "סיום מצגת",
|
||||
"app.presentation.presentationToolbar.noPrevSlideDesc": "התחלת מצגת",
|
||||
"app.presentation.presentationToolbar.selectLabel": "בחירת עמוד",
|
||||
@ -137,6 +176,7 @@
|
||||
"app.presentation.presentationToolbar.fitToWidth": "התאמת רוחב",
|
||||
"app.presentation.presentationToolbar.fitToPage": "התאמה לעמוד",
|
||||
"app.presentation.presentationToolbar.goToSlide": "עמוד {0}",
|
||||
"app.presentation.placeholder": "אין כרגע מצגת פעילה",
|
||||
"app.presentationUploder.title": "מצגת",
|
||||
"app.presentationUploder.message": "כמגיש/ה יש לך יכולת להעלות כל מסמך אופיס או קובץ PDF. אנו ממליצים על קובץ PDF לתוצאות טובות ביותר. אנא ודאו שמצגת נבחרת באמצעות תיבת הסימון המעגלית בצד ימין.",
|
||||
"app.presentationUploder.uploadLabel": "העלאה",
|
||||
@ -151,25 +191,46 @@
|
||||
"app.presentationUploder.fileToUpload": "להעלאה ...",
|
||||
"app.presentationUploder.currentBadge": "נוכחי",
|
||||
"app.presentationUploder.rejectedError": "לא ניתן להעלות קבצים מסוג זה.",
|
||||
"app.presentationUploder.connectionClosedError": "תקלה עקב קליטה ירודה. נא נסו שוב.",
|
||||
"app.presentationUploder.upload.progress": "מעלה ({0}%)",
|
||||
"app.presentationUploder.upload.413": "הקובץ גדול מדי, חרג מהמקסימום של {0} MB",
|
||||
"app.presentationUploder.genericError": "אופס, משהו השתבש..",
|
||||
"app.presentationUploder.conversion.conversionProcessingSlides": "מעבד דף {0} מתוך {1}",
|
||||
"app.presentationUploder.conversion.genericConversionStatus": "ממיר קבצים ...",
|
||||
"app.presentationUploder.conversion.generatingThumbnail": "מייצר תצוגה מקדימה ...",
|
||||
"app.presentationUploder.conversion.generatedSlides": "שקופיות הומרו בהצלחה ...",
|
||||
"app.presentationUploder.conversion.generatingSvg": "ממיר קבצי SVG...",
|
||||
"app.presentationUploder.conversion.pageCountExceeded": "מספר הדפים חרג מהמקסימום של {0}",
|
||||
"app.presentationUploder.conversion.officeDocConversionInvalid": "אירעה שגיאה במהלך הנסיון להציג את מסמך האופיס, אנא העלה מסמך PDF במקום",
|
||||
"app.presentationUploder.conversion.officeDocConversionFailed": "אירעה שגיאה במהלך הנסיון להציג את מסמך האופיס, אנא העלה מסמך PDF במקום",
|
||||
"app.presentationUploder.conversion.pdfHasBigPage": "נכשל נסיון המרת הקובץ PDF, אנא נסו לשנות את הגודל שלו. גודל מקסימלי של דף הוא {0}",
|
||||
"app.presentationUploder.conversion.timeout": "המרת הקובץ ארכה זמן רב מדי, אנא נסה שנית",
|
||||
"app.presentationUploder.conversion.pageCountFailed": "אירעה שגיאה בנסיון לקבוע את מספר העמודים במצגת",
|
||||
"app.presentationUploder.conversion.unsupportedDocument": "סיומת הקובץ אינה נתמכת",
|
||||
"app.presentationUploder.isDownloadableLabel": "הורדת מצגת אינה מותרת - לחצו כדי לאפשר הורדת מצגת",
|
||||
"app.presentationUploder.isNotDownloadableLabel": "הורדת המצגת מותרת - לחצו כדי לבטל אפשרות של הורדת המצגת",
|
||||
"app.presentationUploder.removePresentationLabel": "הסרת מצגת",
|
||||
"app.presentationUploder.setAsCurrentPresentation": "הגדירו את המצגת הנוכחית כעדכנית",
|
||||
"app.presentationUploder.tableHeading.filename": "שם הקובץ",
|
||||
"app.presentationUploder.tableHeading.options": "אפשרויות",
|
||||
"app.presentationUploder.tableHeading.status": "מצב",
|
||||
"app.presentationUploder.uploadStatus": "{0} מתוך {1} העלאות הושלמו",
|
||||
"app.presentationUploder.completed": " {0} העלאות הושלמו",
|
||||
"app.presentationUploder.item" : "פריט",
|
||||
"app.presentationUploder.itemPlural" : "פריטים",
|
||||
"app.presentationUploder.clearErrors": "ניקוי שגיאות",
|
||||
"app.presentationUploder.clearErrorsDesc": "מנקה העלאות של מצגות שנכשלו ",
|
||||
"app.presentationUploder.uploadViewTitle": "העלאות של מצגות",
|
||||
"app.poll.pollPaneTitle": "סקר",
|
||||
"app.poll.enableMultipleResponseLabel": "לאפשר מספר תשובות לכל משיב?",
|
||||
"app.poll.quickPollTitle": "סקר מהיר",
|
||||
"app.poll.hidePollDesc": "הסתרת תפריט הסקר",
|
||||
"app.poll.quickPollInstruction": "בחירת אפשרות להתחלת הסקר.",
|
||||
"app.poll.activePollInstruction": "יציאה ממסך זה על מנת לראות את התשובות לסקר בזמן אמת, כשאת/ה מוכן - יש לבחור 'פרסום תוצאות סקר' כדי לפרסם את תוצאותיו לשאר המשתתפים",
|
||||
"app.poll.dragDropPollInstruction": "כדי למלא את ערכי הסקר, יש לגרור קובץ טקסט עם ערכי הסקר אל השדה המודגש",
|
||||
"app.poll.customPollTextArea": "מלאו את ערכי הסקר",
|
||||
"app.poll.publishLabel": "פרסום הסקר",
|
||||
"app.poll.cancelPollLabel": "ביטול",
|
||||
"app.poll.backLabel": "התחלת סקר",
|
||||
"app.poll.closeLabel": "סגירה",
|
||||
"app.poll.waitingLabel": "מחכה למענה ({0}/{1})",
|
||||
@ -177,12 +238,29 @@
|
||||
"app.poll.customPlaceholder": "הוספת אפשרות מענה",
|
||||
"app.poll.noPresentationSelected": "לא נבחרה מצגת! אנא בחרו אחת.",
|
||||
"app.poll.clickHereToSelect": "לחיצה כאן לבחירה",
|
||||
"app.poll.question.label" : "נא הקלידו את השאלה שלכם...",
|
||||
"app.poll.optionalQuestion.label" : "נא הקלידו את השאלה שלכם (לא חובה)...",
|
||||
"app.poll.userResponse.label" : "תגובת המשתמש",
|
||||
"app.poll.responseTypes.label" : "סוגי תגובה",
|
||||
"app.poll.optionDelete.label" : "מחיקה",
|
||||
"app.poll.responseChoices.label" : "אפשרויות תגובה",
|
||||
"app.poll.typedResponse.desc" : "למשתמשים תוצג תיבת טקסט למילוי תגובתם.",
|
||||
"app.poll.addItem.label" : "הוספת פריט",
|
||||
"app.poll.start.label" : "התחלת סקר",
|
||||
"app.poll.secretPoll.label" : "סקר אנונימי",
|
||||
"app.poll.secretPoll.isSecretLabel": "הסקר אנונימי. אין אפשרות לצפות בתגובות של משתמשים האחרים",
|
||||
"app.poll.questionErr": "נדרשת מתן שאלה.",
|
||||
"app.poll.optionErr": "אנא הוסיפו אפשרות סקר",
|
||||
"app.poll.startPollDesc": "התחלת הסקר",
|
||||
"app.poll.showRespDesc": "תצוגת הגדרת תגובה",
|
||||
"app.poll.deleteRespDesc": "הסרת אפשרות {0}",
|
||||
"app.poll.t": "אמת",
|
||||
"app.poll.f": "שקר",
|
||||
"app.poll.tf": "אמת / שקר",
|
||||
"app.poll.y": "כן",
|
||||
"app.poll.n": "לא",
|
||||
"app.poll.abstention": "הימנעות",
|
||||
"app.poll.yna": "כן / לא / הימנעות",
|
||||
"app.poll.a2": "א / ב",
|
||||
"app.poll.a3": "א / ב / ג",
|
||||
"app.poll.a4": "א / ב / ג / ד",
|
||||
@ -191,6 +269,7 @@
|
||||
"app.poll.answer.false": "שקר",
|
||||
"app.poll.answer.yes": "כן",
|
||||
"app.poll.answer.no": "לא",
|
||||
"app.poll.answer.abstention": "הימנעות",
|
||||
"app.poll.answer.a": "א",
|
||||
"app.poll.answer.b": "ב",
|
||||
"app.poll.answer.c": "ג",
|
||||
@ -198,17 +277,31 @@
|
||||
"app.poll.answer.e": "ה",
|
||||
"app.poll.liveResult.usersTitle": "משתתפים",
|
||||
"app.poll.liveResult.responsesTitle": "תשובה",
|
||||
"app.poll.liveResult.secretLabel": "זהו סקר אנונימי. תגובות אינן מוצגות",
|
||||
"app.poll.removePollOpt": "הוסרה אפשרות סקר {0}",
|
||||
"app.poll.emptyPollOpt": "ריק",
|
||||
"app.polling.pollingTitle": "אפשרויות סקר",
|
||||
"app.polling.pollQuestionTitle": "שאלת סקר",
|
||||
"app.polling.submitLabel": "שליחה",
|
||||
"app.polling.submitAriaLabel": "שליחת תגובה לסקר",
|
||||
"app.polling.responsePlaceholder": "הוספת תשובה",
|
||||
"app.polling.responseSecret": "סקר אנונימי – מציג הסקר אינו יכול לראות את תשובתכם",
|
||||
"app.polling.responseNotSecret": "סקר רגיל – מציג הסקר יכול לראות את תשובתכם",
|
||||
"app.polling.pollAnswerLabel": "מענה לסקר {0}",
|
||||
"app.polling.pollAnswerDesc": "בחירת אפשרות זו לבחירה ב {0}",
|
||||
"app.failedMessage": "מתנצלים, בעיה בחיבור לשרת.",
|
||||
"app.downloadPresentationButton.label": "הורדת המצגת המקורית",
|
||||
"app.connectingMessage": "מתחבר ...",
|
||||
"app.waitingMessage": "נותקת, מנסה להתחבר בעוד {0} שניות...",
|
||||
"app.retryNow": "נסו שנית",
|
||||
"app.muteWarning.label": "נא הקישו על {0} כדי לבטל את ההשתקה.",
|
||||
"app.muteWarning.disableMessage": "השתקת ההתראות מושבתת עד לביטול ההשתקה",
|
||||
"app.muteWarning.tooltip": "נא הקישו על סגירה והשבתת אזהרה עד להשתקה הבאה",
|
||||
"app.navBar.settingsDropdown.optionsLabel": "אפשרויות",
|
||||
"app.navBar.settingsDropdown.fullscreenLabel": "מסך מלא",
|
||||
"app.navBar.settingsDropdown.settingsLabel": "הגדרות",
|
||||
"app.navBar.settingsDropdown.aboutLabel": "אודות",
|
||||
"app.navBar.settingsDropdown.leaveSessionLabel": "עזיבת מפגש",
|
||||
"app.navBar.settingsDropdown.exitFullscreenLabel": "יציאה ממסך מלא",
|
||||
"app.navBar.settingsDropdown.fullscreenDesc": "מעבר ממסך ההגדרות למסך מלא",
|
||||
"app.navBar.settingsDropdown.settingsDesc": "עדכון הגדרות כלליות",
|
||||
@ -224,12 +317,16 @@
|
||||
"app.navBar.userListToggleBtnLabel": "הצגת/הסתרת רשימת משתתפים",
|
||||
"app.navBar.toggleUserList.ariaLabel": "הצגת/הסתרת רשימת הודעות ומשתתפים",
|
||||
"app.navBar.toggleUserList.newMessages": "עם התראה על הודעות חדשות",
|
||||
"app.navBar.toggleUserList.newMsgAria": "הודעה חדשה מ {0}",
|
||||
"app.navBar.recording": "מפגש זה מוקלט",
|
||||
"app.navBar.recording.on": "מקליט",
|
||||
"app.navBar.recording.off": "לא מקליט",
|
||||
"app.navBar.emptyAudioBrdige": "לא נמצא מיקרופון פעיל.",
|
||||
"app.leaveConfirmation.confirmLabel": "יציאה",
|
||||
"app.leaveConfirmation.confirmDesc": "התנתקות מהמפגש",
|
||||
"app.endMeeting.description": "פעולה זו תסיים את ההפעלה עבור {0} משתמש(ים) פעיל(ים). האם אתם בטוחים שברצונכם לסיים את פגישה זו?",
|
||||
"app.endMeeting.noUserDescription": "האם אתם בטוחים שאתם מעוניינים לסיים את המפגש?",
|
||||
"app.endMeeting.contentWarning": "לא תהייה נגישות ישירה להודעות צ'אט, פתקיות משותפות, תוכן לוח ציור ומסמכים משותפים, עבור הפעלה זו.",
|
||||
"app.endMeeting.yesLabel": "כן",
|
||||
"app.endMeeting.noLabel": "לא",
|
||||
"app.about.title": "אודות",
|
||||
@ -255,6 +352,16 @@
|
||||
"app.submenu.application.languageLabel": "שפה",
|
||||
"app.submenu.application.languageOptionLabel": "בחירת שפה",
|
||||
"app.submenu.application.noLocaleOptionLabel": "לא הוגדרה שפת ברירת מחדל",
|
||||
"app.submenu.application.paginationEnabledLabel": "מספור סרטוני וידאו",
|
||||
"app.submenu.application.layoutOptionLabel": "סגנון פריסה",
|
||||
"app.submenu.notification.SectionTitle": "התראות",
|
||||
"app.submenu.notification.Desc": "הגדירו כיצד ועל מה תקבלו התראה.",
|
||||
"app.submenu.notification.audioAlertLabel": "התראות שמע",
|
||||
"app.submenu.notification.pushAlertLabel": "התראות קופצות",
|
||||
"app.submenu.notification.messagesLabel": "הודעת צ'אט",
|
||||
"app.submenu.notification.userJoinLabel": "משתמש הצטרף",
|
||||
"app.submenu.notification.userLeaveLabel": "משתמש עזב",
|
||||
"app.submenu.notification.guestWaitingLabel": "אורח ממתין לאישור",
|
||||
"app.submenu.audio.micSourceLabel": "מיקרופון",
|
||||
"app.submenu.audio.speakerSourceLabel": "רמקול",
|
||||
"app.submenu.audio.streamVolumeLabel": "עוצמת שמע",
|
||||
@ -282,8 +389,11 @@
|
||||
"app.switch.offLabel": "כן",
|
||||
"app.talkingIndicator.ariaMuteDesc" : "בחירת השתקת משתמש",
|
||||
"app.talkingIndicator.isTalking" : "{0} מדבר/ת",
|
||||
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ מדברים",
|
||||
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ דיברו",
|
||||
"app.talkingIndicator.wasTalking" : "{0} הפסיק/ה לדבר",
|
||||
"app.actionsBar.actionsDropdown.actionsLabel": "פעולות נוספות",
|
||||
"app.actionsBar.actionsDropdown.presentationLabel": "ניהול מצגות",
|
||||
"app.actionsBar.actionsDropdown.initPollLabel": "התחלת סקר",
|
||||
"app.actionsBar.actionsDropdown.desktopShareLabel": "שיתוף מסך",
|
||||
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "שיתוף מסך לא מאופשר במפגש זה",
|
||||
@ -301,6 +411,8 @@
|
||||
"app.actionsBar.actionsDropdown.captionsDesc": "הצגת/הסתרת מסך הכתוביות",
|
||||
"app.actionsBar.actionsDropdown.takePresenter": "הפכי/וך עצמך למנחת/ה המפגש",
|
||||
"app.actionsBar.actionsDropdown.takePresenterDesc": "הפכי/וך עצמך למנחת/ה המפגש",
|
||||
"app.actionsBar.actionsDropdown.selectRandUserLabel": "אנא בחרו משתמש אקראי",
|
||||
"app.actionsBar.actionsDropdown.selectRandUserDesc": "אנא בחרו באופן אקראי משתמש מתוך הצופים הזמינים ",
|
||||
"app.actionsBar.emojiMenu.statusTriggerLabel": "עריכת מצב",
|
||||
"app.actionsBar.emojiMenu.awayLabel": "לא ליד המחשב",
|
||||
"app.actionsBar.emojiMenu.awayDesc": "עריכת המצב שלך ל'לא ליד המחשב'",
|
||||
@ -324,6 +436,14 @@
|
||||
"app.actionsBar.currentStatusDesc": "מצב נוכחי {0}",
|
||||
"app.actionsBar.captions.start": "הצגת כתוביות",
|
||||
"app.actionsBar.captions.stop": "הסתרת כתוביות",
|
||||
"app.audioNotification.audioFailedError1003": "גרסת הדפדפן אינה נתמכת (שגיאה 1003)",
|
||||
"app.audioNotification.audioFailedError1005": "השיחה הסתיימה באופן בלתי צפוי (שגיאה 1005)",
|
||||
"app.audioNotification.audioFailedError1006": "תם הזמן הקצוב לשיחה (שגיאה 1006)",
|
||||
"app.audioNotification.audioFailedError1007": "כשל בחיבור (שגיאת ICE 1007)",
|
||||
"app.audioNotification.audioFailedError1008": "ההעברה נכשלה (שגיאה 1008)",
|
||||
"app.audioNotification.audioFailedError1011": "תם זמן החיבור (שגיאת ICE 1011)",
|
||||
"app.audioNotification.audioFailedError1012": "החיבור נסגר (שגיאת ICE 1012)",
|
||||
"app.audioNotification.audioFailedMessage": "חיבור האודיו נכשל",
|
||||
"app.audioNotification.closeLabel": "סגירה",
|
||||
"app.audioNotificaion.reconnectingAsListenOnly": "דיבור לא מאופשר במפגש זה, אתה מחובר במצב האזנה בלבד",
|
||||
"app.breakoutJoinConfirmation.title": "הצטרפות לחדר למידה",
|
||||
@ -334,15 +454,20 @@
|
||||
"app.breakoutJoinConfirmation.freeJoinMessage": "בחירת חדר למידה שברצונך להצטרף אליו",
|
||||
"app.breakoutTimeRemainingMessage": "זמן נותר לחדר הלמידה: {0}",
|
||||
"app.breakoutWillCloseMessage": "נגמר הזמן. חדר הלמידה יסגר בקרוב",
|
||||
"app.breakout.dropdown.manageDuration": "שינוי משך הזמן",
|
||||
"app.breakout.dropdown.destroyAll": "סיום חדרי למידה",
|
||||
"app.calculatingBreakoutTimeRemaining": "מחשב זמן נותר ...",
|
||||
"app.audioModal.ariaTitle": "הצטרפות למפגש מקוון",
|
||||
"app.audioModal.microphoneLabel": "מיקרופון",
|
||||
"app.audioModal.listenOnlyLabel": "האזנה בלבד",
|
||||
"app.audioModal.microphoneDesc": "הצטרפות למפגש קולי מקוון עם מיקרופון",
|
||||
"app.audioModal.listenOnlyDesc": "הצטרפות למפגש קולי מקוון כמאזינים בלבד",
|
||||
"app.audioModal.audioChoiceLabel": "האם להצטרף למפגש הקולי?",
|
||||
"app.audioModal.iOSBrowser": "קול/וידאו לא נתמכים",
|
||||
"app.audioModal.iOSErrorDescription": "כרגע וידאו וקול לא נתמכים בדפדפן כרום למכשירי אפל",
|
||||
"app.audioModal.iOSErrorRecommendation": "מומלץ להשתמש בדפדפן ספארי על מכשיר זה",
|
||||
"app.audioModal.audioChoiceDesc": "איך ברצונך להצטרך למפגש הקולי?",
|
||||
"app.audioModal.unsupportedBrowserLabel": "נראה שאתם משתמשים בדפדפן שאינו נתמך במלואו. אנא השתמשו ב-{0} או ב-{1} לתמיכה מלאה.",
|
||||
"app.audioModal.closeLabel": "סגירה",
|
||||
"app.audioModal.yes": "כן",
|
||||
"app.audioModal.no": "לא",
|
||||
@ -351,22 +476,49 @@
|
||||
"app.audioModal.echoTestTitle": "זו בדיקת הד פרטית. יש להגיד כמה מילים. האם שמעת הד ?",
|
||||
"app.audioModal.settingsTitle": "עדכון הגדרות הקול שלך",
|
||||
"app.audioModal.helpTitle": "אירעה שגיאה בציוד הקול/וידאו",
|
||||
"app.audioModal.helpText": "האם נתתם אישור לגישה למיקרופון שלכם? שימו לב כי תיבת דו-שיח אמורה להופיע, כאשר אתה מנסה להצטרף למצב קולי , ובה בקשת גישה להרשאות מכשיר המדיה שלכם, אנא אשרו זאת על מנת שתוכלו להצטרף למפגש הקולי המקוון. אם זה לא המקרה, נסו לשנות את הרשאות המיקרופון שלכם בהגדרות הדפדפן שלכם.",
|
||||
"app.audioModal.help.noSSL": "דף זה אינו מאובטח. כדי שתתאפשר גישה למיקרופון, הדף חייב להיות מוצג ב-HTTPS. אנא פנו למנהל השרת.",
|
||||
"app.audioModal.help.macNotAllowed": "נראה שהעדפות מערכת ה-Mac שלכם חוסמות את הגישה למיקרופון שלכם. פתחו את העדפות מערכת > אבטחה ופרטיות > פרטיות > מיקרופון, וודאו שהדפדפן שבו אתם משתמשים, מסומן כפעיל.",
|
||||
"app.audioModal.audioDialTitle": "הצטרפו באמצאות הנייד שלכם.",
|
||||
"app.audioDial.audioDialDescription": "חיגו בבקשה",
|
||||
"app.audioDial.audioDialConfrenceText": "נא הזינו את מספר ה-PIN של המפגש המקוון :",
|
||||
"app.audioModal.autoplayBlockedDesc": "אנו זקוקים לרשותכם כדי לנגן שמע.",
|
||||
"app.audioModal.playAudio": "נגינת צליל",
|
||||
"app.audioModal.playAudio.arialabel" : "נגינת צליל",
|
||||
"app.audioDial.tipIndicator": "עצה",
|
||||
"app.audioDial.tipMessage": "לחיצה על מקש '0' בטלפון שלכם, תשתיק/תבבטל את ההשתקה.",
|
||||
"app.audioModal.connecting": "יצירת חיבור שמע",
|
||||
"app.audioManager.joinedAudio": "הצטרפות למפגש הקולי המקוון",
|
||||
"app.audioManager.leftAudio": "עזיבת המפגש הקולי המקוון",
|
||||
"app.audioManager.reconnectingAudio": "נסיון בחיבור חדש של הצליל",
|
||||
"app.audioManager.genericError": "שגיאה: אירעה שגיאה, אנא נסו שוב",
|
||||
"app.audioManager.connectionError": "שגיאה: שגיאת חיבור",
|
||||
"app.audioManager.mediaError": "שגיאה: הייתה בעיה בהשגת מכשירי המדיה שלכם",
|
||||
"app.audio.joinAudio": "הצטרפות למפגש קולי",
|
||||
"app.audio.leaveAudio": "עזיבת המפגש הקולי",
|
||||
"app.audio.changeAudioDevice": "שינוי התקן קולי",
|
||||
"app.audio.enterSessionLabel": "כניסה למפגש",
|
||||
"app.audio.playSoundLabel": "נגינת צליל",
|
||||
"app.audio.backLabel": "חזרה",
|
||||
"app.audio.loading": "טעינה",
|
||||
"app.audio.microphones": "מיקרופונים",
|
||||
"app.audio.speakers": "רמקולים",
|
||||
"app.audio.noDeviceFound": "לא נמצא מכשיר",
|
||||
"app.audio.audioSettings.titleLabel": "בחירת הגדרות הקול",
|
||||
"app.audio.audioSettings.descriptionLabel": "שים לב, יופיע חלון דו-שיח בדפדפן שלכם, המחייב אתכם לאשר את שיתוף המיקרופון שלכם.",
|
||||
"app.audio.audioSettings.microphoneSourceLabel": "מיקרופון",
|
||||
"app.audio.audioSettings.speakerSourceLabel": "רמקולים",
|
||||
"app.audio.audioSettings.testSpeakerLabel": "בדיקת הרמקול שלכם",
|
||||
"app.audio.audioSettings.microphoneStreamLabel": "עוצמת שמע",
|
||||
"app.audio.audioSettings.retryLabel": "ניסיון חוזר",
|
||||
"app.audio.listenOnly.backLabel": "חזרה",
|
||||
"app.audio.listenOnly.closeLabel": "סגירה",
|
||||
"app.audio.permissionsOverlay.title": "אפשרו גישה למיקרופון שלכם",
|
||||
"app.audio.permissionsOverlay.hint": "אנחנו צריכים שתאפשרו לנו להשתמש במכשירי המדיה שלכם כדי להצטרף אליכם למפגש הקולי :)",
|
||||
"app.error.removed": "הוסרתם מהמפגש המקוון",
|
||||
"app.error.meeting.ended": "התנתקתם מהמפגש המקוון",
|
||||
"app.meeting.logout.permissionEjectReason": "פסילה עקב הפרת הרשאה",
|
||||
"app.meeting.logout.ejectedFromMeeting": "הוסרתם מהמפגש",
|
||||
"app.meeting.logout.userInactivityEjectReason": "המשתמש לא היה פעיל במשך זמן רב",
|
||||
"app.meeting-ended.rating.legendLabel": "דרוג משוב",
|
||||
"app.meeting-ended.rating.starLabel": "כוכב",
|
||||
@ -375,10 +527,35 @@
|
||||
"app.modal.confirm": "הושלם",
|
||||
"app.modal.newTab": "(פתיחה בלשונית חדשה)",
|
||||
"app.modal.confirm.description": "שמירת שינויים וסגירת חלונית",
|
||||
"app.modal.randomUser.noViewers.description": "אין צופים זמינים שניתן לבחור אקראית מהם",
|
||||
"app.modal.randomUser.selected.description": "נבחרתם באופן אקראי",
|
||||
"app.modal.randomUser.title": "משתמש שנבחר באקראי",
|
||||
"app.modal.randomUser.who": "מי ייבחר..?",
|
||||
"app.modal.randomUser.alone": "ישנו צופה אחד בלבד",
|
||||
"app.modal.randomUser.reselect.label": "אנא בחרו שוב",
|
||||
"app.dropdown.close": "סגירה",
|
||||
"app.dropdown.list.item.activeLabel": "פעיל",
|
||||
"app.error.401": "לא מורשה",
|
||||
"app.error.403": "הוסרתם מהמפגש",
|
||||
"app.error.404": "לא נמצאו",
|
||||
"app.error.408": "אימות נכשל",
|
||||
"app.error.410": "המפגש הסתיים",
|
||||
"app.error.500": "אופס, משהו השתבש",
|
||||
"app.error.joinedAnotherWindow": "נראה שהמפגש הזה נפתח בחלון דפדפן אחר.",
|
||||
"app.error.leaveLabel": "התחברו שוב",
|
||||
"app.error.fallback.presentation.title": "התרחשה שגיאה",
|
||||
"app.error.fallback.presentation.reloadButton": "טעינה מחדש",
|
||||
"app.guest.waiting": "מחכים לאישורך להצטרף למפגש",
|
||||
"app.guest.noModeratorResponse": "אין תגובה מהמנחה",
|
||||
"app.guest.missingMeeting": "המפגש לא מתקיים",
|
||||
"app.guest.meetingEnded": "המפגש הסתיים",
|
||||
"app.guest.guestWait": "המתינו למנחה שיאשר את הצטרפותכם לפגישה.",
|
||||
"app.guest.guestDeny": "הכחשת אורח להצטרפות למפגישה",
|
||||
"app.guest.allow": "האורח אושר והופנה למפגש",
|
||||
"app.guest.firstPositionInWaitingQueue": "אתם הראשונים בתור!",
|
||||
"app.guest.positionInWaitingQueue": "המיקום הנוכחי שלכם בתור :",
|
||||
"app.guest.guestInvalid": "משתמש אורח אינו חוקי",
|
||||
"app.guest.meetingForciblyEnded": "איניכם יכולים להצטרף לפגישה שהסתיימה",
|
||||
"app.userList.guest.waitingUsers": "משתמשים ממתינים",
|
||||
"app.userList.guest.waitingUsersTitle": "ניהול משתמשים",
|
||||
"app.userList.guest.optionTitle": "סקירת משתמשים ממתינים",
|
||||
@ -387,9 +564,14 @@
|
||||
"app.userList.guest.allowEveryone": "אישור לכולם",
|
||||
"app.userList.guest.denyEveryone": "מניעה מכולם",
|
||||
"app.userList.guest.pendingUsers": "{0} משתמשים ממתינים",
|
||||
"app.userList.guest.noPendingUsers": "כרגע אין משתמשים שממתינים להצטרף..",
|
||||
"app.userList.guest.pendingGuestUsers": "{0} משתתפים ממתינים להצטרף",
|
||||
"app.userList.guest.pendingGuestAlert": "הצטרף/ה למפגש ומחכה לאישורך.",
|
||||
"app.userList.guest.rememberChoice": "זכירת בחירה",
|
||||
"app.userList.guest.emptyMessage": "כרגע אין הודעה",
|
||||
"app.userList.guest.privateMessageLabel": "הודעה",
|
||||
"app.userList.guest.acceptLabel": "אושר",
|
||||
"app.userList.guest.denyLabel": "נדחה",
|
||||
"app.user-info.title": "חיפוש תיקיה",
|
||||
"app.toast.breakoutRoomEnded": "מפגש חדר למידה הסתיים. בבקשה הצטרפו מחדש למפגש הקולי.",
|
||||
"app.toast.chat.public": "הודעת רב־שיח ציבורי חדשה",
|
||||
@ -410,9 +592,12 @@
|
||||
"app.shortcut-help.hidePrivateChat": "הסתרת רב־שיח פרטי",
|
||||
"app.shortcut-help.closePrivateChat": "סגירת שיחה פרטית",
|
||||
"app.shortcut-help.openActions": "פתיחת תפריט הפעולות",
|
||||
"app.shortcut-help.openDebugWindow": "פתיחת חלון של ניפוי שגיאות",
|
||||
"app.shortcut-help.openStatus": "פתיחת תפריט מצבים",
|
||||
"app.shortcut-help.nextSlideDesc": "עמוד הבאה (מנחה)",
|
||||
"app.shortcut-help.previousSlideDesc": "עמוד קודם (מנחה)",
|
||||
"app.shortcut-help.nextSlideKey": "חץ ימני",
|
||||
"app.shortcut-help.previousSlideKey": "חץ שמאלי",
|
||||
"app.lock-viewers.title": "נעילת הגדרות משתתפים",
|
||||
"app.lock-viewers.description": "מסך זה מאפשר לך לקבע את מצב השיתוף של הצופים.",
|
||||
"app.lock-viewers.featuresLable": "תכונה",
|
||||
@ -428,6 +613,9 @@
|
||||
"app.lock-viewers.button.apply": "אישור",
|
||||
"app.lock-viewers.button.cancel": "ביטול",
|
||||
"app.lock-viewers.locked": "לא מאופשר",
|
||||
"app.guest-policy.title": "מדיניות אורחים",
|
||||
"app.guest-policy.description": "שינוי הגדרת המדיניות של אורחים במפגש",
|
||||
"app.guest-policy.button.askModerator": "שאלה למנהל/ת",
|
||||
"app.recording.startTitle": "התחלת הקלטה",
|
||||
"app.recording.stopTitle": "השהית הקלטה",
|
||||
"app.recording.resumeTitle": "הפעלת הקלטה מחדש",
|
||||
@ -525,7 +713,10 @@
|
||||
"app.externalVideo.input": "כתובת וידאו חיצוני URL",
|
||||
"app.externalVideo.urlInput": "הוספת כתובת וידאו URL",
|
||||
"app.externalVideo.close": "סגירה",
|
||||
"playback.player.chat.wrapper.aria": "אזור רב־שיח"
|
||||
"playback.player.chat.wrapper.aria": "אזור רב־שיח",
|
||||
"app.learningDashboard.pollsTable.title": "סקרים",
|
||||
"app.learningDashboard.pollsTable.anonymousRowName": "אנונימי",
|
||||
"app.learningDashboard.statusTimelineTable.title": "ציר הזמן"
|
||||
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@
|
||||
"app.presentation.presentationToolbar.goToSlide": "{0}. dia",
|
||||
"app.presentation.placeholder": "Jelenleg nincs aktív előadás",
|
||||
"app.presentationUploder.title": "Prezentáció",
|
||||
"app.presentationUploder.message": "Előadóként tetszőleges office dokumentumot, illetve PDF fájlt fel tudsz tölteni. A legjobb eredmény érdekében javasoljuk PDF fájl használatát. Kérjük, ellenőrizd, hogy egy prezentációt kiválasztottál a jobb oldalon lévő jelölővel. ",
|
||||
"app.presentationUploder.message": "Előadóként tetszőleges office dokumentumot, illetve PDF fájlt fel tudsz tölteni. A legjobb eredmény érdekében javasoljuk PDF fájl használatát. Kérjük, ellenőrizd, hogy egy prezentációt kiválasztottál a jobb oldalon lévő kör alakú jelölővel. ",
|
||||
"app.presentationUploder.extraHint": "FONTOS: egyik fájl sem érheti el {0} MB-ot és {1} oldalt.",
|
||||
"app.presentationUploder.uploadLabel": "Feltöltés",
|
||||
"app.presentationUploder.confirmLabel": "Jóváhagyás",
|
||||
|
@ -173,6 +173,7 @@
|
||||
"app.presentation.options.fullscreen": "全画面表示",
|
||||
"app.presentation.options.exitFullscreen": "全画面表示解除",
|
||||
"app.presentation.options.minimize": "最小化",
|
||||
"app.presentation.options.snapshot": "現在のスライドのスナップショット",
|
||||
"app.presentation.options.downloading": "ダウンロード中...",
|
||||
"app.presentation.options.downloaded": "プレゼンファイルをダウンロードしました",
|
||||
"app.presentation.options.downloadFailed": "プレゼンファイルがダウンロードできませんでした",
|
||||
|
@ -6,6 +6,7 @@
|
||||
"app.chat.disconnected": "Jesteś rozłączony, wiadomości nie mogą zostać wysłane",
|
||||
"app.chat.locked": "Czat jest zablokowany, nie można wysyłać wiadomości",
|
||||
"app.chat.inputLabel": "Wyślij wiadomość do {0}",
|
||||
"app.chat.inputPlaceholder": "Wiadomość {0}",
|
||||
"app.chat.titlePublic": "Czat Publiczny",
|
||||
"app.chat.titlePrivate": "Czat Prywatny z {0}",
|
||||
"app.chat.partnerDisconnected": "{0} opuścił(a) spotkanie ",
|
||||
@ -24,6 +25,8 @@
|
||||
"app.chat.multi.typing": "Kilku uczestników teraz pisze",
|
||||
"app.chat.one.typing": "{0} teraz pisze",
|
||||
"app.chat.two.typing": "{0} oraz {1} teraz piszą",
|
||||
"app.chat.copySuccess": "Skopiowano transkrypcję czatu",
|
||||
"app.chat.copyErr": "Kopiowanie transkrypcji czatu nie powiodło się",
|
||||
"app.captions.label": "Napisy",
|
||||
"app.captions.menu.close": "Zamknij",
|
||||
"app.captions.menu.start": "Rozpocznij",
|
||||
@ -166,6 +169,7 @@
|
||||
"app.presentation.presentationToolbar.fitToWidth": "Dopasuj do szerokości",
|
||||
"app.presentation.presentationToolbar.fitToPage": "Dopasuj do strony",
|
||||
"app.presentation.presentationToolbar.goToSlide": "Slajd {0}",
|
||||
"app.presentation.placeholder": "Obecnie nikt nie prowadzi prezentacji",
|
||||
"app.presentationUploder.title": "Prezentacja",
|
||||
"app.presentationUploder.message": "Jako prezenter masz możliwość wgrania dowolnego dokumentu lub pliku PDF. Dla uzyskania lepszych rezultatów, zalecamy użycie pliku PDF. Upewnij się, że właściwa prezentacja jest wybrana. Wybierasz prezentację klikając okrągłe pole wyboru po jej prawej stronie.",
|
||||
"app.presentationUploder.uploadLabel": "Prześlij",
|
||||
@ -180,6 +184,7 @@
|
||||
"app.presentationUploder.fileToUpload": "Do przesłania...",
|
||||
"app.presentationUploder.currentBadge": "Bieżąca",
|
||||
"app.presentationUploder.rejectedError": "Plik(i) odrzucono. Sprawdź typ pliku(ów)",
|
||||
"app.presentationUploder.connectionClosedError": "Błąd z powodu słabej jakości połączenia. Spróbuj ponownie.",
|
||||
"app.presentationUploder.upload.progress": "Przesyłanie ({0}%)",
|
||||
"app.presentationUploder.upload.413": "Plik jest za duży, przekracza maksymalny rozmiar {0} MB",
|
||||
"app.presentationUploder.genericError": "Ups, coś poszło nie tak ...",
|
||||
@ -328,6 +333,7 @@
|
||||
"app.actionsBar.label": "Pasek akcji",
|
||||
"app.actionsBar.actionsDropdown.restorePresentationLabel": "Przywróć prezentację",
|
||||
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Zminimalizuj prezentację",
|
||||
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Przycisk używany do zminimalizowania prezentacji",
|
||||
"app.screenshare.screenShareLabel" : "Udostępnianie ekranu",
|
||||
"app.submenu.application.applicationSectionTitle": "Aplikacja",
|
||||
"app.submenu.application.animationsLabel": "Animacje",
|
||||
@ -372,6 +378,7 @@
|
||||
"app.settings.dataSavingTab.description": "Aby ograniczyć wykorzystanie połączenia internetowego włącz lub wyłącz poniższe opcje.",
|
||||
"app.settings.save-notification.label": "Ustawienia zostały zapisane",
|
||||
"app.statusNotifier.lowerHands": "Opuść ręce",
|
||||
"app.statusNotifier.lowerHandDescOneUser": "Opuść rękę dla {0}",
|
||||
"app.statusNotifier.raisedHandsTitle": "Podniesione ręce",
|
||||
"app.statusNotifier.raisedHandDesc": "{0} podnieśli ręce",
|
||||
"app.statusNotifier.raisedHandDescOneUser": "{0} podniósł rękę",
|
||||
@ -380,6 +387,8 @@
|
||||
"app.switch.offLabel": "WYŁ",
|
||||
"app.talkingIndicator.ariaMuteDesc" : "Wybierz aby wyciszyć uczestnika",
|
||||
"app.talkingIndicator.isTalking" : "{0} mówi",
|
||||
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ mówi",
|
||||
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ mówiło",
|
||||
"app.talkingIndicator.wasTalking" : "{0} przestał mówić",
|
||||
"app.actionsBar.actionsDropdown.actionsLabel": "Akcje",
|
||||
"app.actionsBar.actionsDropdown.presentationLabel": "Zarządzaj prezentacjami",
|
||||
@ -571,6 +580,7 @@
|
||||
"app.userList.guest.rememberChoice": "Zapamiętaj wybór",
|
||||
"app.userList.guest.emptyMessage": "Obecnie brak wiadomości",
|
||||
"app.userList.guest.inputPlaceholder": "Wiadomość do poczekalni gości",
|
||||
"app.userList.guest.privateInputPlaceholder": "Wiadomość do {0}",
|
||||
"app.userList.guest.privateMessageLabel": "Wiadomość",
|
||||
"app.userList.guest.acceptLabel": "Akceptuj",
|
||||
"app.userList.guest.denyLabel": "Odrzuć",
|
||||
@ -589,6 +599,7 @@
|
||||
"app.notification.recordingPaused": "Przerwa w rejestrowaniu sesji",
|
||||
"app.notification.recordingAriaLabel": "Czas nagrania",
|
||||
"app.notification.userJoinPushAlert": "{0} dołączył(a) do sesji",
|
||||
"app.notification.userLeavePushAlert": "{0} opuścił(a) sesję",
|
||||
"app.submenu.notification.raiseHandLabel": "Podnieś rękę",
|
||||
"app.shortcut-help.title": "Skróty klawiszowe",
|
||||
"app.shortcut-help.accessKeyNotAvailable": "Brak kluczy dostępowych",
|
||||
@ -694,6 +705,7 @@
|
||||
"app.video.pagination.prevPage": "Zobacz poprzednie video",
|
||||
"app.video.pagination.nextPage": "Zobacz kolejne video",
|
||||
"app.video.clientDisconnected": "Obraz kamery nie może zostać udostępniony z powodu problemów z połączeniem",
|
||||
"app.video.virtualBackground.camBgAriaDesc": "Ustaw wirtualne tło kamery na {0}",
|
||||
"app.fullscreenButton.label": "Przełącz {0} na pełny ekran",
|
||||
"app.fullscreenUndoButton.label": "Cofnij {0} pełny ekran",
|
||||
"app.sfu.mediaServerConnectionError2000": "Nie można połączyć się z serwerem multimediów (błąd 2000)",
|
||||
|
@ -173,6 +173,7 @@
|
||||
"app.presentation.options.fullscreen": "Tam ekrana geç",
|
||||
"app.presentation.options.exitFullscreen": "Tam ekrandan çık",
|
||||
"app.presentation.options.minimize": "Küçült",
|
||||
"app.presentation.options.snapshot": "Geçerli slaytın ekran görüntüsü",
|
||||
"app.presentation.options.downloading": "İndiriliyor...",
|
||||
"app.presentation.options.downloaded": "Geçerli sunum indirildi",
|
||||
"app.presentation.options.downloadFailed": "Geçerli sunum indirilemedi",
|
||||
|
@ -6,6 +6,7 @@
|
||||
"app.chat.disconnected": "Ви від'єднались, повідомлення не можуть бути надіслані",
|
||||
"app.chat.locked": "Чат заблоковано, неможливо надіслати повідомлення",
|
||||
"app.chat.inputLabel": "Текст повідомлення у чаті з {0}",
|
||||
"app.chat.inputPlaceholder": "Повідомлення {0}",
|
||||
"app.chat.titlePublic": "Загальний чат",
|
||||
"app.chat.titlePrivate": "Приватний чат з {0}",
|
||||
"app.chat.partnerDisconnected": "{0} вийшов з конференції",
|
||||
@ -19,6 +20,7 @@
|
||||
"app.chat.label": "Чат",
|
||||
"app.chat.offline": "Не в мережі",
|
||||
"app.chat.pollResult": "Результати опитування",
|
||||
"app.chat.breakoutDurationUpdated": "Час перерви зараз - {0} хвилин",
|
||||
"app.chat.emptyLogLabel": "Журнал чату порожній",
|
||||
"app.chat.clearPublicChatMessage": "Історію загального чату очищено модератором",
|
||||
"app.chat.multi.typing": "Учасники пишуть",
|
||||
@ -41,8 +43,23 @@
|
||||
"app.captions.menu.backgroundColor": "Колір фону",
|
||||
"app.captions.menu.previewLabel": "Попередній перегляд",
|
||||
"app.captions.menu.cancelLabel": "Скасувати",
|
||||
"app.captions.hide": "Сховати субтитри",
|
||||
"app.captions.ownership": "Перехоплення",
|
||||
"app.captions.ownershipTooltip": "Вас призначитимуть володарем {0} субтитрів",
|
||||
"app.captions.dictationStart": "Почати диктування",
|
||||
"app.captions.dictationStop": "Зупинити диктування",
|
||||
"app.captions.dictationOnDesc": "Вмикає ропізнавання голосу",
|
||||
"app.captions.dictationOffDesc": "Вимикає розпізнавання голосу",
|
||||
"app.captions.speech.start": "Розпочато розпізнавання голосу",
|
||||
"app.captions.speech.stop": "Зупинено розпізнавання голосу",
|
||||
"app.captions.speech.error": "Розпізнавання голосу зупинено через несумісний браузер чи тривалий час тиші",
|
||||
"app.textInput.sendLabel": "Відіслати",
|
||||
"app.title.defaultViewLabel": "Стандартний вигляд презентації",
|
||||
"app.notes.title": "Спільні нотатки",
|
||||
"app.notes.label": "Нотатки",
|
||||
"app.notes.hide": "Сховати нотатки",
|
||||
"app.notes.locked": "Заблоковано",
|
||||
"app.pads.hint": "Натисніть Esc для переходу у панель інструментів",
|
||||
"app.user.activityCheck": "Перевірка активності учасника",
|
||||
"app.user.activityCheck.label": "Перевірте, чи учасник зараз на зустрiчi ({0})",
|
||||
"app.user.activityCheck.check": "Перевірка",
|
||||
@ -101,6 +118,7 @@
|
||||
"app.userList.userOptions.disableMic": "Мікрофони учасників вимкнено",
|
||||
"app.userList.userOptions.disablePrivChat": "Приватний чат вимкнено",
|
||||
"app.userList.userOptions.disablePubChat": "Загальний чат вимкнено",
|
||||
"app.userList.userOptions.disableNotes": "Спільні нотатки заблоковано",
|
||||
"app.userList.userOptions.hideUserList": "Список учасників приховано від гостей",
|
||||
"app.userList.userOptions.webcamsOnlyForModerator": "Вебкамери учасників можуть бачити лише ведучі (через налаштування блокування)",
|
||||
"app.userList.content.participants.options.clearedStatus": "Статуси учасників знято",
|
||||
@ -108,11 +126,14 @@
|
||||
"app.userList.userOptions.enableMic": "Мікрофони учасників увімкнено",
|
||||
"app.userList.userOptions.enablePrivChat": "Приватний чат увімкнено",
|
||||
"app.userList.userOptions.enablePubChat": "Загальний чат увімкнено",
|
||||
"app.userList.userOptions.enableNotes": "Спільні нотатки увімкнені",
|
||||
"app.userList.userOptions.showUserList": "Список учасників тепер видимий гостям",
|
||||
"app.userList.userOptions.enableOnlyModeratorWebcam": "Тепер можна активувати вебкамеру, всі бачитимуть вас",
|
||||
"app.userList.userOptions.savedNames.title": "Список користувачів у зустрічі {0} на {1}",
|
||||
"app.userList.userOptions.sortedFirstName.heading": "Відсортовано за Ім'ям:",
|
||||
"app.userList.userOptions.sortedLastName.heading": "Відсортовано за Прізвищем:",
|
||||
"app.userList.userOptions.hideViewersCursor": "Курсори глядачів заблоковано",
|
||||
"app.userList.userOptions.showViewersCursor": "Курсори глядачів розблоковано",
|
||||
"app.media.label": "Мультимедії",
|
||||
"app.media.autoplayAlertDesc": "Дозволити доступ",
|
||||
"app.media.screenshare.start": "Демонстрація екрану розпочалася",
|
||||
@ -149,6 +170,13 @@
|
||||
"app.presentation.endSlideContent": "Кінець вмісту слайду",
|
||||
"app.presentation.changedSlideContent": "Слайд: {0}",
|
||||
"app.presentation.emptySlideContent": "Даний слайд порожній",
|
||||
"app.presentation.options.fullscreen": "Повний екран",
|
||||
"app.presentation.options.exitFullscreen": "Вихід з повного екрану",
|
||||
"app.presentation.options.minimize": "Мінімізувати",
|
||||
"app.presentation.options.snapshot": "Знімок поточного слайду",
|
||||
"app.presentation.options.downloading": "Завантаження...",
|
||||
"app.presentation.options.downloaded": "Завантажено поточну презентацію",
|
||||
"app.presentation.options.downloadFailed": "Не можливо завантажити поточну презентацію",
|
||||
"app.presentation.presentationToolbar.noNextSlideDesc": "Кінець презентації",
|
||||
"app.presentation.presentationToolbar.noPrevSlideDesc": "Початок презентації",
|
||||
"app.presentation.presentationToolbar.selectLabel": "Вибрати слайд",
|
||||
@ -173,6 +201,7 @@
|
||||
"app.presentation.presentationToolbar.fitToWidth": "Умістити за шириною",
|
||||
"app.presentation.presentationToolbar.fitToPage": "Умістити на сторінку",
|
||||
"app.presentation.presentationToolbar.goToSlide": "Слайд {0}",
|
||||
"app.presentation.placeholder": "Немає активної презентації",
|
||||
"app.presentationUploder.title": "Презентація",
|
||||
"app.presentationUploder.message": "Ведучий може завантажувати будь-який документ офісного формату, включно PDF. Ми рекомендуємо завантажувати презентації саме у форматі PDF. Після завантаження поставте прапорець навпроти імені файлу, який ви хочете показати учасникам.",
|
||||
"app.presentationUploder.extraHint": "Важливо: кожен файл має бути не більший за {0} MB та {1} сторінок",
|
||||
@ -188,6 +217,7 @@
|
||||
"app.presentationUploder.fileToUpload": "Буде завантажено ...",
|
||||
"app.presentationUploder.currentBadge": "Поточний",
|
||||
"app.presentationUploder.rejectedError": "Неможливо завантажити вибрані файл(и). Перевірте тип файлу(iв).",
|
||||
"app.presentationUploder.connectionClosedError": "Перервано через поганий зв'язок. Спробуйте пізніше",
|
||||
"app.presentationUploder.upload.progress": "Завантаження ({0}%)",
|
||||
"app.presentationUploder.upload.413": "Файл надто великий, розмір перевищує допустимі {0} МБ",
|
||||
"app.presentationUploder.genericError": "Ой лишенько! Щось пішло не так ...",
|
||||
@ -222,6 +252,7 @@
|
||||
"app.presentationUploder.clearErrorsDesc": "Очищує помилки завантажень презентацій",
|
||||
"app.presentationUploder.uploadViewTitle": "Завантажити презентацію",
|
||||
"app.poll.pollPaneTitle": "Опитування",
|
||||
"app.poll.enableMultipleResponseLabel": "Дозволити декілька відповідей від опитуваних?",
|
||||
"app.poll.quickPollTitle": "Швидке опитування",
|
||||
"app.poll.hidePollDesc": "Ховає панель меню опитувань",
|
||||
"app.poll.quickPollInstruction": "Виберіть типовий шаблон опитування.",
|
||||
@ -332,6 +363,7 @@
|
||||
"app.endMeeting.noLabel": "Ні",
|
||||
"app.about.title": "Про застосунок",
|
||||
"app.about.version": "Збірка клієнта:",
|
||||
"app.about.version_label": "BigBlueButton версія:",
|
||||
"app.about.copyright": "Авторське право:",
|
||||
"app.about.confirmLabel": "ОК",
|
||||
"app.about.confirmDesc": "ОК",
|
||||
@ -392,6 +424,7 @@
|
||||
"app.settings.dataSavingTab.description": "Для заощадження передачі даних, будь ласка, вимкніть функції, які пов'язані з демонстрацією відео:",
|
||||
"app.settings.save-notification.label": "Налаштування збережено",
|
||||
"app.statusNotifier.lowerHands": "Опустити руки",
|
||||
"app.statusNotifier.lowerHandDescOneUser": "Опустити {0} руку",
|
||||
"app.statusNotifier.raisedHandsTitle": "Підняті руки",
|
||||
"app.statusNotifier.raisedHandDesc": "{0} підняли руки",
|
||||
"app.statusNotifier.raisedHandDescOneUser": "{0} підняв руку",
|
||||
@ -473,6 +506,9 @@
|
||||
"app.breakoutJoinConfirmation.freeJoinMessage": "Виберіть кімнату для перерви , до якої бажаєте під’єднатися",
|
||||
"app.breakoutTimeRemainingMessage": "Час перерви у кімнаті : {0}",
|
||||
"app.breakoutWillCloseMessage": "Час вичерпано. Конференцію невдовзі буде закрито",
|
||||
"app.breakout.dropdown.manageDuration": "Змінити протяжність",
|
||||
"app.breakout.dropdown.destroyAll": "Закінчити кімнати перерв",
|
||||
"app.breakout.dropdown.options": "Опції перерви",
|
||||
"app.calculatingBreakoutTimeRemaining": "Підрахунок часу, що залишився...",
|
||||
"app.audioModal.ariaTitle": "Вікно підключення до голосової конференції",
|
||||
"app.audioModal.microphoneLabel": "Мікрофон",
|
||||
@ -528,6 +564,7 @@
|
||||
"app.audio.audioSettings.descriptionLabel": "У вашому браузері з'явиться вікно із запитом на доступ до мікрофона. Вам потрібно його підтвердити.",
|
||||
"app.audio.audioSettings.microphoneSourceLabel": "Джерело мікрофона",
|
||||
"app.audio.audioSettings.speakerSourceLabel": "Пристрій відтворення",
|
||||
"app.audio.audioSettings.testSpeakerLabel": "Перевірте динаміки",
|
||||
"app.audio.audioSettings.microphoneStreamLabel": "Гучність вашого звукового потоку",
|
||||
"app.audio.audioSettings.retryLabel": "Повторити",
|
||||
"app.audio.listenOnly.backLabel": "Назад",
|
||||
@ -566,6 +603,7 @@
|
||||
"app.error.500": "Ой, щось пішло не так",
|
||||
"app.error.userLoggedOut": "Користувач має невірний sessionToken через те що вилогінився",
|
||||
"app.error.ejectedUser": "Користувач має невірний sessionToken через викид",
|
||||
"app.error.joinedAnotherWindow": "Схоже що ця сесія відкрита у іншому вікні браузера",
|
||||
"app.error.userBanned": "Користувача забанено",
|
||||
"app.error.leaveLabel": "Увійдіть знову",
|
||||
"app.error.fallback.presentation.title": "Виникла помилка",
|
||||
@ -584,6 +622,10 @@
|
||||
"app.guest.guestDeny": "Гостю відмовлено у приєднанні до зустрічі.",
|
||||
"app.guest.seatWait": "Гість очікує на вільне місце у зустрічі.",
|
||||
"app.guest.allow": "Гостя підтверджено та скеровано до зустрічі",
|
||||
"app.guest.firstPositionInWaitingQueue": "Ви перші у черзі",
|
||||
"app.guest.positionInWaitingQueue": "Ваша черга",
|
||||
"app.guest.guestInvalid": "Невірний запрошений гість",
|
||||
"app.guest.meetingForciblyEnded": "Зустріч зупинено",
|
||||
"app.userList.guest.waitingUsers": "Учасники у очікуванні",
|
||||
"app.userList.guest.waitingUsersTitle": "Керування учасниками",
|
||||
"app.userList.guest.optionTitle": "Переглянути учасників, які очікують",
|
||||
@ -592,11 +634,14 @@
|
||||
"app.userList.guest.allowEveryone": "Дозволити всім",
|
||||
"app.userList.guest.denyEveryone": "Заборонити всім",
|
||||
"app.userList.guest.pendingUsers": "{0} учасників у очікуванні",
|
||||
"app.userList.guest.noPendingUsers": "Немає користувачів у очікуванні...",
|
||||
"app.userList.guest.pendingGuestUsers": "{0} гостей в очікуванні",
|
||||
"app.userList.guest.pendingGuestAlert": "Приєднався до сеансу та очікує вашого схвалення",
|
||||
"app.userList.guest.rememberChoice": "Запам'ятати вибір",
|
||||
"app.userList.guest.emptyMessage": "Немає повідомлень",
|
||||
"app.userList.guest.inputPlaceholder": "Повідомлення для гостьової кімнати очікування",
|
||||
"app.userList.guest.privateInputPlaceholder": "Повідомлення до {0}",
|
||||
"app.userList.guest.privateMessageLabel": "Повідомлення",
|
||||
"app.userList.guest.acceptLabel": "Прийняти",
|
||||
"app.userList.guest.denyLabel": "Відмовити",
|
||||
"app.user-info.title": "Пошук у каталозі",
|
||||
@ -609,6 +654,9 @@
|
||||
"app.toast.meetingMuteOn.label": "Всім учасникам вимкнено мікрофони",
|
||||
"app.toast.meetingMuteOff.label": "Блокування мікрофону вимкнено",
|
||||
"app.toast.setEmoji.raiseHand": "Ви підняли руку",
|
||||
"app.toast.setEmoji.lowerHand": "Руку опущено",
|
||||
"app.toast.promotedLabel": "Вас підвищено до статусу Модератор",
|
||||
"app.toast.demotedLabel": "Вас понижено до статусу Переглядач",
|
||||
"app.notification.recordingStart": "Цей сеанс записується",
|
||||
"app.notification.recordingStop": "Цей сеанс не записується",
|
||||
"app.notification.recordingPaused": "Цей сеанс більше не записується",
|
||||
@ -636,6 +684,10 @@
|
||||
"app.shortcut-help.toggleFullscreen": "Переключити - На весь екран (ведучий)",
|
||||
"app.shortcut-help.nextSlideDesc": "Наступний слайд (ведучий)",
|
||||
"app.shortcut-help.previousSlideDesc": "Попередній слайд (ведучий)",
|
||||
"app.shortcut-help.togglePanKey": "Пробіл",
|
||||
"app.shortcut-help.toggleFullscreenKey": "Enter",
|
||||
"app.shortcut-help.nextSlideKey": "Права стрілка",
|
||||
"app.shortcut-help.previousSlideKey": "Ліва стрілка",
|
||||
"app.lock-viewers.title": "Обмежити глядачів",
|
||||
"app.lock-viewers.description": "Ці налаштування дозволяють обмежити учасників у доступі до певних функцій",
|
||||
"app.lock-viewers.featuresLable": "Властивість",
|
||||
@ -651,6 +703,7 @@
|
||||
"app.lock-viewers.button.apply": "Застосувати",
|
||||
"app.lock-viewers.button.cancel": "Скасувати",
|
||||
"app.lock-viewers.locked": "Заблокований",
|
||||
"app.lock-viewers.hideViewersCursor": "Показати курсори інших користувачів",
|
||||
"app.guest-policy.ariaTitle": "Вікно налаштування політики для гостей",
|
||||
"app.guest-policy.title": "Гостьова політика",
|
||||
"app.guest-policy.description": "Змінити налаштування гостьової політики зустрічі",
|
||||
@ -663,15 +716,26 @@
|
||||
"app.connection-status.description": "Перегляд стану з'єднання користувачів",
|
||||
"app.connection-status.empty": "Немає проблем із зв'язком",
|
||||
"app.connection-status.more": "докладно",
|
||||
"app.connection-status.copy": "Копіювати статистику",
|
||||
"app.connection-status.copied": "Скопійовано!",
|
||||
"app.connection-status.jitter": "Тремтіння",
|
||||
"app.connection-status.label": "Стан з'єднання",
|
||||
"app.connection-status.settings": "Налаштування ваших параметрів",
|
||||
"app.connection-status.no": "Ні",
|
||||
"app.connection-status.notification": "Ваше під'єднання має втрати",
|
||||
"app.connection-status.offline": "не в мережі",
|
||||
"app.connection-status.audioUploadRate": "Якість відправки аудіо",
|
||||
"app.connection-status.audioDownloadRate": "Якість завантаження аудіо",
|
||||
"app.connection-status.videoUploadRate": "Якість відправки відео",
|
||||
"app.connection-status.videoDownloadRate": "Якість завантаження відео",
|
||||
"app.connection-status.lostPackets": "Втрачені пакети",
|
||||
"app.connection-status.usingTurn": "Використання TURN",
|
||||
"app.connection-status.yes": "Так",
|
||||
"app.connection-status.connectionStats": "Статистика конектів",
|
||||
"app.connection-status.myLogs": "Мої логи",
|
||||
"app.connection-status.sessionLogs": "Логи сесії",
|
||||
"app.connection-status.next": "Наступна сторінка",
|
||||
"app.connection-status.prev": "Попередня сторінка",
|
||||
"app.learning-dashboard.label": "Дошка аналітики навчання",
|
||||
"app.learning-dashboard.description": "Відкрити панель обліку активності учасників",
|
||||
"app.learning-dashboard.clickHereToOpen": "Відкрити дошку аналітики навчання",
|
||||
@ -738,10 +802,12 @@
|
||||
"app.video.virtualBackground.blur": "Розмивання",
|
||||
"app.video.virtualBackground.home": "Будинок",
|
||||
"app.video.virtualBackground.board": "Дошка",
|
||||
"app.video.virtualBackground.coffeeshop": "Кав`ярня",
|
||||
"app.video.virtualBackground.coffeeshop": "Кав'ярня",
|
||||
"app.video.virtualBackground.background": "Задній фон",
|
||||
"app.video.virtualBackground.genericError": "Не вдалось застосувати ефект для камери. Спробуйте знову.",
|
||||
"app.video.virtualBackground.camBgAriaDesc": "Встановлює віртуальне тло для вебкамери: {0}",
|
||||
"app.video.camCapReached": "Ви не можете поширити більше камер",
|
||||
"app.video.meetingCamCapReached": "Досягнуто ліміт камер у зустрічі",
|
||||
"app.video.dropZoneLabel": "Перетягніть сюди",
|
||||
"app.fullscreenButton.label": "Вивести {0} на весь екран",
|
||||
"app.fullscreenUndoButton.label": "Вимкнути {0} режим на весь екран",
|
||||
@ -831,7 +897,11 @@
|
||||
"app.createBreakoutRoom.durationInMinutes": "Тривалість (хвилини)",
|
||||
"app.createBreakoutRoom.randomlyAssign": "Випадково призначити",
|
||||
"app.createBreakoutRoom.randomlyAssignDesc": "Випадково розподілити користувачів по кімнатах",
|
||||
"app.createBreakoutRoom.resetAssignments": "Суинути призначення",
|
||||
"app.createBreakoutRoom.resetAssignmentsDesc": "Скинути усі призначення кімнати",
|
||||
"app.createBreakoutRoom.endAllBreakouts": "Закрити усі перервні кімнати ",
|
||||
"app.createBreakoutRoom.chatTitleMsgAllRooms": "усі кімнати",
|
||||
"app.createBreakoutRoom.msgToBreakoutsSent": "Повідомлення надіслано до {0} кімнат перерв",
|
||||
"app.createBreakoutRoom.roomName": "{0} (Кімната - {1})",
|
||||
"app.createBreakoutRoom.doneLabel": "Готово",
|
||||
"app.createBreakoutRoom.nextLabel": "Далі",
|
||||
@ -846,6 +916,10 @@
|
||||
"app.createBreakoutRoom.numberOfRoomsError": "Кількість кімнат є неправильною.",
|
||||
"app.createBreakoutRoom.duplicatedRoomNameError": "Назва кімнати не може повторюватись",
|
||||
"app.createBreakoutRoom.emptyRoomNameError": "Назва кімнати не може бути порожньою",
|
||||
"app.createBreakoutRoom.setTimeInMinutes": "Протяжність перерви (minutes)",
|
||||
"app.createBreakoutRoom.setTimeLabel": "Застосувати",
|
||||
"app.createBreakoutRoom.setTimeCancel": "Відмінити",
|
||||
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "Чвс перерви не може перевищувати час зустрічі",
|
||||
"app.createBreakoutRoom.roomNameInputDesc": "Оновлює назву кімнати для учасників",
|
||||
"app.externalVideo.start": "Поділитися новим відео",
|
||||
"app.externalVideo.title": "Поділитися зовнішнім відео",
|
||||
@ -857,6 +931,8 @@
|
||||
"app.externalVideo.refreshLabel": "Оновити програвач відео",
|
||||
"app.externalVideo.fullscreenLabel": "Переглядач відео",
|
||||
"app.externalVideo.noteLabel": "Примітка: Зовнішні відеозаписи не з'являються у записі сеансу. Підтримуються: YouTube, Vimeo, Instructure Media, Twitch, Dailymotion та посилання на відео ( наприклад : https://example.com/xy.mp4 )",
|
||||
"app.externalVideo.subtitlesOn": "Вимкнути",
|
||||
"app.externalVideo.subtitlesOff": "Вмикнути (якщо доступно)",
|
||||
"app.actionsBar.actionsDropdown.shareExternalVideo": "Демонстрація зовнішнього відео",
|
||||
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Припинити показ зовнішнього відео",
|
||||
"app.iOSWarning.label": "Будь ласка, оновіть пристрій з iOS до версії 12.2 або новішої версії",
|
||||
@ -885,9 +961,21 @@
|
||||
"playback.button.search.aria": "Пошук",
|
||||
"playback.button.section.aria": "Бічна частина",
|
||||
"playback.button.swap.aria": "Перемкнути вміст",
|
||||
"playback.button.theme.aria": "Перемкнути тему",
|
||||
"playback.error.wrapper.aria": "Область помилок",
|
||||
"playback.loader.wrapper.aria": "Область завантажувача",
|
||||
"playback.player.wrapper.aria": "Область програвача",
|
||||
"playback.player.about.modal.shortcuts.title": "Гарячі клавіші",
|
||||
"playback.player.about.modal.shortcuts.alt": "Alt",
|
||||
"playback.player.about.modal.shortcuts.shift": "Shift",
|
||||
"playback.player.about.modal.shortcuts.fullscreen": "Перемикання на весь екран",
|
||||
"playback.player.about.modal.shortcuts.play": "Відтворення/Пауза",
|
||||
"playback.player.about.modal.shortcuts.section": "Перемкнути бокову панель",
|
||||
"playback.player.about.modal.shortcuts.seek.backward": "Шукати назад",
|
||||
"playback.player.about.modal.shortcuts.seek.forward": "Шукати далі",
|
||||
"playback.player.about.modal.shortcuts.skip.next": "Наступний слайд",
|
||||
"playback.player.about.modal.shortcuts.skip.previous": "Попередній слайд",
|
||||
"playback.player.about.modal.shortcuts.swap": "Обміняти контент",
|
||||
"playback.player.chat.message.poll.name": "Результати опитування",
|
||||
"playback.player.chat.message.poll.question": "Питання",
|
||||
"playback.player.chat.message.poll.options": "Варіанти",
|
||||
@ -906,14 +994,30 @@
|
||||
"playback.player.thumbnails.wrapper.aria": "Область мініатюр",
|
||||
"playback.player.webcams.wrapper.aria": "Вебкамери",
|
||||
"app.learningDashboard.dashboardTitle": "Дошка аналітики навчання",
|
||||
"app.learningDashboard.downloadSessionDataLabel": "Завантажити дані сесії",
|
||||
"app.learningDashboard.lastUpdatedLabel": "Оновлено ",
|
||||
"app.learningDashboard.sessionDataDownloadedLabel": "Завантажено!",
|
||||
"app.learningDashboard.shareButton": "Поширити з іншими",
|
||||
"app.learningDashboard.shareLinkCopied": "Ліну скопійовано!",
|
||||
"app.learningDashboard.user": "Користувач",
|
||||
"app.learningDashboard.indicators.meetingStatusEnded": "Закінчилась",
|
||||
"app.learningDashboard.indicators.meetingStatusActive": "Активна",
|
||||
"app.learningDashboard.indicators.usersOnline": "Користувачі онлайн",
|
||||
"app.learningDashboard.indicators.usersTotal": "Загальна кількість користувачів",
|
||||
"app.learningDashboard.indicators.polls": "Опитування",
|
||||
"app.learningDashboard.indicators.timeline": "Таймлайн",
|
||||
"app.learningDashboard.indicators.activityScore": "Рахунок активності",
|
||||
"app.learningDashboard.indicators.duration": "Тривалість",
|
||||
"app.learningDashboard.userDetails.startTime": "Початковий час",
|
||||
"app.learningDashboard.userDetails.endTime": "Кінцевий час",
|
||||
"app.learningDashboard.userDetails.joined": "Приєднався",
|
||||
"app.learningDashboard.userDetails.category": "Категорія",
|
||||
"app.learningDashboard.userDetails.average": "Усередньому",
|
||||
"app.learningDashboard.userDetails.activityPoints": "Оцінка активності",
|
||||
"app.learningDashboard.userDetails.poll": "Опитування",
|
||||
"app.learningDashboard.userDetails.response": "Відповідь",
|
||||
"app.learningDashboard.userDetails.mostCommonAnswer": "Найчастіша відповідь",
|
||||
"app.learningDashboard.userDetails.anonymousAnswer": "Анонімне опитування",
|
||||
"app.learningDashboard.usersTable.title": "Огляд",
|
||||
"app.learningDashboard.usersTable.colOnline": "Час онлайн",
|
||||
"app.learningDashboard.usersTable.colTalk": "Час виступів",
|
||||
@ -926,10 +1030,32 @@
|
||||
"app.learningDashboard.usersTable.userStatusOnline": "Онлайн",
|
||||
"app.learningDashboard.usersTable.userStatusOffline": "Відсутній",
|
||||
"app.learningDashboard.usersTable.noUsers": "Поки ще нікого немає",
|
||||
"app.learningDashboard.usersTable.name": "Ім'я",
|
||||
"app.learningDashboard.usersTable.moderator": "Модератор",
|
||||
"app.learningDashboard.usersTable.pollVotes": "Результати опитування",
|
||||
"app.learningDashboard.usersTable.join": "Приєднатися",
|
||||
"app.learningDashboard.usersTable.left": "Зліва",
|
||||
"app.learningDashboard.usersTable.notAvailable": "Н/Д",
|
||||
"app.learningDashboard.pollsTable.title": "Опитування",
|
||||
"app.learningDashboard.pollsTable.anonymousAnswer": "Анонімні опитування (відповіді в останньому рядку)",
|
||||
"app.learningDashboard.pollsTable.anonymousRowName": "Анонім",
|
||||
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "Ще не створено жлдного опитування",
|
||||
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "Як опитування буде завершено, результати відобразяться у цьому списку",
|
||||
"app.learningDashboard.statusTimelineTable.title": "Таймлайн",
|
||||
"app.learningDashboard.statusTimelineTable.thumbnail": "Іконка презентації",
|
||||
"app.learningDashboard.errors.invalidToken": "Недійсна лексема сеансу",
|
||||
"app.learningDashboard.errors.dataUnavailable": "Дані більше недоступні"
|
||||
"app.learningDashboard.errors.dataUnavailable": "Дані більше недоступні",
|
||||
"mobileApp.portals.list.empty.addFirstPortal.label": "Додайте свій перший портал кнопками вище",
|
||||
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "чи скористайтеся демонстраційним порталом",
|
||||
"mobileApp.portals.list.add.button.label": "Додати портал",
|
||||
"mobileApp.portals.fields.name.label": "Ім'я порталу",
|
||||
"mobileApp.portals.fields.name.placeholder": "Демонстрація BigBlueButton ",
|
||||
"mobileApp.portals.fields.url.label": "Адреса сервера",
|
||||
"mobileApp.portals.addPortalPopup.confirm.button.label": "Зберегти",
|
||||
"mobileApp.portals.drawerNavigation.button.label": "Портали",
|
||||
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Необхідні поля",
|
||||
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Ім'я вже використовується",
|
||||
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Помилка завантаження сторінки - перевірте посилання та з'єднання з мережею"
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ DEBNAME_TO_SOURCEDIR[bbb-apps-akka]="akka-bbb-apps bbb-common-message"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-config]="bigbluebutton-config"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-demo]="bbb-api-demo"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-etherpad]="bbb-etherpad"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-export-annotations]="bbb-export-annotations"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-freeswitch-core]="freeswitch bbb-voice-conference"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-freeswitch-sounds]="do_not_copy_anything"
|
||||
DEBNAME_TO_SOURCEDIR[bbb-fsesl-akka]="akka-bbb-fsesl bbb-common-message bbb-fsesl-client"
|
||||
|
5
build/packages-template/bbb-config/bigbluebutton.conf
Normal file
5
build/packages-template/bbb-config/bigbluebutton.conf
Normal file
@ -0,0 +1,5 @@
|
||||
[Unit]
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Install]
|
||||
WantedBy=bigbluebutton.target
|
7
build/packages-template/bbb-config/bigbluebutton.target
Normal file
7
build/packages-template/bbb-config/bigbluebutton.target
Normal file
@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton System
|
||||
Requires=
|
||||
After=syslog.target network.target
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -2,6 +2,12 @@
|
||||
|
||||
TARGET=`basename $(pwd)`
|
||||
|
||||
# inject dependency to bigbluebutton.target
|
||||
for unit in freeswitch nginx redis-server; do
|
||||
mkdir -p "staging/lib/systemd/system/${unit}.service.d"
|
||||
cp bigbluebutton.conf "staging/lib/systemd/system/${unit}.service.d/"
|
||||
done
|
||||
|
||||
|
||||
PACKAGE=$(echo $TARGET | cut -d'_' -f1)
|
||||
VERSION=$(echo $TARGET | cut -d'_' -f2)
|
||||
@ -14,6 +20,7 @@ rm -rf staging
|
||||
#
|
||||
# Create build directories for markign by fpm
|
||||
DIRS="/etc/bigbluebutton \
|
||||
/lib/systemd/system \
|
||||
/var/bigbluebutton/blank \
|
||||
/usr/share/bigbluebutton/blank \
|
||||
/var/www/bigbluebutton-default"
|
||||
@ -44,30 +51,7 @@ cp cron.daily/* staging/etc/cron.daily
|
||||
mkdir -p staging/etc/cron.hourly
|
||||
cp cron.hourly/bbb-resync-freeswitch staging/etc/cron.hourly
|
||||
|
||||
# Overrides
|
||||
|
||||
mkdir -p staging/etc/systemd/system/bbb-apps-akka.service.d
|
||||
cat > staging/etc/systemd/system/bbb-apps-akka.service.d/override.conf <<HERE
|
||||
[Unit]
|
||||
Wants=redis-server.service
|
||||
After=redis-server.service
|
||||
HERE
|
||||
|
||||
mkdir -p staging/etc/systemd/system/bbb-fsesl-akka.service.d
|
||||
cat > staging/etc/systemd/system/bbb-fsesl-akka.service.d/override.conf <<HERE
|
||||
[Unit]
|
||||
Wants=redis-server.service
|
||||
After=redis-server.service
|
||||
HERE
|
||||
|
||||
|
||||
mkdir -p staging/etc/systemd/system/bbb-transcode-akka.service.d
|
||||
cat > staging/etc/systemd/system/bbb-transcode-akka.service.d/override.conf <<HERE
|
||||
[Unit]
|
||||
Wants=redis-server.service
|
||||
After=redis-server.service
|
||||
HERE
|
||||
|
||||
cp bigbluebutton.target staging/lib/systemd/system/
|
||||
|
||||
. ./opts-$DISTRO.sh
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=Etherpad Server
|
||||
Wants=redis-server.service
|
||||
After=syslog.target network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -14,5 +15,5 @@ Restart=always
|
||||
# use mysql plus a complete settings.json to avoid Service hold-off time over, scheduling restart.
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
after-install.sh
|
||||
bbb-export-annotations.service
|
||||
before-remove.sh
|
||||
build.sh
|
||||
opts-focal.sh
|
||||
opts-global.sh
|
14
build/packages-template/bbb-export-annotations/after-install.sh
Executable file
14
build/packages-template/bbb-export-annotations/after-install.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
case "$1" in
|
||||
configure|upgrade|1|2)
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton Export Annotations
|
||||
Wants=redis.service
|
||||
After=syslog.target network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/usr/local/bigbluebutton/bbb-export-annotations
|
||||
ExecStart=/usr/bin/node master.js
|
||||
Restart=always
|
||||
SyslogIdentifier=bbb-export-annotations
|
||||
User=bigbluebutton
|
||||
Group=bigbluebutton
|
||||
Environment=NODE_ENV=production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
3
build/packages-template/bbb-export-annotations/before-remove.sh
Executable file
3
build/packages-template/bbb-export-annotations/before-remove.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
stopService bbb-export-annotations || echo "bbb-export-annotations could not be unregistered or stopped"
|
42
build/packages-template/bbb-export-annotations/build.sh
Executable file
42
build/packages-template/bbb-export-annotations/build.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
TARGET=`basename $(pwd)`
|
||||
|
||||
PACKAGE=$(echo $TARGET | cut -d'_' -f1)
|
||||
VERSION=$(echo $TARGET | cut -d'_' -f2)
|
||||
DISTRO=$(echo $TARGET | cut -d'_' -f3)
|
||||
TAG=$(echo $TARGET | cut -d'_' -f4)
|
||||
|
||||
#
|
||||
# Clean up directories
|
||||
rm -rf staging
|
||||
|
||||
#
|
||||
# package
|
||||
|
||||
mkdir -p staging/usr/local/bigbluebutton/bbb-export-annotations
|
||||
|
||||
find -maxdepth 1 ! -path . ! -name staging $(printf "! -name %s " $(cat .build-files)) -exec cp -r {} staging/usr/local/bigbluebutton/bbb-export-annotations/ \;
|
||||
|
||||
pushd .
|
||||
cd staging/usr/local/bigbluebutton/bbb-export-annotations/
|
||||
npm install --production
|
||||
popd
|
||||
|
||||
mkdir -p staging/usr/lib/systemd/system
|
||||
cp bbb-export-annotations.service staging/usr/lib/systemd/system
|
||||
|
||||
##
|
||||
|
||||
. ./opts-$DISTRO.sh
|
||||
|
||||
#
|
||||
# Build package
|
||||
fpm -s dir -C ./staging -n $PACKAGE \
|
||||
--version $VERSION --epoch $EPOCH \
|
||||
--after-install after-install.sh \
|
||||
--before-remove before-remove.sh \
|
||||
--description "BigBlueButton Export Annotations" \
|
||||
$DIRECTORIES \
|
||||
$OPTS
|
||||
|
@ -0,0 +1,3 @@
|
||||
. ./opts-global.sh
|
||||
|
||||
OPTS="$OPTS -t deb -d nodejs,npm,bbb-apps-akka,bbb-web"
|
@ -3,6 +3,7 @@
|
||||
[Unit]
|
||||
Description=freeswitch
|
||||
After=syslog.target network.target local-fs.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
; service
|
||||
@ -54,5 +55,5 @@ CPUSchedulingPriority=89
|
||||
; execute "systemctl daemon-reload" after editing the unit files.
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -59,7 +59,7 @@ source /etc/lsb-release
|
||||
|
||||
# Set up specific version of node
|
||||
if [ "$DISTRIB_CODENAME" == "focal" ]; then
|
||||
node_version="14.19.1"
|
||||
node_version="14.19.3"
|
||||
if [[ ! -d /usr/share/node-v${node_version}-linux-x64 ]]; then
|
||||
cd /usr/share
|
||||
tar xfz "node-v${node_version}-linux-x64.tar.gz"
|
||||
@ -76,9 +76,9 @@ if [ -f /opt/freeswitch/etc/freeswitch/sip_profiles/external.xml ]; then
|
||||
sed -i 's/<!--<param name="enable-3pcc" value="true"\/>-->/<param name="enable-3pcc" value="proxy"\/>/g' /opt/freeswitch/etc/freeswitch/sip_profiles/external.xml
|
||||
fi
|
||||
|
||||
chown root:root /usr/lib/systemd/system
|
||||
chown root:root /usr/lib/systemd/system/bbb-html5.service
|
||||
chown root:root /usr/lib/systemd/system/disable-transparent-huge-pages.service
|
||||
chown root:root /lib/systemd/system
|
||||
chown root:root /lib/systemd/system/bbb-html5.service
|
||||
chown root:root /lib/systemd/system/disable-transparent-huge-pages.service
|
||||
|
||||
# Ensure settings is readable
|
||||
chmod go+r /usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=BigBlueButton HTML5 service
|
||||
Wants=redis.service mongod.service disable-transparent-huge-pages.service bbb-pads.service
|
||||
After=redis.service mongod.service disable-transparent-huge-pages.service bbb-pads.service syslog.target network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
@ -16,5 +17,5 @@ RemainAfterExit=yes
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -92,11 +92,11 @@ cp bbb-html5-frontend@.service staging/usr/lib/systemd/system
|
||||
|
||||
mkdir -p staging/usr/share
|
||||
|
||||
if [ ! -f node-v14.19.1-linux-x64.tar.gz ]; then
|
||||
wget https://nodejs.org/dist/v14.19.1/node-v14.19.1-linux-x64.tar.gz
|
||||
if [ ! -f node-v14.19.3-linux-x64.tar.gz ]; then
|
||||
wget https://nodejs.org/dist/v14.19.3/node-v14.19.3-linux-x64.tar.gz
|
||||
fi
|
||||
|
||||
cp node-v14.19.1-linux-x64.tar.gz staging/usr/share
|
||||
cp node-v14.19.3-linux-x64.tar.gz staging/usr/share
|
||||
|
||||
if [ -f staging/usr/share/meteor/bundle/programs/web.browser/head.html ]; then
|
||||
sed -i "s/VERSION/$(($BUILD))/" staging/usr/share/meteor/bundle/programs/web.browser/head.html
|
||||
|
@ -1,5 +1,6 @@
|
||||
[Unit]
|
||||
Description=Disable Transparent Huge Pages
|
||||
PartOf=bigbluebutton.target
|
||||
ConditionPathIsDirectory=/sys/kernel/mm/transparent_hugepage
|
||||
|
||||
[Service]
|
||||
@ -9,4 +10,4 @@ ExecStart=/bin/sh -c "/bin/echo "never" | tee /sys/kernel/mm/transparent_hugepag
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -5,6 +5,7 @@
|
||||
Description=High-performance, schema-free document-oriented database
|
||||
After=network.target
|
||||
Documentation=https://docs.mongodb.org/manual
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
User=mongodb
|
||||
@ -34,5 +35,5 @@ TasksAccounting=false
|
||||
# http://docs.mongodb.org/manual/reference/ulimit/#recommended-settings
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
. ./opts-global.sh
|
||||
|
||||
OPTS="$OPTS -d bc,bbb-pads,bbb-webrtc-sfu,bbb-web,mongodb-org -t deb"
|
||||
OPTS="$OPTS -d bc,bbb-pads,bbb-webrtc-sfu,bbb-export-annotations,bbb-web,mongodb-org -t deb"
|
||||
|
@ -49,7 +49,7 @@ fi
|
||||
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
|
||||
export MONGO_URL=mongodb://127.0.1.1/meteor
|
||||
export NODE_ENV=production
|
||||
export NODE_VERSION=node-v14.19.1-linux-x64
|
||||
export NODE_VERSION=node-v14.19.3-linux-x64
|
||||
export SERVER_WEBSOCKET_COMPRESSION=0
|
||||
export BIND_IP=127.0.0.1
|
||||
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=$INSTANCE_ID
|
||||
|
@ -49,7 +49,7 @@ fi
|
||||
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
|
||||
export MONGO_URL=mongodb://127.0.1.1/meteor
|
||||
export NODE_ENV=production
|
||||
export NODE_VERSION=node-v14.19.1-linux-x64
|
||||
export NODE_VERSION=node-v14.19.3-linux-x64
|
||||
export SERVER_WEBSOCKET_COMPRESSION=0
|
||||
export BIND_IP=127.0.0.1
|
||||
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js
|
||||
|
@ -1,6 +1,7 @@
|
||||
[Unit]
|
||||
Description=LibreOffice
|
||||
After=network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -12,5 +13,4 @@ MemoryLimit=1G
|
||||
CPUQuota=20%
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -1,6 +1,7 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton LTI Application
|
||||
Requires=network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -19,5 +20,5 @@ PermissionsStartOnly=true
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=BigBlueButton Pads
|
||||
Wants=redis.service etherpad.service
|
||||
After=syslog.target network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/usr/local/bigbluebutton/bbb-pads
|
||||
@ -13,4 +14,4 @@ Group=bigbluebutton
|
||||
Environment=NODE_ENV=production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=BigBlueButton Web Application
|
||||
Requires=network.target
|
||||
After=redis.service
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -20,5 +21,5 @@ PermissionsStartOnly=true
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=BigBlueButton Webhooks
|
||||
Wants=redis-server.service
|
||||
After=syslog.target network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/usr/local/bigbluebutton/bbb-webhooks
|
||||
@ -13,4 +14,4 @@ Group=bigbluebutton
|
||||
Environment=NODE_ENV=production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=BigBlueButton WebRTC SFU
|
||||
Wants=redis-server.service
|
||||
After=syslog.target network.target freeswitch.service kurento-media-server.service
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/usr/local/bigbluebutton/bbb-webrtc-sfu
|
||||
@ -14,4 +15,4 @@ Environment=NODE_ENV=production
|
||||
Environment=NODE_CONFIG_DIR=/etc/bigbluebutton/bbb-webrtc-sfu/:/usr/local/bigbluebutton/bbb-webrtc-sfu/config/
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -1,6 +1,7 @@
|
||||
[Unit]
|
||||
Description=Kurento Media Server daemon
|
||||
After=network.target
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
UMask=0002
|
||||
@ -15,5 +16,5 @@ PIDFile=/var/run/kurento-media-server.pid
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
||||
|
@ -16,6 +16,7 @@ fi
|
||||
PKGS="bbb-apps-akka
|
||||
bbb-config
|
||||
bbb-etherpad
|
||||
bbb-export-annotations
|
||||
bbb-freeswitch-core
|
||||
bbb-freeswitch-sounds
|
||||
bbb-fsesl-akka
|
||||
|
@ -26,16 +26,9 @@ for dir in .gradle .grails .ivy2 .m2; do
|
||||
ln -s "${SOURCE}/cache/${dir}" "/root/${dir}"
|
||||
done
|
||||
|
||||
if [ "$LOCAL_BUILD" != 1 ] ; then
|
||||
GIT_REV="${CI_COMMIT_SHA:0:10}"
|
||||
else
|
||||
GIT_REV=$(git rev-parse HEAD)
|
||||
GIT_REV="local-build-${GIT_REV:0:10}"
|
||||
fi
|
||||
VERSION_NUMBER="$(cat "$SOURCE/bigbluebutton-config/bigbluebutton-release" | cut -d '=' -f2 | cut -d "-" -f1)"
|
||||
# this contains stuff like alpha4 etc
|
||||
VERSION_ADDON="$(cat "$SOURCE/bigbluebutton-config/bigbluebutton-release" | cut -d '=' -f2 | cut -d "-" -f2)"
|
||||
COMMIT_DATE="$(git log -n1 --pretty='format:%cd' --date=format:'%Y%m%dT%H%M%S')"
|
||||
BUILD_NUMBER=${BUILD_NUMBER:=1}
|
||||
EPOCH=${EPOCH:=2}
|
||||
|
||||
|
@ -15,9 +15,17 @@ mkdir -p artifacts
|
||||
|
||||
DOCKER_IMAGE=$(python3 -c 'import yaml; print(yaml.load(open("./.gitlab-ci.yml"), Loader=yaml.SafeLoader)["default"]["image"])')
|
||||
|
||||
if [ "$LOCAL_BUILD" != 1 ] ; then
|
||||
GIT_REV="${CI_COMMIT_SHA:0:10}"
|
||||
else
|
||||
GIT_REV=$(git rev-parse HEAD)
|
||||
GIT_REV="local-build-${GIT_REV:0:10}"
|
||||
fi
|
||||
COMMIT_DATE="$(git log -n1 --pretty='format:%cd' --date=format:'%Y%m%dT%H%M%S')"
|
||||
|
||||
# -v "$CACHE_DIR/dev":/root/dev
|
||||
sudo docker run --rm \
|
||||
-e "LOCAL_BUILD=1" \
|
||||
--env GIT_REV=$GIT_REV --env COMMIT_DATE=$COMMIT_DATE --env "LOCAL_BUILD=1" \
|
||||
--mount type=bind,src="$PWD",dst=/mnt \
|
||||
--mount type=bind,src="${PWD}/artifacts,dst=/artifacts" \
|
||||
-t "$DOCKER_IMAGE" /mnt/build/setup-inside-docker.sh "$PACKAGE_TO_BUILD"
|
||||
@ -28,4 +36,4 @@ sudo docker run --rm \
|
||||
# -v "$CACHE_DIR/$DISTRO/.m2:/root/.m2" \
|
||||
# -v "$TMP/$TARGET:$TMP/$TARGET" \
|
||||
|
||||
find artifacts
|
||||
find artifacts
|
||||
|
@ -960,7 +960,7 @@ module BigBlueButton
|
||||
# The following events are considered to indicate that the presentation
|
||||
# area was actively used during the session.
|
||||
when 'AddShapeEvent', 'ModifyTextEvent', 'UndoShapeEvent',
|
||||
'ClearPageEvent'
|
||||
'ClearPageEvent', 'AddTldrawShapeEvent', 'DeleteTldrawShapeEvent'
|
||||
BigBlueButton.logger.debug("Seen a #{event['eventname']} event, presentation area used.")
|
||||
return true
|
||||
# We ignore the first SharePresentationEvent, since it's the default
|
||||
@ -1093,5 +1093,11 @@ module BigBlueButton
|
||||
return false
|
||||
end
|
||||
|
||||
# Check if doc has tldraw events
|
||||
def self.check_for_tldraw_events(events)
|
||||
return !(events.xpath("recording/event[@eventname='TldrawCameraChangedEvent']").empty? &&
|
||||
events.xpath("recording/event[@eventname='AddTldrawShapeEvent']").empty?)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,6 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton recording caption upload handler
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -10,4 +11,4 @@ Slice=bbb_record_core.slice
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -2,6 +2,7 @@
|
||||
Description=BigBlueButton resque worker for recordings
|
||||
Wants=redis.service
|
||||
After=redis.service
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -15,4 +16,4 @@ Restart=always
|
||||
RestartSec=3
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -1,5 +1,6 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton recording processing starter
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@ -10,4 +11,4 @@ Slice=bbb_record_core.slice
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
@ -192,6 +192,10 @@ unless FileTest.directory?(target_dir)
|
||||
|
||||
# Copy thumbnails from raw files
|
||||
FileUtils.cp_r("#{pres_dir}/thumbnails", "#{target_pres_dir}/thumbnails") if File.exist?("#{pres_dir}/thumbnails")
|
||||
tldraw = BigBlueButton::Events.check_for_tldraw_events(@doc);
|
||||
if (tldraw)
|
||||
FileUtils.cp_r("#{pres_dir}/svgs", "#{target_pres_dir}/svgs") if File.exist?("#{pres_dir}/svgs")
|
||||
end
|
||||
end
|
||||
|
||||
BigBlueButton.logger.info('Generating closed captions')
|
||||
|
@ -382,6 +382,30 @@ def svg_render_shape_poll(g, slide, shape)
|
||||
width: width, height: height, x: x, y: y)
|
||||
end
|
||||
|
||||
def build_tldraw_shape(image_shapes, slide, shape)
|
||||
shape_in = shape[:in]
|
||||
shape_out = shape[:out]
|
||||
|
||||
if shape_in == shape_out
|
||||
BigBlueButton.logger.info("Draw #{shape[:shape_id]} Shape #{shape[:shape_unique_id]} is never shown (duration rounds to 0)")
|
||||
return
|
||||
end
|
||||
|
||||
if (shape_in >= slide[:out]) || (!shape[:out].nil? && shape[:out] <= slide[:in])
|
||||
BigBlueButton.logger.info("Draw #{shape[:shape_id]} Shape #{shape[:shape_unique_id]} is not visible during image time span")
|
||||
return
|
||||
end
|
||||
|
||||
tldraw_shape = {
|
||||
id: shape[:shape_id],
|
||||
timestamp: shape_in,
|
||||
undo: (shape[:undo].nil? ? -1 : shape[:undo]),
|
||||
shape_data: shape[:shape_data]
|
||||
}
|
||||
|
||||
image_shapes.push(tldraw_shape)
|
||||
end
|
||||
|
||||
def svg_render_shape(canvas, slide, shape, image_id)
|
||||
shape_in = shape[:in]
|
||||
shape_out = shape[:out]
|
||||
@ -426,7 +450,7 @@ def svg_render_shape(canvas, slide, shape, image_id)
|
||||
end
|
||||
|
||||
@svg_image_id = 1
|
||||
def svg_render_image(svg, slide, shapes)
|
||||
def svg_render_image(svg, slide, shapes, tldraw, tldraw_shapes)
|
||||
slide_number = slide[:slide]
|
||||
presentation = slide[:presentation]
|
||||
slide_in = slide[:in]
|
||||
@ -458,15 +482,25 @@ def svg_render_image(svg, slide, shapes)
|
||||
|
||||
shapes = shapes[presentation][slide_number]
|
||||
|
||||
canvas = doc.create_element('g',
|
||||
class: 'canvas', id: "canvas#{image_id}",
|
||||
image: "image#{image_id}", display: 'none')
|
||||
if !tldraw
|
||||
canvas = doc.create_element('g',
|
||||
class: 'canvas', id: "canvas#{image_id}",
|
||||
image: "image#{image_id}", display: 'none')
|
||||
|
||||
shapes.each do |shape|
|
||||
svg_render_shape(canvas, slide, shape, image_id)
|
||||
shapes.each do |shape|
|
||||
svg_render_shape(canvas, slide, shape, image_id)
|
||||
end
|
||||
|
||||
svg << canvas unless canvas.element_children.empty?
|
||||
else
|
||||
image_shapes = []
|
||||
|
||||
shapes.each do |shape|
|
||||
build_tldraw_shape(image_shapes, slide, shape)
|
||||
end
|
||||
|
||||
tldraw_shapes[image_id] = { :shapes=>image_shapes, :timestamp=> slide_in}
|
||||
end
|
||||
|
||||
svg << canvas unless canvas.element_children.empty?
|
||||
end
|
||||
|
||||
def panzoom_viewbox(panzoom)
|
||||
@ -483,13 +517,19 @@ def panzoom_viewbox(panzoom)
|
||||
[x, y, w, h]
|
||||
end
|
||||
|
||||
def panzooms_emit_event(rec, panzoom)
|
||||
def panzooms_emit_event(rec, panzoom, tldraw)
|
||||
panzoom_in = panzoom[:in]
|
||||
return if panzoom_in == panzoom[:out]
|
||||
|
||||
rec.event(timestamp: panzoom_in) do
|
||||
x, y, w, h = panzoom_viewbox(panzoom)
|
||||
rec.viewBox("#{x} #{y} #{w} #{h}")
|
||||
if !tldraw
|
||||
rec.event(timestamp: panzoom_in) do
|
||||
x, y, w, h = panzoom_viewbox(panzoom)
|
||||
rec.viewBox("#{x} #{y} #{w} #{h}")
|
||||
end
|
||||
else
|
||||
rec.event(timestamp: panzoom_in) do
|
||||
rec.cameraAndZoom("#{panzoom[:x_camera]} #{panzoom[:y_camera]} #{panzoom[:zoom]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -497,14 +537,14 @@ def convert_cursor_coordinate(cursor_coord, panzoom_offset, panzoom_ratio)
|
||||
(((cursor_coord / 100.0) + (panzoom_offset * MAGIC_MYSTERY_NUMBER / 100.0)) / (panzoom_ratio / 100.0)).round(5)
|
||||
end
|
||||
|
||||
def cursors_emit_event(rec, cursor)
|
||||
def cursors_emit_event(rec, cursor, tldraw)
|
||||
cursor_in = cursor[:in]
|
||||
return if cursor_in == cursor[:out]
|
||||
|
||||
rec.event(timestamp: cursor_in) do
|
||||
panzoom = cursor[:panzoom]
|
||||
if cursor[:visible]
|
||||
if @version_atleast_2_0_0
|
||||
if @version_atleast_2_0_0 && !tldraw
|
||||
# In BBB 2.0, the cursor now uses the same coordinate system as annotations
|
||||
# Use the panzoom information to convert it to be relative to viewbox
|
||||
x = convert_cursor_coordinate(cursor[:x], panzoom[:x_offset], panzoom[:width_ratio])
|
||||
@ -535,6 +575,53 @@ def determine_slide_number(slide, current_slide)
|
||||
slide
|
||||
end
|
||||
|
||||
def events_parse_tldraw_shape(shapes, event, current_presentation, current_slide, timestamp)
|
||||
presentation = event.at_xpath('presentation')
|
||||
slide = event.at_xpath('pageNumber')
|
||||
|
||||
presentation = determine_presentation(presentation, current_presentation)
|
||||
slide = determine_slide_number(slide, current_slide)
|
||||
|
||||
# Set up the shapes data structures if needed
|
||||
shapes[presentation] ||= {}
|
||||
shapes[presentation][slide] ||= []
|
||||
|
||||
# We only need to deal with shapes for this slide
|
||||
shapes = shapes[presentation][slide]
|
||||
|
||||
# Set up the structure for this shape
|
||||
shape = {}
|
||||
# Common properties
|
||||
shape[:in] = timestamp
|
||||
shape_data = shape[:shape_data] = JSON.parse(event.at_xpath('shapeData'))
|
||||
|
||||
user_id = event.at_xpath('userId')&.text
|
||||
shape[:user_id] = user_id if user_id
|
||||
|
||||
shape_id = event.at_xpath('shapeId')&.text
|
||||
shape[:id] = shape_id if shape_id
|
||||
|
||||
draw_id = shape[:shape_id] = @svg_shape_id
|
||||
@svg_shape_id += 1
|
||||
|
||||
# Find the previous shape, for updates
|
||||
prev_shape = nil
|
||||
if shape_id
|
||||
# If we have a shape ID, look up the previous shape by ID
|
||||
prev_shape_pos = shapes.rindex { |s| s[:shade_id] == shape_id }
|
||||
prev_shape = prev_shape_pos ? shapes[prev_shape_pos] : nil
|
||||
end
|
||||
if prev_shape
|
||||
prev_shape[:out] = timestamp
|
||||
shape[:shape_unique_id] = prev_shape[:shape_unique_id]
|
||||
else
|
||||
shape[:shape_unique_id] = @svg_shape_unique_id
|
||||
@svg_shape_unique_id += 1
|
||||
end
|
||||
|
||||
shapes << shape
|
||||
end
|
||||
|
||||
def events_parse_shape(shapes, event, current_presentation, current_slide, timestamp)
|
||||
# Figure out what presentation+slide this shape is for, with fallbacks
|
||||
# for old BBB where this info isn't in the shape messages
|
||||
@ -734,7 +821,7 @@ def events_parse_clear(shapes, event, current_presentation, current_slide, times
|
||||
end
|
||||
end
|
||||
|
||||
def events_get_image_info(slide)
|
||||
def events_get_image_info(slide, tldraw)
|
||||
slide_deskshare = slide[:deskshare]
|
||||
slide_presentation = slide[:presentation]
|
||||
|
||||
@ -744,7 +831,8 @@ def events_get_image_info(slide)
|
||||
slide[:src] = 'presentation/logo.png'
|
||||
else
|
||||
slide_nr = slide[:slide] + 1
|
||||
slide[:src] = "presentation/#{slide_presentation}/slide-#{slide_nr}.png"
|
||||
tldraw ? slide[:src] = "presentation/#{slide_presentation}/svgs/slide#{slide_nr}.svg"
|
||||
: slide[:src] = "presentation/#{slide_presentation}/slide-#{slide_nr}.png"
|
||||
slide[:text] = "presentation/#{slide_presentation}/textfiles/slide-#{slide_nr}.txt"
|
||||
end
|
||||
image_path = "#{@process_dir}/#{slide[:src]}"
|
||||
@ -792,6 +880,7 @@ def process_presentation(package_dir)
|
||||
# Current pan/zoom state
|
||||
current_x_offset = current_y_offset = 0.0
|
||||
current_width_ratio = current_height_ratio = 100.0
|
||||
current_x_camera = current_y_camera = current_zoom = 0.0
|
||||
# Current cursor status
|
||||
cursor_x = cursor_y = -1.0
|
||||
cursor_visible = false
|
||||
@ -802,6 +891,8 @@ def process_presentation(package_dir)
|
||||
panzooms = []
|
||||
cursors = []
|
||||
shapes = {}
|
||||
tldraw = BigBlueButton::Events.check_for_tldraw_events(@doc)
|
||||
tldraw_shapes = {}
|
||||
|
||||
# Iterate through the events.xml and store the events, building the
|
||||
# xml files as we go
|
||||
@ -836,6 +927,12 @@ def process_presentation(package_dir)
|
||||
current_height_ratio = event.at_xpath('heightRatio').text.to_f
|
||||
panzoom_changed = true
|
||||
|
||||
when 'TldrawCameraChangedEvent'
|
||||
current_x_camera = event.at_xpath('xCamera').text.to_f
|
||||
current_y_camera = event.at_xpath('yCamera').text.to_f
|
||||
current_zoom = event.at_xpath('zoom').text.to_f
|
||||
panzoom_changed = true
|
||||
|
||||
when 'DeskshareStartedEvent', 'StartWebRTCDesktopShareEvent'
|
||||
deskshare = slide_changed = true if @presentation_props['include_deskshare']
|
||||
|
||||
@ -848,7 +945,10 @@ def process_presentation(package_dir)
|
||||
when 'AddShapeEvent', 'ModifyTextEvent'
|
||||
events_parse_shape(shapes, event, current_presentation, current_slide, timestamp)
|
||||
|
||||
when 'UndoShapeEvent', 'UndoAnnotationEvent'
|
||||
when 'AddTldrawShapeEvent'
|
||||
events_parse_tldraw_shape(shapes, event, current_presentation, current_slide, timestamp)
|
||||
|
||||
when 'UndoShapeEvent', 'UndoAnnotationEvent', 'DeleteTldrawShapeEvent'
|
||||
events_parse_undo(shapes, event, current_presentation, current_slide, timestamp)
|
||||
|
||||
when 'ClearPageEvent', 'ClearWhiteboardEvent'
|
||||
@ -887,7 +987,7 @@ def process_presentation(package_dir)
|
||||
else
|
||||
if slide
|
||||
slide[:out] = timestamp
|
||||
svg_render_image(svg, slide, shapes)
|
||||
svg_render_image(svg, slide, shapes, tldraw, tldraw_shapes)
|
||||
end
|
||||
|
||||
BigBlueButton.logger.info("Presentation #{current_presentation} Slide #{current_slide} Deskshare #{deskshare}")
|
||||
@ -897,7 +997,7 @@ def process_presentation(package_dir)
|
||||
in: timestamp,
|
||||
deskshare: deskshare,
|
||||
}
|
||||
events_get_image_info(slide)
|
||||
events_get_image_info(slide, tldraw)
|
||||
slides << slide
|
||||
end
|
||||
end
|
||||
@ -909,40 +1009,59 @@ def process_presentation(package_dir)
|
||||
slide_width = slide[:width]
|
||||
slide_height = slide[:height]
|
||||
if panzoom &&
|
||||
(panzoom[:deskshare] == deskshare) &&
|
||||
((!tldraw &&
|
||||
(panzoom[:x_offset] == current_x_offset) &&
|
||||
(panzoom[:y_offset] == current_y_offset) &&
|
||||
(panzoom[:width_ratio] == current_width_ratio) &&
|
||||
(panzoom[:height_ratio] == current_height_ratio) &&
|
||||
(panzoom[:width] == slide_width) &&
|
||||
(panzoom[:height] == slide_height) &&
|
||||
(panzoom[:deskshare] == deskshare)
|
||||
(panzoom[:height] == slide_height)) ||
|
||||
(tldraw &&
|
||||
(panzoom[:x_camera] == current_x_camera) &&
|
||||
(panzoom[:y_camera] == current_y_camera) &&
|
||||
(panzoom[:zoom] == current_zoom))
|
||||
)
|
||||
BigBlueButton.logger.info('Panzoom: skipping, no changes')
|
||||
panzoom_changed = false
|
||||
else
|
||||
if panzoom
|
||||
panzoom[:out] = timestamp
|
||||
panzooms_emit_event(panzooms_rec, panzoom)
|
||||
panzooms_emit_event(panzooms_rec, panzoom, tldraw)
|
||||
end
|
||||
if !tldraw
|
||||
BigBlueButton.logger.info("Panzoom: #{current_x_offset} #{current_y_offset} #{current_width_ratio} #{current_height_ratio} (#{slide_width}x#{slide_height})")
|
||||
panzoom = {
|
||||
x_offset: current_x_offset,
|
||||
y_offset: current_y_offset,
|
||||
width_ratio: current_width_ratio,
|
||||
height_ratio: current_height_ratio,
|
||||
width: slide[:width],
|
||||
height: slide[:height],
|
||||
in: timestamp,
|
||||
deskshare: deskshare,
|
||||
}
|
||||
else
|
||||
BigBlueButton.logger.info("Panzoom: #{current_x_camera} #{current_y_camera} #{current_zoom} (#{slide_width}x#{slide_height})")
|
||||
panzoom = {
|
||||
x_camera: current_x_camera,
|
||||
y_camera: current_y_camera,
|
||||
zoom: current_zoom,
|
||||
in: timestamp,
|
||||
deskshare: deskshare,
|
||||
}
|
||||
end
|
||||
BigBlueButton.logger.info("Panzoom: #{current_x_offset} #{current_y_offset} #{current_width_ratio} #{current_height_ratio} (#{slide_width}x#{slide_height})")
|
||||
panzoom = {
|
||||
x_offset: current_x_offset,
|
||||
y_offset: current_y_offset,
|
||||
width_ratio: current_width_ratio,
|
||||
height_ratio: current_height_ratio,
|
||||
width: slide[:width],
|
||||
height: slide[:height],
|
||||
in: timestamp,
|
||||
deskshare: deskshare,
|
||||
}
|
||||
panzooms << panzoom
|
||||
end
|
||||
end
|
||||
|
||||
# Perform cursor finalization
|
||||
if cursor_changed || panzoom_changed
|
||||
unless cursor_x >= 0 && cursor_x <= 100 &&
|
||||
cursor_y >= 0 && cursor_y <= 100
|
||||
cursor_visible = false
|
||||
if !tldraw
|
||||
unless cursor_x >= 0 && cursor_x <= 100 &&
|
||||
cursor_y >= 0 && cursor_y <= 100
|
||||
cursor_visible = false
|
||||
end
|
||||
end
|
||||
|
||||
panzoom = panzooms.last
|
||||
@ -955,7 +1074,7 @@ def process_presentation(package_dir)
|
||||
else
|
||||
if cursor
|
||||
cursor[:out] = timestamp
|
||||
cursors_emit_event(cursors_rec, cursor)
|
||||
cursors_emit_event(cursors_rec, cursor, tldraw)
|
||||
end
|
||||
cursor = {
|
||||
visible: cursor_visible,
|
||||
@ -972,26 +1091,27 @@ def process_presentation(package_dir)
|
||||
# Add the last slide, panzoom, and cursor
|
||||
slide = slides.last
|
||||
slide[:out] = last_timestamp
|
||||
svg_render_image(svg, slide, shapes)
|
||||
svg_render_image(svg, slide, shapes, tldraw, tldraw_shapes)
|
||||
panzoom = panzooms.last
|
||||
panzoom[:out] = last_timestamp
|
||||
panzooms_emit_event(panzooms_rec, panzoom)
|
||||
panzooms_emit_event(panzooms_rec, panzoom, tldraw)
|
||||
cursor = cursors.last
|
||||
cursor[:out] = last_timestamp
|
||||
cursors_emit_event(cursors_rec, cursor)
|
||||
cursors_emit_event(cursors_rec, cursor, tldraw)
|
||||
|
||||
cursors_doc = Builder::XmlMarkup.new(indent: 2)
|
||||
cursors_doc.instruct!
|
||||
cursors_doc.recording(id: 'cursor_events') { |xml| xml << cursors_rec.target! }
|
||||
cursors_doc.recording(id: 'cursor_events', tldraw: tldraw) { |xml| xml << cursors_rec.target! }
|
||||
|
||||
panzooms_doc = Builder::XmlMarkup.new(indent: 2)
|
||||
panzooms_doc.instruct!
|
||||
panzooms_doc.recording(id: 'panzoom_events') { |xml| xml << panzooms_rec.target! }
|
||||
panzooms_doc.recording(id: 'panzoom_events', tldraw: tldraw) { |xml| xml << panzooms_rec.target! }
|
||||
|
||||
# And save the result
|
||||
File.write("#{package_dir}/#{@shapes_svg_filename}", shapes_doc.to_xml)
|
||||
File.write("#{package_dir}/#{@panzooms_xml_filename}", panzooms_doc.target!)
|
||||
File.write("#{package_dir}/#{@cursor_xml_filename}", cursors_doc.target!)
|
||||
generate_json_file(package_dir, @tldraw_shapes_filename, tldraw_shapes) if tldraw
|
||||
end
|
||||
|
||||
def process_chat_messages(events, bbb_props)
|
||||
@ -1170,6 +1290,7 @@ end
|
||||
@panzooms_xml_filename = 'panzooms.xml'
|
||||
@cursor_xml_filename = 'cursor.xml'
|
||||
@deskshare_xml_filename = 'deskshare.xml'
|
||||
@tldraw_shapes_filename = 'tldraw.json'
|
||||
@svg_shape_id = 1
|
||||
@svg_shape_unique_id = 1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user