From 9f833a47603d796c7d85fba810262a3da2c387ca Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 14 Feb 2022 18:49:11 +0100 Subject: [PATCH 01/41] Introduce bigbluebutton.target --- build/packages-template/bbb-config/bigbluebutton.target | 7 +++++++ build/packages-template/bbb-config/build.sh | 2 ++ build/packages-template/bbb-etherpad/etherpad.service | 3 ++- build/packages-template/bbb-html5/bbb-html5.service | 3 ++- .../bbb-html5/disable-transparent-huge-pages.service | 3 ++- build/packages-template/bbb-html5/mongod.service | 3 ++- .../bbb-libreoffice-docker/libreoffice.service | 4 ++-- build/packages-template/bbb-lti/bbb-lti.service | 3 ++- build/packages-template/bbb-web/bbb-web.service | 3 ++- build/packages-template/bbb-webhooks/bbb-webhooks.service | 3 ++- .../bbb-webrtc-sfu/bbb-webrtc-sfu.service | 3 ++- .../bbb-webrtc-sfu/kurento-media-server.service | 3 ++- 12 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 build/packages-template/bbb-config/bigbluebutton.target diff --git a/build/packages-template/bbb-config/bigbluebutton.target b/build/packages-template/bbb-config/bigbluebutton.target new file mode 100644 index 0000000000..b24b4b09cd --- /dev/null +++ b/build/packages-template/bbb-config/bigbluebutton.target @@ -0,0 +1,7 @@ +[Unit] +Description=Big Blue Button System +Requires= +After=syslog.target network.target + +[Install] +WantedBy=multi-user.target diff --git a/build/packages-template/bbb-config/build.sh b/build/packages-template/bbb-config/build.sh index be008f33c7..7a17f706e4 100755 --- a/build/packages-template/bbb-config/build.sh +++ b/build/packages-template/bbb-config/build.sh @@ -14,6 +14,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" @@ -68,6 +69,7 @@ Wants=redis-server.service After=redis-server.service HERE +cp bigbluebutton.target staging/lib/systemd/system/ . ./opts-$DISTRO.sh diff --git a/build/packages-template/bbb-etherpad/etherpad.service b/build/packages-template/bbb-etherpad/etherpad.service index 7f844c379b..c1f01089ae 100644 --- a/build/packages-template/bbb-etherpad/etherpad.service +++ b/build/packages-template/bbb-etherpad/etherpad.service @@ -2,6 +2,7 @@ Description=Etherpad Server Wants=redis-server.service After=syslog.target network.target +packages-template/bbb-config/build.sh [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 diff --git a/build/packages-template/bbb-html5/bbb-html5.service b/build/packages-template/bbb-html5/bbb-html5.service index ef3bc8ca5a..c58d02b3a9 100644 --- a/build/packages-template/bbb-html5/bbb-html5.service +++ b/build/packages-template/bbb-html5/bbb-html5.service @@ -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 diff --git a/build/packages-template/bbb-html5/disable-transparent-huge-pages.service b/build/packages-template/bbb-html5/disable-transparent-huge-pages.service index a50ff6476f..fafda696e9 100644 --- a/build/packages-template/bbb-html5/disable-transparent-huge-pages.service +++ b/build/packages-template/bbb-html5/disable-transparent-huge-pages.service @@ -1,5 +1,6 @@ [Unit] Description=Disable Transparent Huge Pages +PartOf=bigbluebutton.target [Service] Type=oneshot @@ -7,4 +8,4 @@ ExecStart=/bin/sh -c "/bin/echo "never" | tee /sys/kernel/mm/transparent_hugepag ExecStart=/bin/sh -c "/bin/echo "never" | tee /sys/kernel/mm/transparent_hugepage/defrag" [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target bigbluebutton.target diff --git a/build/packages-template/bbb-html5/mongod.service b/build/packages-template/bbb-html5/mongod.service index 659f40878b..d84dc5abb6 100644 --- a/build/packages-template/bbb-html5/mongod.service +++ b/build/packages-template/bbb-html5/mongod.service @@ -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 diff --git a/build/packages-template/bbb-libreoffice-docker/libreoffice.service b/build/packages-template/bbb-libreoffice-docker/libreoffice.service index cb0fff0c9d..d1b84573f2 100644 --- a/build/packages-template/bbb-libreoffice-docker/libreoffice.service +++ b/build/packages-template/bbb-libreoffice-docker/libreoffice.service @@ -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 diff --git a/build/packages-template/bbb-lti/bbb-lti.service b/build/packages-template/bbb-lti/bbb-lti.service index 2a3a38a94c..d951f8b100 100644 --- a/build/packages-template/bbb-lti/bbb-lti.service +++ b/build/packages-template/bbb-lti/bbb-lti.service @@ -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 diff --git a/build/packages-template/bbb-web/bbb-web.service b/build/packages-template/bbb-web/bbb-web.service index 6caf03f082..bb68dbcaa5 100644 --- a/build/packages-template/bbb-web/bbb-web.service +++ b/build/packages-template/bbb-web/bbb-web.service @@ -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 diff --git a/build/packages-template/bbb-webhooks/bbb-webhooks.service b/build/packages-template/bbb-webhooks/bbb-webhooks.service index daf6c0d73e..fda742c862 100644 --- a/build/packages-template/bbb-webhooks/bbb-webhooks.service +++ b/build/packages-template/bbb-webhooks/bbb-webhooks.service @@ -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 diff --git a/build/packages-template/bbb-webrtc-sfu/bbb-webrtc-sfu.service b/build/packages-template/bbb-webrtc-sfu/bbb-webrtc-sfu.service index 0a44ee1ae5..b3147dda89 100644 --- a/build/packages-template/bbb-webrtc-sfu/bbb-webrtc-sfu.service +++ b/build/packages-template/bbb-webrtc-sfu/bbb-webrtc-sfu.service @@ -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 diff --git a/build/packages-template/bbb-webrtc-sfu/kurento-media-server.service b/build/packages-template/bbb-webrtc-sfu/kurento-media-server.service index 1c8d33f8ab..c50e5d8b73 100644 --- a/build/packages-template/bbb-webrtc-sfu/kurento-media-server.service +++ b/build/packages-template/bbb-webrtc-sfu/kurento-media-server.service @@ -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 From 568756bf7ef3ef0be71ccea7ece2c8a7b7a32f8b Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 14 Feb 2022 18:49:13 +0100 Subject: [PATCH 02/41] move systemd files to /lib/systemd/system --- build/packages-template/bbb-html5/after-install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/packages-template/bbb-html5/after-install.sh b/build/packages-template/bbb-html5/after-install.sh index d119456c19..073fcc81b5 100644 --- a/build/packages-template/bbb-html5/after-install.sh +++ b/build/packages-template/bbb-html5/after-install.sh @@ -77,9 +77,9 @@ if [ -f /opt/freeswitch/etc/freeswitch/sip_profiles/external.xml ]; then sed -i 's///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 From dbae417b0c1c361082a53573a687be7548cba699 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 14 Feb 2022 18:49:14 +0100 Subject: [PATCH 03/41] akka apps should not have override files they are already provided by sbt --- build/packages-template/bbb-config/build.sh | 24 --------------------- 1 file changed, 24 deletions(-) diff --git a/build/packages-template/bbb-config/build.sh b/build/packages-template/bbb-config/build.sh index 7a17f706e4..3f0b0b2a1d 100755 --- a/build/packages-template/bbb-config/build.sh +++ b/build/packages-template/bbb-config/build.sh @@ -45,30 +45,6 @@ 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 < staging/etc/systemd/system/bbb-fsesl-akka.service.d/override.conf < staging/etc/systemd/system/bbb-transcode-akka.service.d/override.conf < Date: Thu, 17 Mar 2022 14:23:28 +0100 Subject: [PATCH 04/41] make bbb-pads.service part of bigbluebutton.target --- build/packages-template/bbb-pads/bbb-pads.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/packages-template/bbb-pads/bbb-pads.service b/build/packages-template/bbb-pads/bbb-pads.service index 200b7c03f6..6c130ecf1c 100644 --- a/build/packages-template/bbb-pads/bbb-pads.service +++ b/build/packages-template/bbb-pads/bbb-pads.service @@ -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 From 658b89308d6eefeef398e90f191340ab4d49a60b Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Thu, 17 Mar 2022 14:27:05 +0100 Subject: [PATCH 05/41] chore: remove obsolete gstream upgrade routine --- bigbluebutton-config/bin/bbb-conf | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index ed319dfb9b..7bd5918ca8 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -861,26 +861,6 @@ check_configuration() { } -update_gstreamer() { - # due to a change in the kurento packages naming convention, gstreamer packages don't naturally upgrade - # this snippet checks if the installed gstreamer packages are the same as the one available in the repository - # if they are not, it will update (possibly downgrade) - # TODO remove it on 2.3 or above - if [ "$DISTRIB_CODENAME" == "xenial" ]; then - DOWNGRADE_LIST="" - for PACKAGE in $(dpkg -l | grep gst | tr -s ' ' | cut -d' ' -f2 | cut -d':' -f1); do - RIGHT_VERSION=$(apt-cache policy $PACKAGE | grep -B1 ubuntu.bigbluebutton.org | head -n1 | tr -s ' ' | cut -d' ' -f2) - if [[ $RIGHT_VERSION != "***" ]] && [[ $RIGHT_VERSION != "" ]]; then - echo "Force $PACKAGE to version $RIGHT_VERSION" - DOWNGRADE_LIST="$PACKAGE=$RIGHT_VERSION $DOWNGRADE_LIST" - fi - done - if [[ $DOWNGRADE_LIST != "" ]]; then - apt-get -y --allow-downgrades install $DOWNGRADE_LIST > /dev/null - fi - fi -} - check_state() { echo print_header @@ -1737,8 +1717,6 @@ String BigBlueButtonURL = \"$BBB_WEB_URL/bigbluebutton/\"; echo "Restarting the BigBlueButton $BIGBLUEBUTTON_RELEASE ..." stop_bigbluebutton - update_gstreamer - echo start_bigbluebutton exit 0 @@ -1752,7 +1730,6 @@ if [ $RESTART ]; then echo "Restarting BigBlueButton $BIGBLUEBUTTON_RELEASE ..." stop_bigbluebutton - update_gstreamer start_bigbluebutton check_state fi @@ -1764,7 +1741,6 @@ if [ $CLEAN ]; then echo "Restarting BigBlueButton $BIGBLUEBUTTON_RELEASE (and cleaning out all log files) ..." stop_bigbluebutton - update_gstreamer # # Clean log files From 9a71e8e0b39ec99a057b5d5738c1d9084895b829 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Thu, 17 Mar 2022 15:04:16 +0100 Subject: [PATCH 06/41] make record-and-playback-scripts part of bbb.target --- record-and-playback/core/systemd/bbb-rap-caption-inbox.service | 3 ++- record-and-playback/core/systemd/bbb-rap-resque-worker.service | 3 ++- record-and-playback/core/systemd/bbb-rap-starter.service | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/record-and-playback/core/systemd/bbb-rap-caption-inbox.service b/record-and-playback/core/systemd/bbb-rap-caption-inbox.service index 528954381e..09dff10622 100644 --- a/record-and-playback/core/systemd/bbb-rap-caption-inbox.service +++ b/record-and-playback/core/systemd/bbb-rap-caption-inbox.service @@ -1,5 +1,6 @@ [Unit] Description=BigBlueButton recording caption upload handler +PartOf=bigbluebutton.target [Service] Type=simple @@ -9,4 +10,4 @@ Slice=bbb_record_core.slice Restart=on-failure [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target bigbluebutton.target diff --git a/record-and-playback/core/systemd/bbb-rap-resque-worker.service b/record-and-playback/core/systemd/bbb-rap-resque-worker.service index 4fec548cf3..f0b7d2c2dc 100644 --- a/record-and-playback/core/systemd/bbb-rap-resque-worker.service +++ b/record-and-playback/core/systemd/bbb-rap-resque-worker.service @@ -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 diff --git a/record-and-playback/core/systemd/bbb-rap-starter.service b/record-and-playback/core/systemd/bbb-rap-starter.service index de7e5eb8f9..9aba301aca 100644 --- a/record-and-playback/core/systemd/bbb-rap-starter.service +++ b/record-and-playback/core/systemd/bbb-rap-starter.service @@ -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 From 61ce7ab9b658cea6e069faf91c96e6cb1d90f349 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 14 Feb 2022 18:49:14 +0100 Subject: [PATCH 07/41] inject dependency to bigbluebutton.target into externally provided services --- build/packages-template/bbb-config/bigbluebutton.conf | 5 +++++ build/packages-template/bbb-config/build.sh | 6 ++++++ .../bbb-freeswitch-core/freeswitch.service.focal | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 build/packages-template/bbb-config/bigbluebutton.conf diff --git a/build/packages-template/bbb-config/bigbluebutton.conf b/build/packages-template/bbb-config/bigbluebutton.conf new file mode 100644 index 0000000000..f49dc0bf44 --- /dev/null +++ b/build/packages-template/bbb-config/bigbluebutton.conf @@ -0,0 +1,5 @@ +[Unit] +PartOf=bigbluebutton.target + +[Install] +WantedBy=bigbluebutton.target diff --git a/build/packages-template/bbb-config/build.sh b/build/packages-template/bbb-config/build.sh index 3f0b0b2a1d..cbc2b7d435 100755 --- a/build/packages-template/bbb-config/build.sh +++ b/build/packages-template/bbb-config/build.sh @@ -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) diff --git a/build/packages-template/bbb-freeswitch-core/freeswitch.service.focal b/build/packages-template/bbb-freeswitch-core/freeswitch.service.focal index 4d5b714c21..5111cd1fc9 100644 --- a/build/packages-template/bbb-freeswitch-core/freeswitch.service.focal +++ b/build/packages-template/bbb-freeswitch-core/freeswitch.service.focal @@ -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 From cd80d891e7d736db6be7e7b9b59784421afeee16 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Thu, 17 Mar 2022 15:29:40 +0100 Subject: [PATCH 08/41] make bbb-conf use bigbluebutton.target --- bigbluebutton-config/bin/bbb-conf | 57 ++----------------------------- 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 7bd5918ca8..2cd520b407 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -338,35 +338,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.service } start_bigbluebutton () { @@ -389,41 +365,12 @@ start_bigbluebutton () { fi 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 fi - systemctl start $TOMCAT_SERVICE 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 - - if [ -f /usr/lib/systemd/system/bbb-html5.service ]; then - systemctl start mongod - sleep 3 - systemctl start bbb-html5 - fi + systemctl start $TOMCAT_SERVICE bigbluebutton.target } display_bigbluebutton_status () { From 91c882862e6879e397967f6bef802cb5b051ee3e Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Thu, 17 Mar 2022 16:06:42 +0100 Subject: [PATCH 09/41] fix paste error --- build/packages-template/bbb-etherpad/etherpad.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/packages-template/bbb-etherpad/etherpad.service b/build/packages-template/bbb-etherpad/etherpad.service index c1f01089ae..fa408bf374 100644 --- a/build/packages-template/bbb-etherpad/etherpad.service +++ b/build/packages-template/bbb-etherpad/etherpad.service @@ -2,7 +2,7 @@ Description=Etherpad Server Wants=redis-server.service After=syslog.target network.target -packages-template/bbb-config/build.sh +PartOf=bigbluebutton.target [Service] Type=simple From c9606257aad443366319b8f5dd69f6ecfd4cdd50 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Tue, 26 Apr 2022 10:51:29 -0400 Subject: [PATCH 10/41] package build scripts - calculate GIT_REV and COMMIT_DATE outside the docker container and pass them in as environment variables, since we can't compute them inside the docker container if the source directory is a git worktree --- build/setup-inside-docker.sh | 7 ------- build/setup.sh | 12 ++++++++++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/build/setup-inside-docker.sh b/build/setup-inside-docker.sh index ee54366b89..3ae629fa62 100755 --- a/build/setup-inside-docker.sh +++ b/build/setup-inside-docker.sh @@ -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} diff --git a/build/setup.sh b/build/setup.sh index f8ee735905..1b33da724e 100755 --- a/build/setup.sh +++ b/build/setup.sh @@ -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 \ No newline at end of file +find artifacts From 853d0dfd9bf2812d7cbd45e0805c707939b8f8d3 Mon Sep 17 00:00:00 2001 From: germanocaumo Date: Thu, 23 Jun 2022 17:04:09 +0000 Subject: [PATCH 11/41] fix(whiteboard): tldraw recording processing/publishing Changed the names of tldraw record events to differentiate from before. Publish tldraw.json file with all shape information during the meeting to be used in playback. Adapted cursor.xml and panzoom.xml to store tldraw data. Publish slides svgs to be used by playback's tldraw component (otherwise we have different image sizes in pngs and thus messing the coordinates). Retro-compatible with old recordings. --- .../AddTldrawShapeWhiteboardRecordEvent.scala | 65 ++++++ .../events/DeleteTldrawShapeRecordEvent.scala | 39 ++++ .../ResizeAndMoveSlideRecordEvent.scala | 23 +- .../TldrawCameraChangedRecordEvent.scala | 54 +++++ .../endpoint/redis/RedisRecorderActor.scala | 6 +- .../whiteboard/cursors/component.jsx | 7 +- .../recordandplayback/generators/events.rb | 10 +- .../scripts/process/presentation.rb | 4 + .../scripts/publish/presentation.rb | 205 ++++++++++++++---- 9 files changed, 353 insertions(+), 60 deletions(-) create mode 100755 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/AddTldrawShapeWhiteboardRecordEvent.scala create mode 100755 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/DeleteTldrawShapeRecordEvent.scala create mode 100755 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/TldrawCameraChangedRecordEvent.scala diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/AddTldrawShapeWhiteboardRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/AddTldrawShapeWhiteboardRecordEvent.scala new file mode 100755 index 0000000000..cdba60459d --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/AddTldrawShapeWhiteboardRecordEvent.scala @@ -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 . + * + */ + +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" +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/DeleteTldrawShapeRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/DeleteTldrawShapeRecordEvent.scala new file mode 100755 index 0000000000..4322e03895 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/DeleteTldrawShapeRecordEvent.scala @@ -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 . + * + */ + +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" +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/ResizeAndMoveSlideRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/ResizeAndMoveSlideRecordEvent.scala index 1797a89ada..0905fd5d8a 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/ResizeAndMoveSlideRecordEvent.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/ResizeAndMoveSlideRecordEvent.scala @@ -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" } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/TldrawCameraChangedRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/TldrawCameraChangedRecordEvent.scala new file mode 100755 index 0000000000..f5ea3deba8 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/TldrawCameraChangedRecordEvent.scala @@ -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 . + * + */ + +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" +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala index 0954bed385..04097fc8ab 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala @@ -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)) diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx index 387685915e..8aaf70dd0a 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx @@ -1,6 +1,5 @@ import * as React from "react"; import ReactCursorPosition from "react-cursor-position"; -import Vec from "@tldraw/vec"; import { _ } from "lodash"; function usePrevious(value) { @@ -79,7 +78,7 @@ const PositionLabel = (props) => { whiteboardId, } = props; - const { name, color, userId, presenter } = currentUser; + const { name, color } = currentUser; const prevCurrentPoint = usePrevious(currentPoint); React.useEffect(() => { @@ -128,8 +127,8 @@ export default function Cursors(props) { !cursorWrapper.hasOwnProperty("mouseleave") && cursorWrapper?.addEventListener("mouseleave", (event) => { publishCursorUpdate({ - xPercent: null, - yPercent: null, + xPercent: -1.0, + yPercent: -1.0, whiteboardId: whiteboardId, }); setActive(false); diff --git a/record-and-playback/core/lib/recordandplayback/generators/events.rb b/record-and-playback/core/lib/recordandplayback/generators/events.rb index 97beb67cdf..e145cf3972 100755 --- a/record-and-playback/core/lib/recordandplayback/generators/events.rb +++ b/record-and-playback/core/lib/recordandplayback/generators/events.rb @@ -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 \ No newline at end of file +end diff --git a/record-and-playback/presentation/scripts/process/presentation.rb b/record-and-playback/presentation/scripts/process/presentation.rb index aa64702af2..d0b0630b1b 100755 --- a/record-and-playback/presentation/scripts/process/presentation.rb +++ b/record-and-playback/presentation/scripts/process/presentation.rb @@ -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') diff --git a/record-and-playback/presentation/scripts/publish/presentation.rb b/record-and-playback/presentation/scripts/publish/presentation.rb index 38ad1049e5..503f64e6a0 100755 --- a/record-and-playback/presentation/scripts/publish/presentation.rb +++ b/record-and-playback/presentation/scripts/publish/presentation.rb @@ -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 From 11afdcfb96ca1f7829d8c0d888b99659c6daf4c1 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 28 Jun 2022 20:13:02 +0200 Subject: [PATCH 12/41] fix: restart the bigbluebutton target, not a non-existing service --- bigbluebutton-config/bin/bbb-conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 935729274e..f279a16748 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -346,7 +346,7 @@ stop_bigbluebutton () { TOMCAT_SERVICE=$TOMCAT_USER fi - systemctl stop $TOMCAT_SERVICE bigbluebutton.service + systemctl stop $TOMCAT_SERVICE bigbluebutton.target } start_bigbluebutton () { From 75c8dcd491dc229a44103478441d2dcfbbf6b13d Mon Sep 17 00:00:00 2001 From: Tiago Jacobs Date: Wed, 16 Feb 2022 21:51:39 -0300 Subject: [PATCH 13/41] Merge 2.6 --- bigbluebutton-html5/client/main.jsx | 1 + .../actions-bar/screenshare/component.jsx | 4 +- .../ui/components/screenshare/service.js | 6 + .../imports/ui/services/mobile-app/index.js | 191 ++++++++++++++++++ .../imports/utils/browserInfo.js | 8 +- .../imports/utils/deviceInfo.js | 5 +- 6 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 bigbluebutton-html5/imports/ui/services/mobile-app/index.js diff --git a/bigbluebutton-html5/client/main.jsx b/bigbluebutton-html5/client/main.jsx index 5cb59f24bb..a42c539989 100755 --- a/bigbluebutton-html5/client/main.jsx +++ b/bigbluebutton-html5/client/main.jsx @@ -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'; diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx index 382176f7dc..cd40c7179d 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx @@ -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' diff --git a/bigbluebutton-html5/imports/ui/components/screenshare/service.js b/bigbluebutton-html5/imports/ui/components/screenshare/service.js index 22b314c596..9c8c73de99 100644 --- a/bigbluebutton-html5/imports/ui/components/screenshare/service.js +++ b/bigbluebutton-html5/imports/ui/components/screenshare/service.js @@ -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. diff --git a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js new file mode 100644 index 0000000000..c4f7ec723f --- /dev/null +++ b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js @@ -0,0 +1,191 @@ +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("Mobile APP detected"); + + // 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, arguments=[]) { + 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: arguments, + })); + } ); + } 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) => { + // alert("Constraints applied: " + JSON.stringify(constraints)); + 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) + + const videoTracks = [ + fakeVideoTrack + ]; + stream.getTracks = stream.getVideoTracks = function () { + return videoTracks; + }; + resolve(stream); + } + ).catch( + () => alert("Não deu") + ); + }); + } + + // RTCPeerConnection + const prototype = window.RTCPeerConnection.prototype; + + prototype.createOffer = function (options) { + logger.info("BBB-MOBILE - createOffer called", {options}); + + return new Promise( (resolve, reject) => { + callNativeMethod('createOffer').then ( sdp => { + logger.info("BBB-MOBILE - createOffer resolved", {sdp}); + + // + resolve({ + type: 'offer', + sdp + }); + }); + } ); + }; + + prototype.addEventListener = function (event, callback) { + logger.info("BBB-MOBILE - addEventListener called", {event, callback}); + + switch(event) { + case 'icecandidate': + window.bbbMobileScreenShareIceCandidateCallback = function () { + console.log("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.setLocalDescription = function (description, successCallback, failureCallback) { + 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.setRemoteDescription = function (description, successCallback, failureCallback) { + 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) {}}); + + return new Promise( (resolve, reject) => { + callNativeMethod('setRemoteDescription', [description]).then ( () => { + logger.info("BBB-MOBILE - setRemoteDescription resolved"); + + resolve(); + }); + } ); + } + + prototype.addTrack = function (description, successCallback, failureCallback) { + logger.info("BBB-MOBILE - addTrack called", {description, successCallback, failureCallback}); + } + + prototype.getLocalStreams = function() { + logger.info("BBB-MOBILE - getLocalStreams called", arguments); + + // + return [ + stream + ]; + } + + prototype.addTransceiver = function() { + logger.info("BBB-MOBILE - addTransceiver called", arguments); + } + + prototype.addIceCandidate = function (candidate) { + logger.info("BBB-MOBILE - addIceCandidate called", {candidate}); + + return new Promise( (resolve, reject) => { + callNativeMethod('addRemoteIceCandidate', [candidate]).then ( () => { + logger.info("BBB-MOBILE - addRemoteIceCandidate resolved"); + + resolve(); + }); + } ); + } + + } +})(); + + diff --git a/bigbluebutton-html5/imports/utils/browserInfo.js b/bigbluebutton-html5/imports/utils/browserInfo.js index 2459cb8af6..98c4d69213 100755 --- a/bigbluebutton-html5/imports/utils/browserInfo.js +++ b/bigbluebutton-html5/imports/utils/browserInfo.js @@ -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; diff --git a/bigbluebutton-html5/imports/utils/deviceInfo.js b/bigbluebutton-html5/imports/utils/deviceInfo.js index 9471862c58..3acb0e8c52 100755 --- a/bigbluebutton-html5/imports/utils/deviceInfo.js +++ b/bigbluebutton-html5/imports/utils/deviceInfo.js @@ -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; From f459aec949e443d88b6f9ced8055bf01324d5a03 Mon Sep 17 00:00:00 2001 From: Tiago Jacobs Date: Sat, 16 Apr 2022 20:17:50 -0300 Subject: [PATCH 14/41] Fixes variable name to avoid colision with reserved arguments variable --- bigbluebutton-html5/imports/ui/services/mobile-app/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js index c4f7ec723f..2521e81daf 100644 --- a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js +++ b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js @@ -14,7 +14,7 @@ import logger from '/imports/startup/client/logger'; const promisesHolder = {}; // Call a method in the mobile application, returning a promise for its execution - function callNativeMethod(method, arguments=[]) { + function callNativeMethod(method, args=[]) { try { const sequence = ++sequenceHolder.sequence; @@ -26,7 +26,7 @@ import logger from '/imports/startup/client/logger'; window.ReactNativeWebView.postMessage(JSON.stringify({ sequence: sequenceHolder.sequence, method: method, - arguments: arguments, + arguments: args, })); } ); } catch(e) { From 092f5bcafdb6a2057ac4f72b8abb25c92b40d91e Mon Sep 17 00:00:00 2001 From: Tiago Jacobs Date: Sun, 17 Apr 2022 10:12:28 -0300 Subject: [PATCH 15/41] Add logic to skip webRTC replacement methods when it's not a screenshare --- .../imports/ui/services/mobile-app/index.js | 100 +++++++++++++++--- 1 file changed, 84 insertions(+), 16 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js index 2521e81daf..2a00d26a39 100644 --- a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js +++ b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js @@ -5,8 +5,39 @@ import logger from '/imports/startup/client/logger'; // 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("Mobile APP detected"); + logger.debug(`BBB-MOBILE - Mobile APP detected`); + // This function detects if the call happened to publish a screenshare + function isScreenShareBroadcastRelated(caller, peerConnection = null, args = null) { + // Keep track of how many webRTC evaluations was done + if(!peerConnection.isSBREvaluations) + peerConnection.isSBREvaluations = 0; + + peerConnection.isSBREvaluations ++; + + // If already successfully evaluated, reuse + if(peerConnection && peerConnection.isSBR !== undefined ) { + logger.info(`BBB-MOBILE - isScreenShareBroadcastRelated (already evaluated as ${peerConnection.isSBR})`, {caller, peerConnection}); + return peerConnection.isSBR; + } + + // Evaluate context otherwise + const e = new Error('dummy'); + const stackTrace = e.stack; + logger.info(`BBB-MOBILE - isScreenShareBroadcastRelated (evaluating)`, {caller, peerConnection, stackTrace: stackTrace.split('\n'), isSBREvaluations: peerConnection.isSBREvaluations, args}); + + // addTransceiver is the first call for screensharing and it has a startScreensharing in its stackTrace + if( peerConnection.isSBREvaluations == 1) { + if(caller == 'addTransceiver' && stackTrace.indexOf('startScreensharing') !== -1) { + peerConnection.isSBR = true; + } else { + peerConnection.isSBR = false; + } + + return peerConnection.isSBR; + } + + } // Store the method call sequential const sequenceHolder = {sequence: 0}; @@ -27,7 +58,7 @@ import logger from '/imports/startup/client/logger'; sequence: sequenceHolder.sequence, method: method, arguments: args, - })); + })); } ); } catch(e) { logger.error(`Error on callNativeMethod ${e.message}`, e); @@ -56,7 +87,7 @@ import logger from '/imports/startup/client/logger'; // Navigator navigator.getDisplayMedia = function() { - logger.info("BBB-MOBILE - getDisplayMedia called", arguments); + logger.info(`BBB-MOBILE - getDisplayMedia called`, arguments); return new Promise((resolve, reject) => { callNativeMethod('initializeScreenShare').then( @@ -65,7 +96,6 @@ import logger from '/imports/startup/client/logger'; fakeVideoTrack.applyConstraints = function (constraints) { return new Promise( (resolve, reject) => { - // alert("Constraints applied: " + JSON.stringify(constraints)); resolve(); } ); @@ -82,7 +112,9 @@ import logger from '/imports/startup/client/logger'; resolve(stream); } ).catch( - () => alert("Não deu") + (e) => { + logger.error(`Failure calling native initializeScreenShare`, e.message) + } ); }); } @@ -90,12 +122,16 @@ import logger from '/imports/startup/client/logger'; // RTCPeerConnection const prototype = window.RTCPeerConnection.prototype; + prototype.originalCreateOffer = prototype.createOffer; prototype.createOffer = function (options) { - logger.info("BBB-MOBILE - createOffer called", {options}); + if(!isScreenShareBroadcastRelated('createOffer', this)){ + return prototype.originalCreateOffer.call(this, ...arguments); + } + logger.info(`BBB-MOBILE - createOffer called`, {options}); return new Promise( (resolve, reject) => { callNativeMethod('createOffer').then ( sdp => { - logger.info("BBB-MOBILE - createOffer resolved", {sdp}); + logger.info(`BBB-MOBILE - createOffer resolved`, {sdp}); // resolve({ @@ -106,13 +142,18 @@ import logger from '/imports/startup/client/logger'; } ); }; + prototype.originalAddEventListener = prototype.addEventListener; prototype.addEventListener = function (event, callback) { - logger.info("BBB-MOBILE - addEventListener called", {event, callback}); + if(!isScreenShareBroadcastRelated('addEventListener', this, arguments)){ + return prototype.originalAddEventListener.call(this, ...arguments); + } + + logger.info(`BBB-MOBILE - addEventListener called`, {event, callback}); switch(event) { case 'icecandidate': window.bbbMobileScreenShareIceCandidateCallback = function () { - console.log("Received a bbbMobileScreenShareIceCandidateCallback call with arguments", arguments); + logger.info("Received a bbbMobileScreenShareIceCandidateCallback call with arguments", arguments); if(callback){ callback.apply(this, arguments); } @@ -128,8 +169,12 @@ import logger from '/imports/startup/client/logger'; } } + prototype.originalSetLocalDescription = prototype.setLocalDescription; prototype.setLocalDescription = function (description, successCallback, failureCallback) { - logger.info("BBB-MOBILE - setLocalDescription called", {description, successCallback, failureCallback}); + if(!isScreenShareBroadcastRelated('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)); @@ -142,26 +187,41 @@ import logger from '/imports/startup/client/logger'; }) } + prototype.originalSetRemoteDescription = prototype.setRemoteDescription; prototype.setRemoteDescription = function (description, successCallback, failureCallback) { - logger.info("BBB-MOBILE - setRemoteDescription called", {description, successCallback, failureCallback}); + if(!isScreenShareBroadcastRelated('setRemoteDescription', this)){ + 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) {}}); return new Promise( (resolve, reject) => { callNativeMethod('setRemoteDescription', [description]).then ( () => { - logger.info("BBB-MOBILE - setRemoteDescription resolved"); + logger.info(`BBB-MOBILE - setRemoteDescription resolved`); resolve(); }); } ); } + prototype.originalAddTrack = prototype.addTrack; prototype.addTrack = function (description, successCallback, failureCallback) { - logger.info("BBB-MOBILE - addTrack called", {description, successCallback, failureCallback}); + if(!isScreenShareBroadcastRelated('addTrack', this)){ + return prototype.originalAddTrack.call(this, ...arguments); + } + + logger.info(`BBB-MOBILE - addTrack called`, {description, successCallback, failureCallback}); } + prototype.originalGetLocalStreams = prototype.getLocalStreams; prototype.getLocalStreams = function() { - logger.info("BBB-MOBILE - getLocalStreams called", arguments); + if(!isScreenShareBroadcastRelated('getLocalStreams', this)){ + return prototype.originalGetLocalStreams.call(this, ...arguments); + } + logger.info(`BBB-MOBILE - getLocalStreams called`, arguments); // return [ @@ -169,12 +229,20 @@ import logger from '/imports/startup/client/logger'; ]; } + prototype.originalAddTransceiver = prototype.addTransceiver; prototype.addTransceiver = function() { - logger.info("BBB-MOBILE - addTransceiver called", arguments); + if(!isScreenShareBroadcastRelated('addTransceiver', this)){ + return prototype.originalAddTransceiver.call(this, ...arguments); + } + logger.info(`BBB-MOBILE - addTransceiver called`, arguments); } + prototype.originalAddIceCandidate = prototype.addIceCandidate; prototype.addIceCandidate = function (candidate) { - logger.info("BBB-MOBILE - addIceCandidate called", {candidate}); + if(!isScreenShareBroadcastRelated('addIceCandidate', this)){ + return prototype.originalAddIceCandidate.call(this, ...arguments); + } + logger.info(`BBB-MOBILE - addIceCandidate called`, {candidate}); return new Promise( (resolve, reject) => { callNativeMethod('addRemoteIceCandidate', [candidate]).then ( () => { From 2b953a47bb236ed04f71cd933745b957d0bbd487 Mon Sep 17 00:00:00 2001 From: Tiago Jacobs Date: Wed, 20 Apr 2022 13:05:48 -0300 Subject: [PATCH 16/41] Add structure to detect and forward full audio calls to mobile application --- .../imports/ui/services/mobile-app/index.js | 76 +++++++++++++------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js index 2a00d26a39..ecf48718ac 100644 --- a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js +++ b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js @@ -7,34 +7,40 @@ import logger from '/imports/startup/client/logger'; 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 isScreenShareBroadcastRelated(caller, peerConnection = null, args = null) { + function detectWebRtcCallType(caller, peerConnection = null, args = null) { // Keep track of how many webRTC evaluations was done - if(!peerConnection.isSBREvaluations) - peerConnection.isSBREvaluations = 0; + if(!peerConnection.detectWebRtcCallTypeEvaluations) + peerConnection.detectWebRtcCallTypeEvaluations = 0; - peerConnection.isSBREvaluations ++; + peerConnection.detectWebRtcCallTypeEvaluations ++; // If already successfully evaluated, reuse - if(peerConnection && peerConnection.isSBR !== undefined ) { - logger.info(`BBB-MOBILE - isScreenShareBroadcastRelated (already evaluated as ${peerConnection.isSBR})`, {caller, peerConnection}); - return peerConnection.isSBR; + 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 - isScreenShareBroadcastRelated (evaluating)`, {caller, peerConnection, stackTrace: stackTrace.split('\n'), isSBREvaluations: peerConnection.isSBREvaluations, args}); + 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.isSBREvaluations == 1) { + if( peerConnection.detectWebRtcCallTypeEvaluations == 1) { if(caller == 'addTransceiver' && stackTrace.indexOf('startScreensharing') !== -1) { - peerConnection.isSBR = true; + 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.isSBR = false; + peerConnection.webRtcCallType = WEBRTC_CALL_TYPE_STANDARD; // this uses the webview webRTC } - return peerConnection.isSBR; + return peerConnection.webRtcCallType; } } @@ -84,7 +90,7 @@ import logger from '/imports/startup/client/logger'; // WebRTC replacement functions const buildVideoTrack = function () {} const stream = {}; - + // Navigator navigator.getDisplayMedia = function() { logger.info(`BBB-MOBILE - getDisplayMedia called`, arguments); @@ -124,16 +130,20 @@ import logger from '/imports/startup/client/logger'; prototype.originalCreateOffer = prototype.createOffer; prototype.createOffer = function (options) { - if(!isScreenShareBroadcastRelated('createOffer', this)){ + 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('createOffer').then ( sdp => { + callNativeMethod(createOfferMethod).then ( sdp => { logger.info(`BBB-MOBILE - createOffer resolved`, {sdp}); - // + // send offer to BBB code resolve({ type: 'offer', sdp @@ -144,7 +154,7 @@ import logger from '/imports/startup/client/logger'; prototype.originalAddEventListener = prototype.addEventListener; prototype.addEventListener = function (event, callback) { - if(!isScreenShareBroadcastRelated('addEventListener', this, arguments)){ + if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addEventListener', this, arguments)){ return prototype.originalAddEventListener.call(this, ...arguments); } @@ -171,7 +181,7 @@ import logger from '/imports/startup/client/logger'; prototype.originalSetLocalDescription = prototype.setLocalDescription; prototype.setLocalDescription = function (description, successCallback, failureCallback) { - if(!isScreenShareBroadcastRelated('setLocalDescription', this)){ + if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('setLocalDescription', this)){ return prototype.originalSetLocalDescription.call(this, ...arguments); } logger.info(`BBB-MOBILE - setLocalDescription called`, {description, successCallback, failureCallback}); @@ -189,7 +199,8 @@ import logger from '/imports/startup/client/logger'; prototype.originalSetRemoteDescription = prototype.setRemoteDescription; prototype.setRemoteDescription = function (description, successCallback, failureCallback) { - if(!isScreenShareBroadcastRelated('setRemoteDescription', this)){ + const webRtcCallType = detectWebRtcCallType('setRemoteDescription', this); + if(WEBRTC_CALL_TYPE_STANDARD === webRtcCallType){ return prototype.originalSetRemoteDescription.call(this, ...arguments); } @@ -197,28 +208,38 @@ import logger from '/imports/startup/client/logger'; 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('setRemoteDescription', [description]).then ( () => { + 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(!isScreenShareBroadcastRelated('addTrack', this)){ + if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addTrack', this)){ return prototype.originalAddTrack.call(this, ...arguments); } logger.info(`BBB-MOBILE - addTrack called`, {description, successCallback, failureCallback}); + console.log(`BBB-MOBILE - addTrack called`, {description, successCallback, failureCallback}); } prototype.originalGetLocalStreams = prototype.getLocalStreams; prototype.getLocalStreams = function() { - if(!isScreenShareBroadcastRelated('getLocalStreams', this)){ + if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('getLocalStreams', this)){ return prototype.originalGetLocalStreams.call(this, ...arguments); } logger.info(`BBB-MOBILE - getLocalStreams called`, arguments); @@ -231,7 +252,7 @@ import logger from '/imports/startup/client/logger'; prototype.originalAddTransceiver = prototype.addTransceiver; prototype.addTransceiver = function() { - if(!isScreenShareBroadcastRelated('addTransceiver', this)){ + if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addTransceiver', this)){ return prototype.originalAddTransceiver.call(this, ...arguments); } logger.info(`BBB-MOBILE - addTransceiver called`, arguments); @@ -239,7 +260,7 @@ import logger from '/imports/startup/client/logger'; prototype.originalAddIceCandidate = prototype.addIceCandidate; prototype.addIceCandidate = function (candidate) { - if(!isScreenShareBroadcastRelated('addIceCandidate', this)){ + if(WEBRTC_CALL_TYPE_STANDARD === detectWebRtcCallType('addIceCandidate', this)){ return prototype.originalAddIceCandidate.call(this, ...arguments); } logger.info(`BBB-MOBILE - addIceCandidate called`, {candidate}); @@ -253,6 +274,13 @@ import logger from '/imports/startup/client/logger'; } ); } + + // Application events + window.bbbMobileScreenShareBroadcastFinishedCallback = function () { + document.querySelector('[data-test="stopScreenShare"]')?.click(); + } + + } })(); From b13039c31f4af4bffd71c3a4d7d12ceb9859e9af Mon Sep 17 00:00:00 2001 From: Gustavo Emanuel Farias Rosa Date: Thu, 2 Jun 2022 21:03:06 -0300 Subject: [PATCH 17/41] Detect screen share stop and propagate it to the application --- .../imports/ui/services/mobile-app/index.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js index ecf48718ac..bd6fd26795 100644 --- a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js +++ b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js @@ -234,7 +234,6 @@ import logger from '/imports/startup/client/logger'; } logger.info(`BBB-MOBILE - addTrack called`, {description, successCallback, failureCallback}); - console.log(`BBB-MOBILE - addTrack called`, {description, successCallback, failureCallback}); } prototype.originalGetLocalStreams = prototype.getLocalStreams; @@ -274,13 +273,21 @@ import logger from '/imports/startup/client/logger'; } ); } + // 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() + } - // Application events + // Handle screenshare stop requested by application (i.e. stopped the broadcast extension) window.bbbMobileScreenShareBroadcastFinishedCallback = function () { document.querySelector('[data-test="stopScreenShare"]')?.click(); } - } })(); From 438afa7db1692ee57513b9f55b3caddeb57c050c Mon Sep 17 00:00:00 2001 From: KDSBrowne Date: Thu, 30 Jun 2022 16:48:42 +0000 Subject: [PATCH 18/41] fix RTL cursor position --- .../ui/components/whiteboard/component.jsx | 4 ++-- .../whiteboard/cursors/component.jsx | 20 ++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx index 6872d01097..c3738f103e 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx @@ -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} > { @@ -136,15 +138,27 @@ 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 = !nav?.nextSibling?.hasAttribute('role') ? nav?.nextSibling : null; 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); + if (type === 'touchmove') { !active && setActive(true); return setPos({ x: event?.changedTouches[0]?.clientX - xOffset, y: event?.changedTouches[0]?.clientY - yOffset }); } + + if (webcams) { + yOffset += (parseFloat(webcams?.firstChild?.style?.height) + RESIZE_HANDLE_HEIGHT); + } + + if (document?.documentElement?.dir === 'rtl') { + xOffset = 0; + } + return setPos({ x: event.x - xOffset, y: event.y - yOffset }); } From 6c98e4d8547955330f9c9cb622b071f30a06843c Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Fri, 1 Jul 2022 19:28:04 +0200 Subject: [PATCH 19/41] temporarily increase verbosity --- bigbluebutton-config/bin/bbb-conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 84cf1fd511..1151b0d86a 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -x # # BlueButton open source conferencing system - https://www.bigbluebutton.org/ # From 0b0cf2f6bf54d1f74197c4bdd0b70d77e49f335d Mon Sep 17 00:00:00 2001 From: GuiLeme Date: Fri, 1 Jul 2022 12:06:41 -0300 Subject: [PATCH 20/41] [fix-tomcat-warnings] - verified if the Tomcat service has been installed --- bigbluebutton-config/bin/bbb-conf | 44 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 9da0538e44..5883091f86 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -419,15 +419,15 @@ start_bigbluebutton () { if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then TOMCAT_SERVICE=$TOMCAT_USER - 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 $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 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 @@ -1143,17 +1143,29 @@ check_state() { if bbb-conf --status | grep -q inactive; then - 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 "#" - fi - if bbb-conf --status | grep inactive | grep -vq tomcat9; then + if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then + TOMCAT_SERVICE=$TOMCAT_USER + + if bbb-conf --status | grep -q $TOMCAT_SERVICE; then + echo "# Warning: $TOMCAT_SERVICE is not started correctly" + echo "#" + echo "# $(bbb-conf --status | grep inactive | grep $TOMCAT_SERVICE)" + echo "#" + fi + if bbb-conf --status | grep inactive | grep -vq $TOMCAT_SERVICE; then + echo "# Error: Detected some processes have not started correctly" + echo "#" + echo "# $(bbb-conf --status | grep inactive | grep -v $TOMCAT_SERVICE)" + echo "#" + fi + + else + 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 fi From 9e246093f9b2f75f024a4370e770e6963f29fa09 Mon Sep 17 00:00:00 2001 From: Ramon Souza Date: Mon, 4 Jul 2022 10:41:27 -0300 Subject: [PATCH 21/41] remove duplicated webcam label --- .../video-list/video-list-item/component.jsx | 47 ++----------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx index d787c57f07..e6bf27b565 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx @@ -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} /> { onHandleVideoFocus={onHandleVideoFocus} focused={focused} onHandleMirror={() => setIsMirrored((value) => !value)} + isRTL={isRTL} /> { animations={animations} {...makeDragOperations(onVirtualBgDrop, user?.userId)} > - { - videoIsReady - ? ( - <> - - - - - - setIsMirrored((value) => !value)} - isRTL={isRTL} - /> - - - - ) - : ( - - {name} - - ) - } - Date: Mon, 4 Jul 2022 16:19:38 -0300 Subject: [PATCH 22/41] Add support to 2.6 by initializing stream active flag --- bigbluebutton-html5/imports/ui/services/mobile-app/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js index bd6fd26795..9f72ddb07f 100644 --- a/bigbluebutton-html5/imports/ui/services/mobile-app/index.js +++ b/bigbluebutton-html5/imports/ui/services/mobile-app/index.js @@ -108,6 +108,7 @@ import logger from '/imports/startup/client/logger'; }; 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 @@ -115,6 +116,7 @@ import logger from '/imports/startup/client/logger'; stream.getTracks = stream.getVideoTracks = function () { return videoTracks; }; + stream.active=true; resolve(stream); } ).catch( From a467e97dccefe83d395fd0b370b4097e414b6126 Mon Sep 17 00:00:00 2001 From: Paulo Lanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Tue, 5 Jul 2022 09:12:56 -0300 Subject: [PATCH 23/41] build(bbb-webrtc-sfu): v2.9.0-alpha.4 See https://github.com/bigbluebutton/bbb-webrtc-sfu/releases/tag/v2.9.0-alpha.4 --- bbb-webrtc-sfu.placeholder.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbb-webrtc-sfu.placeholder.sh b/bbb-webrtc-sfu.placeholder.sh index 6614c9c6e6..16582b4386 100755 --- a/bbb-webrtc-sfu.placeholder.sh +++ b/bbb-webrtc-sfu.placeholder.sh @@ -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 From 3cdfe2fc3940e6ba790b7d1cecfdf5a70b07bcf9 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Tue, 5 Jul 2022 13:19:08 +0000 Subject: [PATCH 24/41] chore: update meteor 2.7.1 to 2.7.3 --- bigbluebutton-html5/.meteor/packages | 2 +- bigbluebutton-html5/.meteor/release | 2 +- bigbluebutton-html5/.meteor/versions | 20 ++++----- bigbluebutton-html5/package-lock.json | 41 ------------------- .../bbb-html5/after-install.sh | 2 +- build/packages-template/bbb-html5/build.sh | 6 +-- .../bbb-html5/systemd_start.sh | 2 +- .../bbb-html5/systemd_start_frontend.sh | 2 +- 8 files changed, 18 insertions(+), 59 deletions(-) diff --git a/bigbluebutton-html5/.meteor/packages b/bigbluebutton-html5/.meteor/packages index 137d6f4190..e7649fe00f 100644 --- a/bigbluebutton-html5/.meteor/packages +++ b/bigbluebutton-html5/.meteor/packages @@ -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 diff --git a/bigbluebutton-html5/.meteor/release b/bigbluebutton-html5/.meteor/release index 8e3f1708ae..66dd7b6647 100644 --- a/bigbluebutton-html5/.meteor/release +++ b/bigbluebutton-html5/.meteor/release @@ -1 +1 @@ -METEOR@2.7.1 +METEOR@2.7.3 diff --git a/bigbluebutton-html5/.meteor/versions b/bigbluebutton-html5/.meteor/versions index bf1e9659b4..ab0881cd0b 100644 --- a/bigbluebutton-html5/.meteor/versions +++ b/bigbluebutton-html5/.meteor/versions @@ -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 diff --git a/bigbluebutton-html5/package-lock.json b/bigbluebutton-html5/package-lock.json index e6c4a850e8..a283b97d72 100644 --- a/bigbluebutton-html5/package-lock.json +++ b/bigbluebutton-html5/package-lock.json @@ -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", diff --git a/build/packages-template/bbb-html5/after-install.sh b/build/packages-template/bbb-html5/after-install.sh index 733a48ce92..9c3b2513f1 100644 --- a/build/packages-template/bbb-html5/after-install.sh +++ b/build/packages-template/bbb-html5/after-install.sh @@ -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" diff --git a/build/packages-template/bbb-html5/build.sh b/build/packages-template/bbb-html5/build.sh index 4d04818d82..61fc8434fc 100755 --- a/build/packages-template/bbb-html5/build.sh +++ b/build/packages-template/bbb-html5/build.sh @@ -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 diff --git a/build/packages-template/bbb-html5/systemd_start.sh b/build/packages-template/bbb-html5/systemd_start.sh index 05f7a48fbe..0c33ab00df 100644 --- a/build/packages-template/bbb-html5/systemd_start.sh +++ b/build/packages-template/bbb-html5/systemd_start.sh @@ -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 diff --git a/build/packages-template/bbb-html5/systemd_start_frontend.sh b/build/packages-template/bbb-html5/systemd_start_frontend.sh index 651ee51214..b92a07acc8 100644 --- a/build/packages-template/bbb-html5/systemd_start_frontend.sh +++ b/build/packages-template/bbb-html5/systemd_start_frontend.sh @@ -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 From c27749aebe527f69e1b4a6a738cbbf2c373b41cc Mon Sep 17 00:00:00 2001 From: Localization Server Date: Tue, 5 Jul 2022 17:35:49 +0000 Subject: [PATCH 25/41] chore: Pulled the latest 2.6 HTML5 locales from Transifex --- bigbluebutton-html5/public/locales/ar.json | 10 +- bigbluebutton-html5/public/locales/ca.json | 25 ++- bigbluebutton-html5/public/locales/eu.json | 2 +- bigbluebutton-html5/public/locales/he.json | 193 +++++++++++++++++- bigbluebutton-html5/public/locales/hu_HU.json | 2 +- bigbluebutton-html5/public/locales/ja.json | 1 + bigbluebutton-html5/public/locales/pl_PL.json | 12 ++ bigbluebutton-html5/public/locales/tr.json | 1 + bigbluebutton-html5/public/locales/uk_UA.json | 130 +++++++++++- 9 files changed, 365 insertions(+), 11 deletions(-) diff --git a/bigbluebutton-html5/public/locales/ar.json b/bigbluebutton-html5/public/locales/ar.json index 494a8eb4cc..a091308306 100644 --- a/bigbluebutton-html5/public/locales/ar.json +++ b/bigbluebutton-html5/public/locales/ar.json @@ -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": "البوابات", diff --git a/bigbluebutton-html5/public/locales/ca.json b/bigbluebutton-html5/public/locales/ca.json index b4be5a6071..29cf4f8be8 100644 --- a/bigbluebutton-html5/public/locales/ca.json +++ b/bigbluebutton-html5/public/locales/ca.json @@ -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" } diff --git a/bigbluebutton-html5/public/locales/eu.json b/bigbluebutton-html5/public/locales/eu.json index 172fcf515e..fbce14676e 100644 --- a/bigbluebutton-html5/public/locales/eu.json +++ b/bigbluebutton-html5/public/locales/eu.json @@ -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", diff --git a/bigbluebutton-html5/public/locales/he.json b/bigbluebutton-html5/public/locales/he.json index 5745c09a5b..d187f92c32 100644 --- a/bigbluebutton-html5/public/locales/he.json +++ b/bigbluebutton-html5/public/locales/he.json @@ -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": "ציר הזמן" } diff --git a/bigbluebutton-html5/public/locales/hu_HU.json b/bigbluebutton-html5/public/locales/hu_HU.json index fae023f5ab..11d40d1ad8 100644 --- a/bigbluebutton-html5/public/locales/hu_HU.json +++ b/bigbluebutton-html5/public/locales/hu_HU.json @@ -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", diff --git a/bigbluebutton-html5/public/locales/ja.json b/bigbluebutton-html5/public/locales/ja.json index d5355bb4dc..3fb1bf7f79 100644 --- a/bigbluebutton-html5/public/locales/ja.json +++ b/bigbluebutton-html5/public/locales/ja.json @@ -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": "プレゼンファイルがダウンロードできませんでした", diff --git a/bigbluebutton-html5/public/locales/pl_PL.json b/bigbluebutton-html5/public/locales/pl_PL.json index 3cd3094b40..bf081d363c 100644 --- a/bigbluebutton-html5/public/locales/pl_PL.json +++ b/bigbluebutton-html5/public/locales/pl_PL.json @@ -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)", diff --git a/bigbluebutton-html5/public/locales/tr.json b/bigbluebutton-html5/public/locales/tr.json index dbe9a153ba..d03b426601 100644 --- a/bigbluebutton-html5/public/locales/tr.json +++ b/bigbluebutton-html5/public/locales/tr.json @@ -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", diff --git a/bigbluebutton-html5/public/locales/uk_UA.json b/bigbluebutton-html5/public/locales/uk_UA.json index 6ac47c7341..184c80f309 100644 --- a/bigbluebutton-html5/public/locales/uk_UA.json +++ b/bigbluebutton-html5/public/locales/uk_UA.json @@ -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": "Помилка завантаження сторінки - перевірте посилання та з'єднання з мережею" } From 5a8cce66671c9f6abdd5cc5b3aa0f83179a6fabb Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Tue, 5 Jul 2022 17:47:01 +0000 Subject: [PATCH 26/41] chore: rename export-annotations to bbb-export-annotations --- {export-annotations => bbb-export-annotations}/.gitignore | 0 .../config/index.js | 0 .../config/settings.json | 0 .../lib/utils/logger.js | 0 {export-annotations => bbb-export-annotations}/master.js | 2 +- .../package-lock.json | 4 ++-- {export-annotations => bbb-export-annotations}/package.json | 2 +- .../workers/collector.js | 0 .../workers/notifier.js | 0 .../workers/process.js | 0 10 files changed, 4 insertions(+), 4 deletions(-) rename {export-annotations => bbb-export-annotations}/.gitignore (100%) rename {export-annotations => bbb-export-annotations}/config/index.js (100%) rename {export-annotations => bbb-export-annotations}/config/settings.json (100%) rename {export-annotations => bbb-export-annotations}/lib/utils/logger.js (100%) rename {export-annotations => bbb-export-annotations}/master.js (97%) rename {export-annotations => bbb-export-annotations}/package-lock.json (99%) rename {export-annotations => bbb-export-annotations}/package.json (91%) rename {export-annotations => bbb-export-annotations}/workers/collector.js (100%) rename {export-annotations => bbb-export-annotations}/workers/notifier.js (100%) rename {export-annotations => bbb-export-annotations}/workers/process.js (100%) diff --git a/export-annotations/.gitignore b/bbb-export-annotations/.gitignore similarity index 100% rename from export-annotations/.gitignore rename to bbb-export-annotations/.gitignore diff --git a/export-annotations/config/index.js b/bbb-export-annotations/config/index.js similarity index 100% rename from export-annotations/config/index.js rename to bbb-export-annotations/config/index.js diff --git a/export-annotations/config/settings.json b/bbb-export-annotations/config/settings.json similarity index 100% rename from export-annotations/config/settings.json rename to bbb-export-annotations/config/settings.json diff --git a/export-annotations/lib/utils/logger.js b/bbb-export-annotations/lib/utils/logger.js similarity index 100% rename from export-annotations/lib/utils/logger.js rename to bbb-export-annotations/lib/utils/logger.js diff --git a/export-annotations/master.js b/bbb-export-annotations/master.js similarity index 97% rename from export-annotations/master.js rename to bbb-export-annotations/master.js index 95ab75c510..e1437f37e8 100644 --- a/export-annotations/master.js +++ b/bbb-export-annotations/master.js @@ -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) => { diff --git a/export-annotations/package-lock.json b/bbb-export-annotations/package-lock.json similarity index 99% rename from export-annotations/package-lock.json rename to bbb-export-annotations/package-lock.json index b691a41e34..c4d12807d4 100644 --- a/export-annotations/package-lock.json +++ b/bbb-export-annotations/package-lock.json @@ -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", diff --git a/export-annotations/package.json b/bbb-export-annotations/package.json similarity index 91% rename from export-annotations/package.json rename to bbb-export-annotations/package.json index fe1a076eb4..dc2756cbfa 100644 --- a/export-annotations/package.json +++ b/bbb-export-annotations/package.json @@ -1,5 +1,5 @@ { - "name": "export-annotations", + "name": "bbb-export-annotations", "version": "0.0.1", "description": "BigBlueButton's Presentation Annotation Exporter", "scripts": { diff --git a/export-annotations/workers/collector.js b/bbb-export-annotations/workers/collector.js similarity index 100% rename from export-annotations/workers/collector.js rename to bbb-export-annotations/workers/collector.js diff --git a/export-annotations/workers/notifier.js b/bbb-export-annotations/workers/notifier.js similarity index 100% rename from export-annotations/workers/notifier.js rename to bbb-export-annotations/workers/notifier.js diff --git a/export-annotations/workers/process.js b/bbb-export-annotations/workers/process.js similarity index 100% rename from export-annotations/workers/process.js rename to bbb-export-annotations/workers/process.js From ffa2aff4a94f377fc54a42c5c1ad712669e92472 Mon Sep 17 00:00:00 2001 From: GuiLeme Date: Tue, 5 Jul 2022 16:19:07 -0300 Subject: [PATCH 27/41] [fix-tomcat-warnings] - changes in review --- bigbluebutton-config/bin/bbb-conf | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 5883091f86..3262d5ff17 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -1142,30 +1142,20 @@ 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 $TOMCAT_SERVICE; then + if bbb-conf --status | grep -q inactive | grep -q $TOMCAT_SERVICE; then echo "# Warning: $TOMCAT_SERVICE is not started correctly" echo "#" - echo "# $(bbb-conf --status | grep inactive | grep $TOMCAT_SERVICE)" - echo "#" fi - if bbb-conf --status | grep inactive | grep -vq $TOMCAT_SERVICE; then - echo "# Error: Detected some processes have not started correctly" - echo "#" - echo "# $(bbb-conf --status | grep inactive | grep -v $TOMCAT_SERVICE)" - echo "#" - fi - - else - if bbb-conf --status | grep inactive; then + fi + + if bbb-conf --status | grep inactive; then echo "# Error: Detected some processes have not started correctly" echo "#" echo "# $(bbb-conf --status | grep inactive)" echo "#" - fi fi fi From b075cf822b1a78d8b0cf39e11864d63c16edbefc Mon Sep 17 00:00:00 2001 From: KDSBrowne Date: Tue, 5 Jul 2022 20:16:55 +0000 Subject: [PATCH 28/41] fix delay minimizing presentation | display default cursor for no MUA --- .../whiteboard/cursors/component.jsx | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx index a59474f968..b0cdaf3154 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx @@ -181,18 +181,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 ( (cursorWrapper = r)}> -
- {active && ( +
+ {(active && multiUserAccess || (active && currentUser?.presenter)) && ( Date: Wed, 6 Jul 2022 17:17:05 +0000 Subject: [PATCH 29/41] handle cursor position for all custom layout orientations --- .../ui/components/webcam/component.jsx | 2 ++ .../whiteboard/cursors/component.jsx | 36 +++++++++++++++---- .../whiteboard/cursors/container.jsx | 2 ++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/webcam/component.jsx b/bigbluebutton-html5/imports/ui/components/webcam/component.jsx index 22cae7a5a1..ca09d75f4e 100644 --- a/bigbluebutton-html5/imports/ui/components/webcam/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/webcam/component.jsx @@ -122,6 +122,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({ diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx index b0cdaf3154..bc88e63dd0 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx @@ -2,6 +2,8 @@ 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(); @@ -123,6 +125,7 @@ export default function Cursors(props) { isViewersCursorLocked, hasMultiUserAccess, isMultiUserActive, + application, } = props; const start = () => setActive(true); @@ -136,7 +139,7 @@ export default function Cursors(props) { setActive(false); }; - const moved = (event) => { + const moved = (event, sl) => { const { type } = event; const nav = document.getElementById('Navbar'); let yOffset = parseFloat(nav?.style?.height); @@ -145,18 +148,37 @@ export default function Cursors(props) { const webcams = !nav?.nextSibling?.hasAttribute('role') ? nav?.nextSibling : null; const subPanel = panel && getSibling(panel); let xOffset = (parseFloat(panel?.style?.width) || 0) + (parseFloat(subPanel?.style?.width) || 0); + const camPosition = document.getElementById('layout')?.getAttribute('data-cam-position') || null; if (type === 'touchmove') { !active && setActive(true); return setPos({ x: event?.changedTouches[0]?.clientX - xOffset, y: event?.changedTouches[0]?.clientY - yOffset }); } - if (webcams) { - yOffset += (parseFloat(webcams?.firstChild?.style?.height) + RESIZE_HANDLE_HEIGHT); + const handleYOffsets = () => { + if (camPosition === 'contentTop' || !camPosition) { + yOffset += (parseFloat(webcams?.firstChild?.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')) { + handleYOffsets(); + if (camPosition === 'contentRight') { + xOffset += (parseFloat(webcams?.firstChild?.style?.width) + RESIZE_HANDLE_WIDTH); + } + } + } else { + if (webcams && sl?.includes('custom')) { + handleYOffsets(); + if (camPosition === 'contentLeft') { + xOffset += (parseFloat(webcams?.firstChild?.style?.width) + RESIZE_HANDLE_WIDTH); + } + } } return setPos({ x: event.x - xOffset, y: event.y - yOffset }); @@ -173,10 +195,10 @@ export default function Cursors(props) { cursorWrapper?.addEventListener("touchend", end); !cursorWrapper.hasOwnProperty("mousemove") && - cursorWrapper?.addEventListener("mousemove", moved); + cursorWrapper?.addEventListener("mousemove", (event) => moved(event, application?.selectedLayout)); !cursorWrapper.hasOwnProperty("touchmove") && - cursorWrapper?.addEventListener("touchmove", moved); + cursorWrapper?.addEventListener("touchmove", (event) => moved(event, application?.selectedLayout)); }, [cursorWrapper]); React.useEffect(() => { @@ -184,9 +206,9 @@ export default function Cursors(props) { if (cursorWrapper) { cursorWrapper.removeEventListener('mouseenter', start); cursorWrapper.removeEventListener('mouseleave', end); - cursorWrapper.removeEventListener('mousemove', moved); + // cursorWrapper.removeEventListener('mousemove', moved); cursorWrapper.removeEventListener('touchend', end); - cursorWrapper.removeEventListener('touchmove', moved); + // cursorWrapper.removeEventListener('touchmove', moved); } } }); diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/container.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/container.jsx index deb1b6dfc7..6b93250c8c 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/container.jsx @@ -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), From 22bef3b5514e2ac342e32546a26f6947df0b4203 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Wed, 6 Jul 2022 14:41:18 -0400 Subject: [PATCH 30/41] Update build/packages-template/bbb-config/bigbluebutton.target --- build/packages-template/bbb-config/bigbluebutton.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/packages-template/bbb-config/bigbluebutton.target b/build/packages-template/bbb-config/bigbluebutton.target index b24b4b09cd..5aedab477c 100644 --- a/build/packages-template/bbb-config/bigbluebutton.target +++ b/build/packages-template/bbb-config/bigbluebutton.target @@ -1,5 +1,5 @@ [Unit] -Description=Big Blue Button System +Description=BigBlueButton System Requires= After=syslog.target network.target From 3960e8f073a0e2d1edf9f15bb9d603598f24932e Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Wed, 6 Jul 2022 14:41:42 -0400 Subject: [PATCH 31/41] Update bigbluebutton-config/bin/bbb-conf --- bigbluebutton-config/bin/bbb-conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 1151b0d86a..84cf1fd511 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -1,4 +1,4 @@ -#!/bin/bash -x +#!/bin/bash # # BlueButton open source conferencing system - https://www.bigbluebutton.org/ # From 046518abe50483ef08b18c8cadbdbb1239e275d8 Mon Sep 17 00:00:00 2001 From: KDSBrowne Date: Wed, 6 Jul 2022 20:03:04 +0000 Subject: [PATCH 32/41] handle cursor positions for smart layout --- .../layout/layout-manager/layoutEngine.jsx | 7 +++ .../ui/components/webcam/component.jsx | 3 + .../whiteboard/cursors/component.jsx | 56 +++++++++++++++---- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/layout/layout-manager/layoutEngine.jsx b/bigbluebutton-html5/imports/ui/components/layout/layout-manager/layoutEngine.jsx index 71a80efa11..18c84bdf87 100644 --- a/bigbluebutton-html5/imports/ui/components/layout/layout-manager/layoutEngine.jsx +++ b/bigbluebutton-html5/imports/ui/components/layout/layout-manager/layoutEngine.jsx @@ -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 ; case LAYOUT_TYPE.SMART_LAYOUT: + layout?.setAttribute("data-layout", LAYOUT_TYPE.SMART_LAYOUT); return ; case LAYOUT_TYPE.PRESENTATION_FOCUS: + layout?.setAttribute("data-layout", LAYOUT_TYPE.PRESENTATION_FOCUS); return ; case LAYOUT_TYPE.VIDEO_FOCUS: + layout?.setAttribute("data-layout",LAYOUT_TYPE.VIDEO_FOCUS); return ; default: + layout?.setAttribute("data-layout", LAYOUT_TYPE.CUSTOM_LAYOUT); return ; } }; diff --git a/bigbluebutton-html5/imports/ui/components/webcam/component.jsx b/bigbluebutton-html5/imports/ui/components/webcam/component.jsx index ca09d75f4e..8e095208b9 100644 --- a/bigbluebutton-html5/imports/ui/components/webcam/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/webcam/component.jsx @@ -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) => { diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx index bc88e63dd0..5ccdd0cdf6 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/cursors/component.jsx @@ -139,25 +139,26 @@ export default function Cursors(props) { setActive(false); }; - const moved = (event, sl) => { + const moved = (event) => { const { type } = event; const nav = document.getElementById('Navbar'); let yOffset = parseFloat(nav?.style?.height); const getSibling = (el) => el?.previousSibling || null; const panel = getSibling(nav); - const webcams = !nav?.nextSibling?.hasAttribute('role') ? nav?.nextSibling : null; + const webcams = document.getElementById('cameraDock'); const subPanel = panel && getSibling(panel); 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 handleYOffsets = () => { + const handleCustomYOffsets = () => { if (camPosition === 'contentTop' || !camPosition) { - yOffset += (parseFloat(webcams?.firstChild?.style?.height) + RESIZE_HANDLE_HEIGHT); + yOffset += (parseFloat(webcams?.style?.height) + RESIZE_HANDLE_HEIGHT); } if (camPosition === 'contentBottom') { yOffset -= BOTTOM_CAM_HANDLE_HEIGHT; @@ -167,18 +168,49 @@ export default function Cursors(props) { if (document?.documentElement?.dir === 'rtl') { xOffset = 0; if (webcams && sl?.includes('custom')) { - handleYOffsets(); + handleCustomYOffsets(); if (camPosition === 'contentRight') { - xOffset += (parseFloat(webcams?.firstChild?.style?.width) + RESIZE_HANDLE_WIDTH); + 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')) { - handleYOffsets(); + handleCustomYOffsets(); if (camPosition === 'contentLeft') { - xOffset += (parseFloat(webcams?.firstChild?.style?.width) + RESIZE_HANDLE_WIDTH); + 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 }); @@ -195,10 +227,10 @@ export default function Cursors(props) { cursorWrapper?.addEventListener("touchend", end); !cursorWrapper.hasOwnProperty("mousemove") && - cursorWrapper?.addEventListener("mousemove", (event) => moved(event, application?.selectedLayout)); + cursorWrapper?.addEventListener("mousemove", moved); !cursorWrapper.hasOwnProperty("touchmove") && - cursorWrapper?.addEventListener("touchmove", (event) => moved(event, application?.selectedLayout)); + cursorWrapper?.addEventListener("touchmove", moved); }, [cursorWrapper]); React.useEffect(() => { @@ -206,9 +238,9 @@ export default function Cursors(props) { if (cursorWrapper) { cursorWrapper.removeEventListener('mouseenter', start); cursorWrapper.removeEventListener('mouseleave', end); - // cursorWrapper.removeEventListener('mousemove', moved); + cursorWrapper.removeEventListener('mousemove', moved); cursorWrapper.removeEventListener('touchend', end); - // cursorWrapper.removeEventListener('touchmove', moved); + cursorWrapper.removeEventListener('touchmove', moved); } } }); From aa38cca17f104ff069d67145e285f86e486b57cd Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Wed, 6 Jul 2022 20:51:57 +0000 Subject: [PATCH 33/41] build: packaging for bbb-export-annotations --- build/package-names.inc.sh | 1 + .../bbb-export-annotations/after-install.sh | 14 +++++++ .../bbb-export-annotations.service | 16 ++++++++ .../bbb-export-annotations/before-remove.sh | 3 ++ .../bbb-export-annotations/build.sh | 40 +++++++++++++++++++ .../bbb-export-annotations/opts-focal.sh | 3 ++ .../packages-template/bigbluebutton/build.sh | 1 + 7 files changed, 78 insertions(+) create mode 100755 build/packages-template/bbb-export-annotations/after-install.sh create mode 100644 build/packages-template/bbb-export-annotations/bbb-export-annotations.service create mode 100755 build/packages-template/bbb-export-annotations/before-remove.sh create mode 100755 build/packages-template/bbb-export-annotations/build.sh create mode 100644 build/packages-template/bbb-export-annotations/opts-focal.sh diff --git a/build/package-names.inc.sh b/build/package-names.inc.sh index e68d039a0a..09db92a92a 100644 --- a/build/package-names.inc.sh +++ b/build/package-names.inc.sh @@ -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" diff --git a/build/packages-template/bbb-export-annotations/after-install.sh b/build/packages-template/bbb-export-annotations/after-install.sh new file mode 100755 index 0000000000..7d805fbab7 --- /dev/null +++ b/build/packages-template/bbb-export-annotations/after-install.sh @@ -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 diff --git a/build/packages-template/bbb-export-annotations/bbb-export-annotations.service b/build/packages-template/bbb-export-annotations/bbb-export-annotations.service new file mode 100644 index 0000000000..7b5851efc0 --- /dev/null +++ b/build/packages-template/bbb-export-annotations/bbb-export-annotations.service @@ -0,0 +1,16 @@ +[Unit] +Description=BigBlueButton Export Annotations +Wants=redis.service +After=syslog.target network.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 diff --git a/build/packages-template/bbb-export-annotations/before-remove.sh b/build/packages-template/bbb-export-annotations/before-remove.sh new file mode 100755 index 0000000000..468a1671f7 --- /dev/null +++ b/build/packages-template/bbb-export-annotations/before-remove.sh @@ -0,0 +1,3 @@ +#!/bin/bash -e + +stopService bbb-export-annotations || echo "bbb-export-annotations could not be unregistered or stopped" diff --git a/build/packages-template/bbb-export-annotations/build.sh b/build/packages-template/bbb-export-annotations/build.sh new file mode 100755 index 0000000000..8893ebd44c --- /dev/null +++ b/build/packages-template/bbb-export-annotations/build.sh @@ -0,0 +1,40 @@ +#!/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 + +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 + diff --git a/build/packages-template/bbb-export-annotations/opts-focal.sh b/build/packages-template/bbb-export-annotations/opts-focal.sh new file mode 100644 index 0000000000..d51848d8cf --- /dev/null +++ b/build/packages-template/bbb-export-annotations/opts-focal.sh @@ -0,0 +1,3 @@ +. ./opts-global.sh + +OPTS="$OPTS -t deb -d nodejs,npm,bbb-apps-akka,bbb-web" diff --git a/build/packages-template/bigbluebutton/build.sh b/build/packages-template/bigbluebutton/build.sh index 712bf8bd28..7f8b408718 100755 --- a/build/packages-template/bigbluebutton/build.sh +++ b/build/packages-template/bigbluebutton/build.sh @@ -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 From da474130d91ea9a6ab4fb7a7fcf919f60442fafd Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 7 Jul 2022 00:00:35 +0000 Subject: [PATCH 34/41] build: akka apps + fsesl as part of bigbluebutton.target --- .../src/templates/systemloader/systemd/start-template | 4 ++-- .../src/templates/systemloader/systemd/start-template | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/akka-bbb-apps/src/templates/systemloader/systemd/start-template b/akka-bbb-apps/src/templates/systemloader/systemd/start-template index da275d3248..c2db41b7a4 100644 --- a/akka-bbb-apps/src/templates/systemloader/systemd/start-template +++ b/akka-bbb-apps/src/templates/systemloader/systemd/start-template @@ -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 diff --git a/akka-bbb-fsesl/src/templates/systemloader/systemd/start-template b/akka-bbb-fsesl/src/templates/systemloader/systemd/start-template index 7283ac8864..eaa40f7a2c 100644 --- a/akka-bbb-fsesl/src/templates/systemloader/systemd/start-template +++ b/akka-bbb-fsesl/src/templates/systemloader/systemd/start-template @@ -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 From b11e406d8e06d7eb08934d35c1db88bddbdb53f7 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 7 Jul 2022 09:20:19 -0400 Subject: [PATCH 35/41] test: Update automated test command for 2.6 --- .github/workflows/automated-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index c0c5ea585e..4eb4fbf5f2 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -109,8 +109,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 +137,4 @@ jobs: name: tests-report path: | bigbluebutton-tests/playwright/playwright-report - bigbluebutton-tests/playwright/test-results \ No newline at end of file + bigbluebutton-tests/playwright/test-results From a4263b6d6f9633ed6920f047362e168606dfd8c4 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 7 Jul 2022 10:49:31 -0400 Subject: [PATCH 36/41] Reload nginx before bbb-conf --restart --- .github/workflows/automated-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index 4eb4fbf5f2..9275412b21 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -113,6 +113,7 @@ jobs: 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 + systemctl reload nginx bbb-conf --restart ' - name: Install test dependencies From 048bf7d541b69f99955d71dd7886b88586455753 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 7 Jul 2022 17:19:09 +0000 Subject: [PATCH 37/41] fix(conf): reload nginx configuration before BBB start --- .github/workflows/automated-tests.yml | 1 - bigbluebutton-config/bin/bbb-conf | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index 9275412b21..4eb4fbf5f2 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -113,7 +113,6 @@ jobs: 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 - systemctl reload nginx bbb-conf --restart ' - name: Install test dependencies diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 4876cfabfd..e2d8586e0c 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -368,6 +368,9 @@ start_bigbluebutton () { fi fi + echo "Reloading NginX configuration" + systemctl reload nginx + echo "Starting BigBlueButton" if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then @@ -1676,7 +1679,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 From 6cf2d3def7d53fde440a06aaf14eacfc1e572df1 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 7 Jul 2022 17:40:04 +0000 Subject: [PATCH 38/41] build: add export annotations to bbb target --- bigbluebutton-config/bin/bbb-conf | 4 ++++ .../bbb-export-annotations/bbb-export-annotations.service | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 4876cfabfd..915b83da2b 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -445,6 +445,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 diff --git a/build/packages-template/bbb-export-annotations/bbb-export-annotations.service b/build/packages-template/bbb-export-annotations/bbb-export-annotations.service index 7b5851efc0..48ca735d98 100644 --- a/build/packages-template/bbb-export-annotations/bbb-export-annotations.service +++ b/build/packages-template/bbb-export-annotations/bbb-export-annotations.service @@ -2,6 +2,7 @@ Description=BigBlueButton Export Annotations Wants=redis.service After=syslog.target network.target +PartOf=bigbluebutton.target [Service] WorkingDirectory=/usr/local/bigbluebutton/bbb-export-annotations @@ -13,4 +14,4 @@ Group=bigbluebutton Environment=NODE_ENV=production [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target bigbluebutton.target From 3978b7d9a200307a1e613e67cac2c191ec55f056 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 7 Jul 2022 22:00:47 +0000 Subject: [PATCH 39/41] add bbb-export-annotations to be built by ci --- .github/workflows/automated-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index 4eb4fbf5f2..e8f9dcf644 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -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 From 37a1807549e5c4878eb2480fc6b5df9766759828 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Fri, 8 Jul 2022 01:13:59 -0400 Subject: [PATCH 40/41] build: bbb-export-annotations packaging part2 --- build/packages-template/bbb-export-annotations/.build-files | 6 ++++++ build/packages-template/bbb-export-annotations/build.sh | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 build/packages-template/bbb-export-annotations/.build-files diff --git a/build/packages-template/bbb-export-annotations/.build-files b/build/packages-template/bbb-export-annotations/.build-files new file mode 100644 index 0000000000..c4f2a679d8 --- /dev/null +++ b/build/packages-template/bbb-export-annotations/.build-files @@ -0,0 +1,6 @@ +after-install.sh +bbb-export-annotations.service +before-remove.sh +build.sh +opts-focal.sh +opts-global.sh diff --git a/build/packages-template/bbb-export-annotations/build.sh b/build/packages-template/bbb-export-annotations/build.sh index 8893ebd44c..2107c815aa 100755 --- a/build/packages-template/bbb-export-annotations/build.sh +++ b/build/packages-template/bbb-export-annotations/build.sh @@ -16,6 +16,8 @@ rm -rf staging 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 From 7642fd67fe20a4b5e3282948535f26936af6df49 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Fri, 8 Jul 2022 01:19:53 -0400 Subject: [PATCH 41/41] build: set bbb-export-presentations as a required package --- build/packages-template/bbb-html5/opts-focal.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/packages-template/bbb-html5/opts-focal.sh b/build/packages-template/bbb-html5/opts-focal.sh index 1c434e0f83..7e1e748780 100644 --- a/build/packages-template/bbb-html5/opts-focal.sh +++ b/build/packages-template/bbb-html5/opts-focal.sh @@ -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"