From 1b8f33b9c33e96141052fde756926498be3a0ea2 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 20 Sep 2024 08:01:26 +0200 Subject: [PATCH 001/119] [mirotalksfu] - update dep --- README.md | 4 ++-- app/src/Server.js | 2 +- package.json | 14 +++++++------- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 73952dcb..40556b6d 100644 --- a/README.md +++ b/README.md @@ -312,9 +312,9 @@ To set up your own instance of `MiroTalk SFU` on a dedicated cloud server, pleas
-[![DigitalOcean Referral Badge](https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg)](https://www.digitalocean.com/?refcode=1070207afbb1&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge) +[![DigitalOcean Referral Badge](https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg)](https://m.do.co/c/1070207afbb1) -For personal use, you can start with a single $5 a month cloud server and scale up as needed. You can use [this link](https://m.do.co/c/1070207afbb1) to get a `$100 credit for the first 60 days`. +For personal use, you can start with a single $5 a month cloud server and scale up as needed. You can use [this link](https://m.do.co/c/1070207afbb1) to get a `$200 credit for the first 60 days`. diff --git a/app/src/Server.js b/app/src/Server.js index 68667349..870863e1 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.67 + * @version 1.5.68 * */ diff --git a/package.json b/package.json index dffbee64..b6fb11c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.67", + "version": "1.5.68", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,15 +57,15 @@ "node": ">=18" }, "dependencies": { - "@sentry/node": "^8.28.0", + "@sentry/node": "^8.30.0", "axios": "^1.7.7", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "colors": "1.4.0", "compression": "1.7.4", "cors": "2.8.5", "crypto-js": "4.2.0", "dompurify": "^3.1.6", - "express": "4.19.2", + "express": "4.21.0", "express-openid-connect": "^2.17.1", "fluent-ffmpeg": "^2.1.3", "he": "^1.2.0", @@ -77,7 +77,7 @@ "mediasoup-client": "3.7.16", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.58.1", + "openai": "^4.62.1", "qs": "6.13.0", "socket.io": "4.7.5", "swagger-ui-express": "5.0.1", @@ -86,10 +86,10 @@ "devDependencies": { "mocha": "^10.7.3", "node-fetch": "^3.3.2", - "nodemon": "^3.1.4", + "nodemon": "^3.1.6", "prettier": "3.3.3", "proxyquire": "^2.1.3", "should": "^13.2.3", - "sinon": "^18.0.0" + "sinon": "^19.0.2" } } diff --git a/public/js/Room.js b/public/js/Room.js index e5190a03..4280d2e0 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.67 + * @version 1.5.68 * */ @@ -4455,7 +4455,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.67', + title: 'WebRTC SFU v1.5.68', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index d0860cd9..bf1df92c 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.67 + * @version 1.5.68 * */ From 75edb3500df5397d65da38e3fb5bcaeb1d6da442 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 21 Sep 2024 09:17:43 +0200 Subject: [PATCH 002/119] [mirotalksfu] - improve chat UI --- app/src/Server.js | 2 +- package.json | 2 +- public/css/GroupChat.css | 7 +++++++ public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 870863e1..c7c8e54b 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.68 + * @version 1.5.69 * */ diff --git a/package.json b/package.json index b6fb11c5..711615ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.68", + "version": "1.5.69", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/css/GroupChat.css b/public/css/GroupChat.css index f075a5d0..8299f54e 100644 --- a/public/css/GroupChat.css +++ b/public/css/GroupChat.css @@ -373,3 +373,10 @@ input[type='text'] { background: var(--select-bg); transform: translateY(-3px); } + +/* handle screen sizes */ +@media screen and (max-width: 600px) { + .people-list { + width: 100% !important; + } +} diff --git a/public/js/Room.js b/public/js/Room.js index 4280d2e0..5904eb82 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.68 + * @version 1.5.69 * */ @@ -4455,7 +4455,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.68', + title: 'WebRTC SFU v1.5.69', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index bf1df92c..ab2defa9 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.68 + * @version 1.5.69 * */ From 5b38ce64115d9c7b7dd3c5916457fb65d051679c Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sun, 22 Sep 2024 17:22:05 +0200 Subject: [PATCH 003/119] [mirotalksfu] - update dep --- app/src/Server.js | 2 +- package.json | 10 +++++----- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index c7c8e54b..351d92ea 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.69 + * @version 1.5.70 * */ diff --git a/package.json b/package.json index 711615ab..fb729c37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.69", + "version": "1.5.70", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -71,22 +71,22 @@ "he": "^1.2.0", "httpolyglot": "0.1.2", "js-yaml": "^4.1.0", - "jsdom": "^25.0.0", + "jsdom": "^25.0.1", "jsonwebtoken": "^9.0.2", "mediasoup": "3.14.14", "mediasoup-client": "3.7.16", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.62.1", + "openai": "^4.63.0", "qs": "6.13.0", - "socket.io": "4.7.5", + "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", "uuid": "10.0.0" }, "devDependencies": { "mocha": "^10.7.3", "node-fetch": "^3.3.2", - "nodemon": "^3.1.6", + "nodemon": "^3.1.7", "prettier": "3.3.3", "proxyquire": "^2.1.3", "should": "^13.2.3", diff --git a/public/js/Room.js b/public/js/Room.js index 5904eb82..f178527f 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.69 + * @version 1.5.70 * */ @@ -4455,7 +4455,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.69', + title: 'WebRTC SFU v1.5.70', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index ab2defa9..2bf1dfe2 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.69 + * @version 1.5.70 * */ From 876232326ae553ed52754b86dfa2a5cb876dca65 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Tue, 24 Sep 2024 15:01:38 +0200 Subject: [PATCH 004/119] [mirotalksfu] - update dep, test restartIce --- app/src/Server.js | 2 +- package.json | 4 ++-- public/js/Room.js | 11 ++++++----- public/js/RoomClient.js | 4 +++- public/views/Room.html | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 351d92ea..e227a013 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.70 + * @version 1.5.71 * */ diff --git a/package.json b/package.json index fb729c37..70e301ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.70", + "version": "1.5.71", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,7 +57,7 @@ "node": ">=18" }, "dependencies": { - "@sentry/node": "^8.30.0", + "@sentry/node": "^8.31.0", "axios": "^1.7.7", "body-parser": "1.20.3", "colors": "1.4.0", diff --git a/public/js/Room.js b/public/js/Room.js index f178527f..c7c95dc8 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.70 + * @version 1.5.71 * */ @@ -1403,6 +1403,7 @@ function roomIsReady() { if (room_password) { lockRoomButton.click(); } + //show(restartICEButton); // TEST } function elemDisplay(element, display, mode = 'block') { @@ -1961,9 +1962,9 @@ function handleButtons() { aboutButton.onclick = () => { showAbout(); }; - // restartICE.onclick = async () => { - // await rc.restartIce(); - // }; + restartICEButton.onclick = async () => { + await rc.restartIce(); + }; } // #################################################### @@ -4455,7 +4456,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.70', + title: 'WebRTC SFU v1.5.71', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 2bf1dfe2..a1eedc3f 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.70 + * @version 1.5.71 * */ @@ -658,6 +658,8 @@ class RoomClient { return; } + producerTransportData['proprietaryConstraints'] = { optional: [{ googDscp: true }] }; + this.producerTransport = device.createSendTransport(producerTransportData); console.info('07.4 producerTransportData ---->', { diff --git a/public/views/Room.html b/public/views/Room.html index a1d3c3f4..891a7e27 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -189,8 +189,8 @@

Loading

+ -
From b554710ecc1b9d80aaa0947bc7606ae16b278624 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 25 Sep 2024 09:45:49 +0200 Subject: [PATCH 005/119] [mirotalksfu] - fix transport --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 21 +++++++++++---------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index e227a013..2445b4cf 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.71 + * @version 1.5.72 * */ diff --git a/package.json b/package.json index 70e301ad..242060d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.71", + "version": "1.5.72", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index c7c95dc8..ef476634 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.71 + * @version 1.5.72 * */ @@ -4456,7 +4456,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.71', + title: 'WebRTC SFU v1.5.72', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a1eedc3f..e5049c0e 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.71 + * @version 1.5.72 * */ @@ -793,19 +793,19 @@ class RoomClient { break; case 'disconnected': console.log('Consumer Transport disconnected', { id: this.consumerTransport.id }); - /* + this.restartIce(); popupHtmlMessage( null, image.network, 'Consumer Transport disconnected', - 'Check Your Network Connectivity (Restarted ICE)', + 'Network connection may have dropped or changed (Restarted ICE)', 'center', false, - true + false, ); - */ + break; case 'failed': console.warn('Consumer Transport failed', { id: this.consumerTransport.id }); @@ -1418,12 +1418,12 @@ class RoomClient { } producer.on('trackended', () => { - console.log('Producer track ended', { id: producer.id }); + console.log('Producer track ended', { id: producer.id, type }); this.closeProducer(type); }); producer.on('transportclose', () => { - console.log('Producer transport close', { id: producer.id }); + console.log('Producer transport close', { id: producer.id, type }); if (!audio) { const d = this.getId(producer.id + '__video'); elem.srcObject.getTracks().forEach(function (track) { @@ -1445,7 +1445,7 @@ class RoomClient { }); producer.on('close', () => { - console.log('Closing producer', { id: producer.id }); + console.log('Closing producer', { id: producer.id, type }); if (!audio) { const d = this.getId(producer.id + '__video'); elem.srcObject.getTracks().forEach(function (track) { @@ -2207,12 +2207,12 @@ class RoomClient { } consumer.on('trackended', () => { - console.log('Consumer track end', { id: consumer.id }); + console.log('Consumer track end', { id: consumer.id, type }); this.removeConsumer(consumer.id, consumer.kind); }); consumer.on('transportclose', () => { - console.log('Consumer transport close', { id: consumer.id }); + console.log('Consumer transport close', { id: consumer.id, type }); this.removeConsumer(consumer.id, consumer.kind); }); @@ -2517,6 +2517,7 @@ class RoomClient { } } + this.consumers.get(consumer_id).close(); this.consumers.delete(consumer_id); this.sound('left'); } From 209c6d984a2f41c99f766f697755b5d8aa852594 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 25 Sep 2024 14:19:55 +0200 Subject: [PATCH 006/119] [mirotalksfu] - move full screen button --- app/src/Server.js | 2 +- package.json | 4 ++-- public/js/Room.js | 8 +++++--- public/js/RoomClient.js | 38 ++++++++++++++++++++++++++++++++++++-- public/views/Room.html | 6 +----- 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 2445b4cf..19f9e23c 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.72 + * @version 1.5.73 * */ diff --git a/package.json b/package.json index 242060d0..da164222 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.72", + "version": "1.5.73", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,7 +57,7 @@ "node": ">=18" }, "dependencies": { - "@sentry/node": "^8.31.0", + "@sentry/node": "^8.32.0", "axios": "^1.7.7", "body-parser": "1.20.3", "colors": "1.4.0", diff --git a/public/js/Room.js b/public/js/Room.js index ef476634..2f4cb5c6 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.72 + * @version 1.5.73 * */ @@ -383,6 +383,7 @@ function refreshMainButtonsToolTipPlacement() { setTippy('shareButton', 'Share room', placement); setTippy('startRecButton', 'Start recording', placement); setTippy('stopRecButton', 'Stop recording', placement); + setTippy('fullScreenButton', 'Toggle full screen', placement); setTippy('emojiRoomButton', 'Toggle emoji reaction', placement); setTippy('chatButton', 'Toggle the chat', placement); setTippy('pollButton', 'Toggle the poll', placement); @@ -391,6 +392,7 @@ function refreshMainButtonsToolTipPlacement() { setTippy('whiteboardButton', 'Toggle the whiteboard', placement); setTippy('snapshotRoomButton', 'Snapshot screen, window, or tab', placement); setTippy('settingsButton', 'Toggle the settings', placement); + setTippy('restartICEButton', 'Restart ICE', placement); setTippy('aboutButton', 'About this project', placement); // Bottom buttons @@ -1758,7 +1760,7 @@ function handleButtons() { transcription.stop(); }; fullScreenButton.onclick = () => { - rc.toggleFullScreen(); + rc.toggleRoomFullScreen(); }; recordingImage.onclick = () => { isRecording ? stopRecButton.click() : startRecButton.click(); @@ -4456,7 +4458,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.72', + title: 'WebRTC SFU v1.5.73', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index e5049c0e..6bec50b1 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.72 + * @version 1.5.73 * */ @@ -29,6 +29,8 @@ const html = { userHand: 'fas fa-hand-paper pulsate', pip: 'fas fa-images', fullScreen: 'fas fa-expand', + fullScreenOn: 'fas fa-compress-alt', + fullScreenOff: 'fas fa-expand-alt', snapshot: 'fas fa-camera-retro', sendFile: 'fas fa-upload', sendMsg: 'fas fa-paper-plane', @@ -255,6 +257,7 @@ class RoomClient { this.isMySettingsOpen = false; this._isConnected = false; + this.isDocumentOnFullScreen = false; this.isVideoOnFullScreen = false; this.isVideoFullScreenSupported = this.isFullScreenSupported(); this.isVideoPictureInPictureSupported = document.pictureInPictureEnabled; @@ -3271,15 +3274,46 @@ class RoomClient { // #################################################### isFullScreenSupported() { - return ( + const fsSupported = ( document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled ); + if (fsSupported){ + this.handleFullScreenEvents() + } + return fsSupported; + } + + handleFullScreenEvents(){ + document.addEventListener('fullscreenchange', (e) => { + const fullscreenElement = document.fullscreenElement; + if (!fullscreenElement) { + const fullScreenIcon = this.getId('fullScreenIcon'); + fullScreenIcon.className = html.fullScreenOff; + this.isDocumentOnFullScreen = false; + } + }); + } + + toggleRoomFullScreen() { + const fullScreenIcon = this.getId('fullScreenIcon'); + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen(); + fullScreenIcon.className = html.fullScreenOn; + this.isDocumentOnFullScreen = true; + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + fullScreenIcon.className = html.fullScreenOff; + this.isDocumentOnFullScreen = false; + } + } } toggleFullScreen(elem = null) { + if (this.isDocumentOnFullScreen) return; const element = elem ? elem : document.documentElement; const fullScreen = this.isFullScreen(); fullScreen ? this.goOutFullscreen(element) : this.goInFullscreen(element); diff --git a/public/views/Room.html b/public/views/Room.html index 891a7e27..c344f0b6 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -181,6 +181,7 @@

Loading

+ @@ -260,11 +261,6 @@

Loading

- -
+ @@ -378,15 +379,6 @@

Loading

Video Source:

-
-
- -

Toggle mirror

-
- -
-
-

From c3804ce48b157c7a15edc3b3936b81f5214b26c8 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 30 Sep 2024 20:49:31 +0200 Subject: [PATCH 011/119] [mirotalksfu] - fix mirror --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 6 +----- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 3ab8bac5..19f70b5c 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.75 + * @version 1.5.76 * */ diff --git a/package.json b/package.json index 4e8d52df..2fa66e9e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.75", + "version": "1.5.76", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index b3d37436..1db241be 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.75 + * @version 1.5.76 * */ @@ -4463,7 +4463,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.75', + title: 'WebRTC SFU v1.5.76', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a0f7d295..87498af3 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.75 + * @version 1.5.76 * */ @@ -1407,10 +1407,6 @@ class RoomClient { if (type == mediaType.video) this.videoProducerId = producer.id; if (type == mediaType.screen) this.screenProducerId = producer.id; elem = await this.handleProducer(producer.id, type, stream); - // No mirror effect for producer - if (!isInitVideoMirror && elem.classList.contains('mirror')) { - elem.classList.toggle('mirror'); - } //if (!screen && !isEnumerateDevices) enumerateVideoDevices(stream); } else { this.localAudioStream = stream; From 2697cbf657cf2f5fcff4af4c1a578881f6b49950 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 30 Sep 2024 21:14:20 +0200 Subject: [PATCH 012/119] [mirotalksfu] - ops --- public/js/Room.js | 2 +- public/js/RoomClient.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/Room.js b/public/js/Room.js index 1db241be..0e295036 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -213,7 +213,7 @@ let isEnumerateVideoDevices = false; let isAudioAllowed = false; let isVideoAllowed = false; let isVideoPrivacyActive = false; -let isInitVideoMirror = false; +let isInitVideoMirror = true; let isRecording = false; let isAudioVideoAllowed = false; let isParticipantsListOpen = false; diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 87498af3..9fdecfbd 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -1407,6 +1407,10 @@ class RoomClient { if (type == mediaType.video) this.videoProducerId = producer.id; if (type == mediaType.screen) this.screenProducerId = producer.id; elem = await this.handleProducer(producer.id, type, stream); + // No mirror effect for producer + if (!isInitVideoMirror && elem.classList.contains('mirror')) { + elem.classList.remove('mirror'); + } //if (!screen && !isEnumerateDevices) enumerateVideoDevices(stream); } else { this.localAudioStream = stream; From 48187a7dfc643456ac10cee7c248922e9c525d24 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Tue, 1 Oct 2024 21:44:48 +0200 Subject: [PATCH 013/119] [mirotalksfu] - add username emoji, update dep --- app/src/Server.js | 2 +- package.json | 6 +- public/css/Room.css | 11 ++++ public/js/Room.js | 29 ++++++++- public/js/RoomClient.js | 2 +- public/sfu/MediasoupClient.js | 117 +++++++++++++++++++++------------- public/views/Room.html | 2 + 7 files changed, 116 insertions(+), 53 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 19f70b5c..5ec6b024 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.76 + * @version 1.5.77 * */ diff --git a/package.json b/package.json index 2fa66e9e..d81b37a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.76", + "version": "1.5.77", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -74,10 +74,10 @@ "jsdom": "^25.0.1", "jsonwebtoken": "^9.0.2", "mediasoup": "3.14.14", - "mediasoup-client": "3.7.16", + "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.65.0", + "openai": "^4.67.0", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/css/Room.css b/public/css/Room.css index 21541c14..77a01101 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -926,6 +926,17 @@ th { # Room/user emoji picker --------------------------------------------------------------*/ +#usernameEmoji { + position: absolute; + z-index: 9999; + border-radius: 10px; + border: var(--border); + background: var(--body-bg); + box-shadow: var(--box-shadow); + --rgb-background: var(--body-bg); + --color-border-over: var(--body-bg); +} + .roomEmoji { z-index: 9; position: absolute; diff --git a/public/js/Room.js b/public/js/Room.js index 0e295036..a24cffc5 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.76 + * @version 1.5.77 * */ @@ -471,6 +471,7 @@ async function initRoom() { } else { setButtonsInit(); handleSelectsInit(); + handleUsernameEmojiPicker(); await whoAreYou(); await setSelectsInit(); } @@ -663,6 +664,9 @@ function setupInitButtons() { initVideo.classList.toggle('mirror'); isInitVideoMirror = initVideo.classList.contains('mirror'); }; + initUsernameEmojiButton.onclick = () => { + toggleUsernameEmoji(); + }; } // #################################################### @@ -992,7 +996,7 @@ async function whoAreYou() { title: BRAND.app.name, input: 'text', inputPlaceholder: 'Enter your email or name', - inputAttributes: { maxlength: 32 }, + inputAttributes: { maxlength: 32, id: 'usernameInput' }, inputValue: default_name, html: initUser, // Inject HTML confirmButtonText: `Join meeting`, @@ -1990,6 +1994,7 @@ function setButtonsInit() { setTippy('initStartScreenButton', 'Toggle screen sharing', 'top'); setTippy('initStopScreenButton', 'Toggle screen sharing', 'top'); setTippy('initVideoMirrorButton', 'Toggle video mirror', 'top'); + setTippy('initUsernameEmojiButton', 'Toggle username emoji', 'top'); } if (!isAudioAllowed) hide(initAudioButton); if (!isVideoAllowed) hide(initVideoButton); @@ -2675,6 +2680,24 @@ function handleInputs() { // EMOJI PIKER // #################################################### +function toggleUsernameEmoji() { + getId('usernameEmoji').classList.toggle('hidden'); +} + +function handleUsernameEmojiPicker() { + const pickerOptions = { + theme: 'dark', + onEmojiSelect: addEmojiToUsername, + }; + const emojiUsernamePicker = new EmojiMart.Picker(pickerOptions); + getId('usernameEmoji').appendChild(emojiUsernamePicker); + + function addEmojiToUsername(data) { + getId('usernameInput').value += data.native; + toggleUsernameEmoji(); + } +} + function handleChatEmojiPicker() { const pickerOptions = { theme: 'dark', @@ -4463,7 +4486,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.76', + title: 'WebRTC SFU v1.5.77', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 9fdecfbd..7de46670 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.76 + * @version 1.5.77 * */ diff --git a/public/sfu/MediasoupClient.js b/public/sfu/MediasoupClient.js index 0a33119e..73ea0c9b 100644 --- a/public/sfu/MediasoupClient.js +++ b/public/sfu/MediasoupClient.js @@ -1968,11 +1968,11 @@ const ReactNativeUnifiedPlan_1 = require('./handlers/ReactNativeUnifiedPlan'); const ReactNative_1 = require('./handlers/ReactNative'); const logger = new Logger_1.Logger('Device'); - function detectDevice() { + function detectDevice(userAgent) { // React-Native. // NOTE: react-native-webrtc >= 1.75.0 is required. // NOTE: react-native-webrtc with Unified Plan requires version >= 106.0.0. - if (typeof navigator === 'object' && navigator.product === 'ReactNative') { + if (!userAgent && typeof navigator === 'object' && navigator.product === 'ReactNative') { logger.debug('detectDevice() | React-Native detected'); if (typeof RTCPeerConnection === 'undefined') { logger.warn( @@ -1989,10 +1989,14 @@ } } // Browser. - else if (typeof navigator === 'object' && typeof navigator.userAgent === 'string') { - const ua = navigator.userAgent; - const uaParser = new ua_parser_js_1.UAParser(ua); - logger.debug('detectDevice() | browser detected [ua:%s, parsed:%o]', ua, uaParser.getResult()); + else if (userAgent || (typeof navigator === 'object' && typeof navigator.userAgent === 'string')) { + userAgent ?? (userAgent = navigator.userAgent); + const uaParser = new ua_parser_js_1.UAParser(userAgent); + logger.debug( + 'detectDevice() | browser detected [userAgent:%s, parsed:%o]', + userAgent, + uaParser.getResult(), + ); const browser = uaParser.getBrowser(); const browserName = browser.name?.toLowerCase(); const browserVersion = parseInt(browser.major ?? '0'); @@ -2067,7 +2071,7 @@ // Best effort for Chromium based browsers. else if (engineName === 'blink') { // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec - const match = ua.match(/(?:(?:Chrome|Chromium))[ /](\w+)/i); + const match = userAgent.match(/(?:(?:Chrome|Chromium))[ /](\w+)/i); if (match) { const version = Number(match[1]); if (version >= 111) { @@ -2107,25 +2111,12 @@ * * @throws {UnsupportedError} if device is not supported. */ - constructor({ handlerName, handlerFactory, Handler } = {}) { + constructor({ handlerName, handlerFactory } = {}) { // Loaded flag. this._loaded = false; // Observer instance. this._observer = new enhancedEvents_1.EnhancedEventEmitter(); logger.debug('constructor()'); - // Handle deprecated option. - if (Handler) { - logger.warn( - 'constructor() | Handler option is DEPRECATED, use handlerName or handlerFactory instead', - ); - if (typeof Handler === 'string') { - handlerName = Handler; - } else { - throw new TypeError( - 'non string Handler option no longer supported, use handlerFactory instead', - ); - } - } if (handlerName && handlerFactory) { throw new TypeError('just one of handlerName or handlerInterface can be given'); } @@ -13912,7 +13903,7 @@ /** * Expose mediasoup-client version. */ - exports.version = '3.7.16'; + exports.version = '3.7.17'; /** * Expose parseScalabilityMode() function. */ @@ -16445,7 +16436,7 @@ 50: [ function (require, module, exports) { ///////////////////////////////////////////////////////////////////////////////// - /* UAParser.js v1.0.38 + /* UAParser.js v1.0.39 Copyright © 2012-2021 Faisal Salman MIT License */ /* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. @@ -16461,7 +16452,7 @@ // Constants ///////////// - var LIBVERSION = '1.0.38', + var LIBVERSION = '1.0.39', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', @@ -16504,7 +16495,8 @@ ZEBRA = 'Zebra', FACEBOOK = 'Facebook', CHROMIUM_OS = 'Chromium OS', - MAC_OS = 'Mac OS'; + MAC_OS = 'Mac OS', + SUFFIX_BROWSER = ' Browser'; /////////// // Helper @@ -16622,7 +16614,7 @@ return i === UNKNOWN ? undefined : i; } } - return str; + return map.hasOwnProperty('*') ? map['*'] : str; }; /////////////// @@ -16694,18 +16686,23 @@ [VERSION, [NAME, 'Baidu']], [ /(kindle)\/([\w\.]+)/i, // Kindle - /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer + /(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i, + // Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir // Trident based /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon - /(flock|rockmelt|midori|epiphany|silk|skyfire|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i, - // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ - /(heytap|ovi)browser\/([\d\.]+)/i, // Heytap/Ovi + /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio)\/([-\w\.]+)/i, + // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio + /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi /(weibo)__([\d\.]+)/i, // Weibo ], [NAME, VERSION], + [ + /quark(?:pc)?\/([-\w\.]+)/i, // Quark + ], + [VERSION, [NAME, 'Quark']], [ /\bddg\/([\w\.]+)/i, // DuckDuckGo ], @@ -16771,11 +16768,15 @@ [ /\bqihu|(qi?ho?o?|360)browser/i, // 360 ], - [[NAME, '360 ' + BROWSER]], - [/(oculus|sailfish|huawei|vivo)browser\/([\w\.]+)/i], - [[NAME, /(.+)/, '$1 ' + BROWSER], VERSION], + [[NAME, '360' + SUFFIX_BROWSER]], [ - // Oculus/Sailfish/HuaweiBrowser/VivoBrowser + /\b(qq)\/([\w\.]+)/i, // QQ + ], + [[NAME, /(.+)/, '$1Browser'], VERSION], + [/(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i], + [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], + [ + // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser /samsungbrowser\/([\w\.]+)/i, // Samsung Internet ], [VERSION, [NAME, SAMSUNG + ' Internet']], @@ -16798,7 +16799,7 @@ ], [NAME, VERSION], [ - /(lbbrowser)/i, // LieBao Browser + /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq /\[(linkedin)app\]/i, // LinkedIn App for iOS & Android ], [NAME], @@ -16861,6 +16862,10 @@ /(navigator|netscape\d?)\/([-\w\.]+)/i, // Netscape ], [[NAME, 'Netscape'], VERSION], + [ + /(wolvic)\/([\w\.]+)/i, // Wolvic + ], + [NAME, VERSION], [ /mobile vr; rv:([\w\.]+)\).+firefox/i, // Firefox Reality ], @@ -16868,20 +16873,19 @@ [ /ekiohf.+(flow)\/([\w\.]+)/i, // Flow /(swiftfox)/i, // Swiftfox - /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, - // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar + /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i, + // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix /(firefox)\/([\w\.]+)/i, // Other Firefox-based /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla // Other - /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, - // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser + /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, + // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser /(links) \(([\w\.]+)/i, // Links - /panasonic;(viera)/i, // Panasonic Viera ], - [NAME, VERSION], + [NAME, [VERSION, /_/g, '.']], [ /(cobalt)\/([\w\.]+)/i, // Cobalt ], @@ -16940,8 +16944,8 @@ ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [ - /\b((?:s[cgp]h|gt|sm)-\w+|sc[g-]?[\d]+a?|galaxy nexus)/i, - /samsung[- ]([-\w]+)/i, + /\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i, + /samsung[- ]((?!sm-[lr])[-\w]+)/i, /sec-(sgh\w+)/i, ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], @@ -16980,7 +16984,7 @@ /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models - /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i, // Xiaomi Mi + /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite|pro)?)(?: bui|\))/i, // Xiaomi Mi ], [ [MODEL, /_/g, ' '], @@ -17080,7 +17084,7 @@ [ // Amazon /(alexa)webm/i, - /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i, // Kindle Fire without Silk / Echo Show + /(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show /(kf[a-z]+)( bui|\)).+silk\//i, // Kindle Fire HD ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], @@ -17122,6 +17126,20 @@ /(alcatel|geeksphone|nexian|panasonic(?!(?:;|\.))|sony(?!-bra))[-_ ]?([-\w]*)/i, // Alcatel/GeeksPhone/Nexian/Panasonic/Sony ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], + [ + // TCL + /droid [\w\.]+; ((?:8[14]9[16]|9(?:0(?:48|60|8[01])|1(?:3[27]|66)|2(?:6[69]|9[56])|466))[gqswx])\w*(\)| bui)/i, + ], + [MODEL, [VENDOR, 'TCL'], [TYPE, TABLET]], + [ + // itel + /(itel) ((\w+))/i, + ], + [ + [VENDOR, lowerize], + MODEL, + [TYPE, strMapper, { tablet: ['p10001l', 'w7001'], '*': 'mobile' }], + ], [ // Acer /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i, @@ -17138,6 +17156,11 @@ /; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i, ], [MODEL, [VENDOR, 'Ulefone'], [TYPE, MOBILE]], + [ + // Nothing + /droid.+; (a(?:015|06[35]|142p?))/i, + ], + [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [ // MIXED /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i, @@ -17369,6 +17392,10 @@ // WEARABLES /////////////////// + /\b(sm-[lr]\d\d[05][fnuw]?s?)\b/i, // Samsung Galaxy Watch + ], + [MODEL, [VENDOR, SAMSUNG], [TYPE, WEARABLE]], + [ /((pebble))app/i, // Pebble ], [VENDOR, MODEL, [TYPE, WEARABLE]], diff --git a/public/views/Room.html b/public/views/Room.html index 83d1a941..e16903ac 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -171,11 +171,13 @@

Loading

+
+
From b6649d90ea86830d2429ea8125a5ce3c645f1653 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Tue, 1 Oct 2024 21:52:42 +0200 Subject: [PATCH 014/119] [mirotalksfu] - fix username emoji --- public/js/Room.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/js/Room.js b/public/js/Room.js index a24cffc5..41d6429e 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -1015,6 +1015,9 @@ async function whoAreYou() { peer_name = name; }, }).then(async () => { + if (!usernameEmoji.classList.contains('hidden')) { + usernameEmoji.classList.add('hidden'); + } if (initStream && !joinRoomWithScreen) { await stopTracks(initStream); elemDisplay('initVideo', false); From 3631d1fa61562c8f5466e6df86aa1d298f1a440c Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Tue, 1 Oct 2024 22:15:59 +0200 Subject: [PATCH 015/119] [mirotalksfu] - improvements --- public/js/Room.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/Room.js b/public/js/Room.js index 41d6429e..f3b5b669 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -665,6 +665,7 @@ function setupInitButtons() { isInitVideoMirror = initVideo.classList.contains('mirror'); }; initUsernameEmojiButton.onclick = () => { + getId('usernameInput').value = ''; toggleUsernameEmoji(); }; } From 1a4c71669d8b13cb8eeb4343325b56fa5a3128a1 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 2 Oct 2024 13:49:55 +0200 Subject: [PATCH 016/119] [mirotalksfu] - fix room broadcasting --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 9 +++++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 5ec6b024..ef2ae7c5 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.77 + * @version 1.5.78 * */ diff --git a/package.json b/package.json index d81b37a3..99dc8bff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.77", + "version": "1.5.78", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index f3b5b669..81f64314 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.77 + * @version 1.5.78 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.77', + title: 'WebRTC SFU v1.5.78', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 7de46670..32a75c89 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.77 + * @version 1.5.78 * */ @@ -7014,10 +7014,11 @@ class RoomClient { const audioMessage = 'The participant has been muted, and only they have the ability to unmute themselves'; if (isBroadcastingEnabled) { + alert('isBroadcastingEnabled'); const peerAudioButton = this.getId(data.peer_id + '___pAudio'); if (peerAudioButton) { const peerAudioIcon = peerAudioButton.querySelector('i'); - if (peerAudioIcon && peerAudioIcon.style.color == 'red') { + if (peerAudioIcon && peerAudioIcon.classList.contains('red')) { if (isRulesActive && isPresenter) { data.action = 'unmute'; return this.confirmPeerAction(data.action, data); @@ -7043,7 +7044,7 @@ class RoomClient { const peerVideoButton = this.getId(data.peer_id + '___pVideo'); if (peerVideoButton) { const peerVideoIcon = peerVideoButton.querySelector('i'); - if (peerVideoIcon && peerVideoIcon.style.color == 'red') { + if (peerVideoIcon && peerVideoIcon.classList.contains('red')) { if (isRulesActive && isPresenter) { data.action = 'unhide'; return this.confirmPeerAction(data.action, data); @@ -7067,7 +7068,7 @@ class RoomClient { const peerScreenButton = this.getId(id); if (peerScreenButton) { const peerScreenStatus = peerScreenButton.querySelector('i'); - if (peerScreenStatus && peerScreenStatus.style.color == 'red') { + if (peerScreenStatus && peerScreenStatus.classList.contains('red')) { if (isRulesActive && isPresenter) { data.action = 'start'; return this.confirmPeerAction(data.action, data); From b5e86d82bc9227841d0d08a70b2c7b8a15edab18 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 2 Oct 2024 13:59:37 +0200 Subject: [PATCH 017/119] [mirotalksfu] - ops --- public/js/RoomClient.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 32a75c89..ff021bbd 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -7014,7 +7014,6 @@ class RoomClient { const audioMessage = 'The participant has been muted, and only they have the ability to unmute themselves'; if (isBroadcastingEnabled) { - alert('isBroadcastingEnabled'); const peerAudioButton = this.getId(data.peer_id + '___pAudio'); if (peerAudioButton) { const peerAudioIcon = peerAudioButton.querySelector('i'); From 31e113513923bbf66bb3ccbb0c056f409945cae5 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 3 Oct 2024 18:03:35 +0200 Subject: [PATCH 018/119] [mirotalksfu] - add comment --- app/src/config.template.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/config.template.js b/app/src/config.template.js index b3fdeb07..777e6d29 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -78,7 +78,9 @@ module.exports = { - dir: Directory where your video files are stored to be streamed via RTMP. - ffmpeg: Path of the ffmpeg installation on the system (which ffmpeg) - Important: Ensure your RTMP server is operational before proceeding. You can start the server by running the following command: + Important: Before proceeding, make sure your RTMP server is up and running. + For more information, refer to the documentation here: https://docs.mirotalk.com/mirotalk-sfu/rtmp/. + You can start the server by running the following command: - Start: npm run nms-start - Start the RTMP server. - Stop: npm run npm-stop - Stop the RTMP server. - Logs: npm run npm-logs - View the logs of the RTMP server. From 5f15bc43fdee3dd24389a9ea7893bc6e9d2ed628 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sun, 6 Oct 2024 18:14:45 +0200 Subject: [PATCH 019/119] [mirotalksfu] - fix, update dep --- app/src/Server.js | 39 ++++++++++++++++++++++++++------------- package.json | 6 +++--- public/js/Login.js | 5 ++--- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index ef2ae7c5..649cc45b 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.78 + * @version 1.5.79 * */ @@ -431,7 +431,7 @@ function startServer() { hostCfg.authenticated = true; } else { hostCfg.authenticated = false; - res.sendFile(views.login); + res.redirect('/login'); } } else { res.sendFile(views.landing); @@ -453,11 +453,11 @@ function startServer() { if ((!OIDC.enabled && hostCfg.protected && !hostCfg.authenticated) || authHost.isRoomActive()) { const ip = getIP(req); if (allowedIP(ip)) { - res.sendFile(views.newRoom); + res.redirect('/'); hostCfg.authenticated = true; } else { hostCfg.authenticated = false; - res.sendFile(views.login); + res.redirect('/login'); } } else { res.sendFile(views.newRoom); @@ -608,11 +608,11 @@ function startServer() { app.get(['/logged'], (req, res) => { const ip = getIP(req); if (allowedIP(ip)) { - res.sendFile(views.landing); + res.redirect('/'); hostCfg.authenticated = true; } else { hostCfg.authenticated = false; - res.sendFile(views.login); + res.redirect('/login'); } }); @@ -1221,6 +1221,7 @@ function startServer() { const validToken = await isValidToken(peer_token); if (!validToken) { + log.warn('[Join] - Invalid token', peer_token); return cb('unauthorized'); } @@ -1230,6 +1231,7 @@ function startServer() { if (!isPeerValid) { // redirect peer to login page + log.warn('[Join] - Invalid peer not authenticated', isPeerValid); return cb('unauthorized'); } @@ -1252,13 +1254,15 @@ function startServer() { }); return cb('unauthorized'); } - } else { - return cb('unauthorized'); } + // else { + // return cb('unauthorized'); + // } if (!hostCfg.users_from_db) { const roomAllowedForUser = isRoomAllowedForUser('[Join]', peer_name, room.id); if (!roomAllowedForUser) { + log.warn('[Join] - Room not allowed for this peer', { peer_name, room_id: room.id }); return cb('notAllowed'); } } @@ -1345,6 +1349,7 @@ function startServer() { if ((hostCfg.protected || hostCfg.user_auth) && isPresenter && !hostCfg.users_from_db) { const roomAllowedForUser = isRoomAllowedForUser('[Join]', peer_name, room.id); if (!roomAllowedForUser) { + log.warn('[Join] - Room not allowed for this peer', { peer_name, room_id: room.id }); return cb('notAllowed'); } } @@ -2813,11 +2818,19 @@ function startServer() { async function isAuthPeer(username, password) { if (hostCfg.users_from_db && hostCfg.users_api_endpoint) { try { - const response = await axios.post(hostCfg.users_api_endpoint, { - email: username, - password: password, - api_secret_key: hostCfg.users_api_secret_key, - }); + // Using either email or username, as the username can also be an email here. + const response = await axios.post( + hostCfg.users_api_endpoint, + { + email: username, + username: username, + password: password, + api_secret_key: hostCfg.users_api_secret_key, + }, + { + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) + }, + ); return response.data && response.data.message === true; } catch (error) { log.error('AXIOS isAuthPeer error', error.message); diff --git a/package.json b/package.json index 99dc8bff..f52ec048 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.78", + "version": "1.5.79", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,7 +57,7 @@ "node": ">=18" }, "dependencies": { - "@sentry/node": "^8.32.0", + "@sentry/node": "^8.33.1", "axios": "^1.7.7", "body-parser": "1.20.3", "colors": "1.4.0", @@ -77,7 +77,7 @@ "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.67.0", + "openai": "^4.67.1", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/js/Login.js b/public/js/Login.js index e6e0d1f6..312f6f90 100644 --- a/public/js/Login.js +++ b/public/js/Login.js @@ -28,8 +28,7 @@ function login() { const password = filterXSS(document.getElementById('password').value); // http://localhost:3010/join/?room=test - // http://localhost:3010/join/?room=test&roomPassword=0&name=mirotalksfu&audio=0&video=0&screen=0¬ify=0 - // http://localhost:3010/join/?room=test&roomPassword=0&name=mirotalksfu&audio=0&video=0&screen=0¬ify=0&username=username&password=password + // http://localhost:3010/join/?room=test&roomPassword=0&name=admin&audio=0&video=0&screen=0¬ify=0 const qs = new URLSearchParams(window.location.search); const room = filterXSS(qs.get('room')); @@ -55,7 +54,7 @@ function login() { return (window.location.href = '/join/' + window.location.search); // return (window.location.href = '/join/?room=' + room + '&token=' + token); } - if (roomPath) { + if (roomPath && roomPath !== 'login') { return (window.location.href = '/join/' + roomPath); // return (window.location.href ='/join/?room=' + roomPath + '&token=' + token); } diff --git a/public/js/Room.js b/public/js/Room.js index 81f64314..128563f5 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.78 + * @version 1.5.79 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.78', + title: 'WebRTC SFU v1.5.79', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index ff021bbd..fc041dd4 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.78 + * @version 1.5.79 * */ From 181cb7408f14c0cc196bece84e13a80165fd9bf7 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 7 Oct 2024 11:14:29 +0200 Subject: [PATCH 020/119] [mirotalksfu] - fix --- app/src/Server.js | 4 ++-- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 649cc45b..e0691f16 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.79 + * @version 1.5.80 * */ @@ -450,7 +450,7 @@ function startServer() { app.get(['/newroom'], OIDCAuth, (req, res) => { //log.info('/newroom - hostCfg ----->', hostCfg); - if ((!OIDC.enabled && hostCfg.protected && !hostCfg.authenticated) || authHost.isRoomActive()) { + if ((!OIDC.enabled && hostCfg.protected) || authHost.isRoomActive()) { const ip = getIP(req); if (allowedIP(ip)) { res.redirect('/'); diff --git a/package.json b/package.json index f52ec048..726ac815 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.79", + "version": "1.5.80", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index 128563f5..8c019fb5 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.79 + * @version 1.5.80 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.79', + title: 'WebRTC SFU v1.5.80', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index fc041dd4..e1ce75d6 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.79 + * @version 1.5.80 * */ @@ -7948,6 +7948,7 @@ class RoomClient { 'default', ]; + //console.log('AVATARS LISTS', completion.response.avatars); completion.response.avatars.forEach((avatar) => { avatar.avatar_states.forEach((avatarUi) => { if ( From f667a047eb5159eb12ae58d76689b4b724311b79 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 7 Oct 2024 11:22:02 +0200 Subject: [PATCH 021/119] [mirotalksfu] - fix --- app/src/Server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/Server.js b/app/src/Server.js index e0691f16..27d29b79 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -424,7 +424,7 @@ function startServer() { // main page app.get(['/'], OIDCAuth, (req, res) => { //log.debug('/ - hostCfg ----->', hostCfg); - if ((!OIDC.enabled && hostCfg.protected && !hostCfg.authenticated) || authHost.isRoomActive()) { + if ((!OIDC.enabled && hostCfg.protected) || authHost.isRoomActive()) { const ip = getIP(req); if (allowedIP(ip)) { res.sendFile(views.landing); From 80ba5a8707995b972f98abe4a9e5aec6f4fa6b10 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 7 Oct 2024 18:37:44 +0200 Subject: [PATCH 022/119] [mirotalksfu] - update dep --- app/src/Server.js | 2 +- package.json | 6 +++--- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 27d29b79..1075efe6 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.80 + * @version 1.5.81 * */ diff --git a/package.json b/package.json index 726ac815..aa32a8ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.80", + "version": "1.5.81", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -73,11 +73,11 @@ "js-yaml": "^4.1.0", "jsdom": "^25.0.1", "jsonwebtoken": "^9.0.2", - "mediasoup": "3.14.14", + "mediasoup": "3.14.15", "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.67.1", + "openai": "^4.67.2", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/js/Room.js b/public/js/Room.js index 8c019fb5..b1f12c95 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.80 + * @version 1.5.81 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.80', + title: 'WebRTC SFU v1.5.81', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index e1ce75d6..5dc4cbe9 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.80 + * @version 1.5.81 * */ From f7a94f00fbdbe67b6713d6ddf6ebdd061a2512e9 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 7 Oct 2024 21:22:19 +0200 Subject: [PATCH 023/119] [mirotalksfu] - handle allowedRooms from WEB --- app/src/Server.js | 40 ++++++++++++++++++++++++++++++++++---- app/src/config.template.js | 6 ++++-- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 1075efe6..75548b5d 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.81 + * @version 1.5.82 * */ @@ -140,6 +140,7 @@ const hostCfg = { protected: config.host.protected, user_auth: config.host.user_auth, users_from_db: config.host.users_from_db, + users_api_room_allowed: config.host.users_api_room_allowed, users_api_endpoint: config.host.users_api_endpoint, users_api_secret_key: config.host.users_api_secret_key, users: config.host.users, @@ -505,7 +506,7 @@ function startServer() { isPeerPresenter = presenter === '1' || presenter === 'true'; if (isPeerPresenter && !hostCfg.users_from_db) { - const roomAllowedForUser = isRoomAllowedForUser('Direct Join with token', username, room); + const roomAllowedForUser = await isRoomAllowedForUser('Direct Join with token', username, room); if (!roomAllowedForUser) { return res.status(401).json({ message: 'Direct Room Join for this User is Unauthorized' }); } @@ -518,7 +519,7 @@ function startServer() { } } else { const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, authHost, roomList, room); - const roomAllowedForUser = isRoomAllowedForUser('Direct Join with token', name, room); + const roomAllowedForUser = await isRoomAllowedForUser('Direct Join without token', name, room); if (!allowRoomAccess && !roomAllowedForUser) { return res.status(401).json({ message: 'Direct Room Join Unauthorized' }); } @@ -2140,6 +2141,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }); const data = { response: response.data.data }; @@ -2162,6 +2164,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }); const data = { response: response.data.data }; @@ -2194,6 +2197,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2224,6 +2228,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2252,6 +2257,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2282,6 +2288,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2337,6 +2344,7 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2944,7 +2952,7 @@ function startServer() { return allowRoomAccess; } - function isRoomAllowedForUser(message, username, room) { + async function isRoomAllowedForUser(message, username, room) { const logData = { message, username, room }; log.debug('isRoomAllowedForUser ------>', logData); @@ -2952,6 +2960,30 @@ function startServer() { const isOIDCEnabled = config.oidc && config.oidc.enabled; if (hostCfg.protected || hostCfg.user_auth) { + // Check if allowed room for user from DB... + if (hostCfg.users_from_db && hostCfg.users_api_room_allowed) { + try { + // Using either email or username, as the username can also be an email here. + const response = await axios.post( + hostCfg.users_api_room_allowed, + { + email: username, + username: username, + room: room, + api_secret_key: hostCfg.users_api_secret_key, + }, + { + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) + }, + ); + + return response.data && response.data.message === true; + } catch (error) { + log.error('AXIOS isRoomAllowedForUserDb error', error.message); + return false; + } + } + const isInPresenterLists = config.presenters.list.includes(username); if (isInPresenterLists) { diff --git a/app/src/config.template.js b/app/src/config.template.js index 777e6d29..53174f3a 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -172,8 +172,10 @@ module.exports = { protected: false, user_auth: false, users_from_db: false, // if true ensure that api.token is also set to true. - //users_api_endpoint: 'http://localhost:9000/api/v1/user/isAuth', - users_api_endpoint: 'https://webrtc.mirotalk.com/api/v1/user/isAuth', + users_api_endpoint: 'http://localhost:9000/api/v1/user/isAuth', + users_api_room_allowed: 'http://localhost:9000/api/v1/user/isRoomAllowed', + //users_api_endpoint: 'https://webrtc.mirotalk.com/api/v1/user/isAuth', + //users_api_room_allowed: 'https://webrtc.mirotalk.com/api/v1/user/isRoomAllowed', users_api_secret_key: 'mirotalkweb_default_secret', users: [ { diff --git a/package.json b/package.json index aa32a8ef..f0b4da5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.81", + "version": "1.5.82", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index b1f12c95..aab5ebb3 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.81 + * @version 1.5.82 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.81', + title: 'WebRTC SFU v1.5.82', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 5dc4cbe9..7067c34f 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.81 + * @version 1.5.82 * */ From 3389f8d8c0a7ea9722df1533222fc98458cedfbf Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Tue, 8 Oct 2024 17:42:27 +0200 Subject: [PATCH 024/119] [mirotalksfu] - update readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 40556b6d..f2791293 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,10 @@ $ PORT=3011 npm start - Install [docker engine](https://docs.docker.com/engine/install/) and [docker compose](https://docs.docker.com/compose/install/) ```bash +# Clone this repo +$ git clone https://github.com/miroslavpejic85/mirotalksfu.git +# Go to to dir mirotalksfu +$ cd mirotalksfu # Copy app/src/config.template.js in app/src/config.js IMPORTANT (edit it according to your needs) $ cp app/src/config.template.js app/src/config.js # Copy docker-compose.template.yml in docker-compose.yml and edit it if needed From 7690d9a6e3fb301a5baaabb6ac2fddcaf683364b Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 9 Oct 2024 13:56:36 +0200 Subject: [PATCH 025/119] [mirotalksfu] - fix allowedRoomAccess on host protected --- app/src/Host.js | 27 ----------------------- app/src/Server.js | 48 +++++++++++++++++++---------------------- package.json | 6 +++--- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 5 files changed, 28 insertions(+), 59 deletions(-) diff --git a/app/src/Host.js b/app/src/Host.js index f660028e..f1f4c771 100644 --- a/app/src/Host.js +++ b/app/src/Host.js @@ -3,7 +3,6 @@ module.exports = class Host { constructor() { this.authorizedIPs = new Map(); - this.roomActive = false; } /** @@ -30,7 +29,6 @@ module.exports = class Host { */ setAuthorizedIP(ip, authorized) { this.authorizedIPs.set(ip, authorized); - this.setRoomActive(); } /** @@ -42,37 +40,12 @@ module.exports = class Host { return this.authorizedIPs.has(ip); } - /** - * Host room status - * @returns boolean - */ - isRoomActive() { - return this.roomActive; - } - - /** - * Set host room activate - */ - setRoomActive() { - this.roomActive = true; - } - - /** - * Set host room deactivate - */ - setRoomDeactivate() { - this.roomActive = false; - } - /** * Delete ip from authorized IPs * @param {string} ip * @returns boolean */ deleteIP(ip) { - if (this.isAuthorizedIP(ip)) { - this.setRoomDeactivate(); - } return this.authorizedIPs.delete(ip); } }; diff --git a/app/src/Server.js b/app/src/Server.js index 75548b5d..ada62c4d 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.82 + * @version 1.5.83 * */ @@ -299,7 +299,6 @@ function OIDCAuth(req, res, next) { log.debug('[OIDC] ------> Host protected', { authenticated: hostCfg.authenticated, authorizedIPs: authHost.getAuthorizedIPs(), - activeRoom: authHost.isRoomActive(), }); } next(); @@ -404,7 +403,6 @@ function startServer() { log.debug('[OIDC] ------> Logout', { authenticated: hostCfg.authenticated, authorizedIPs: authHost.getAuthorizedIPs(), - activeRoom: authHost.isRoomActive(), }); } req.logout(); // Logout user @@ -425,7 +423,8 @@ function startServer() { // main page app.get(['/'], OIDCAuth, (req, res) => { //log.debug('/ - hostCfg ----->', hostCfg); - if ((!OIDC.enabled && hostCfg.protected) || authHost.isRoomActive()) { + + if (!OIDC.enabled && hostCfg.protected) { const ip = getIP(req); if (allowedIP(ip)) { res.sendFile(views.landing); @@ -451,7 +450,7 @@ function startServer() { app.get(['/newroom'], OIDCAuth, (req, res) => { //log.info('/newroom - hostCfg ----->', hostCfg); - if ((!OIDC.enabled && hostCfg.protected) || authHost.isRoomActive()) { + if (!OIDC.enabled && hostCfg.protected) { const ip = getIP(req); if (allowedIP(ip)) { res.redirect('/'); @@ -518,7 +517,7 @@ function startServer() { : res.sendFile(views.landing); } } else { - const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, authHost, roomList, room); + const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, roomList, room); const roomAllowedForUser = await isRoomAllowedForUser('Direct Join without token', name, room); if (!allowRoomAccess && !roomAllowedForUser) { return res.status(401).json({ message: 'Direct Room Join Unauthorized' }); @@ -552,24 +551,24 @@ function startServer() { // join room by id app.get('/join/:roomId', (req, res) => { // - const roomId = req.params.roomId; + const { roomId } = req.params; + + if (!roomId) { + log.warn('/join/:roomId empty', roomId); + return res.redirect('/'); + } if (!Validator.isValidRoomName(roomId)) { log.warn('/join/:roomId invalid', roomId); return res.redirect('/'); } - const allowRoomAccess = isAllowedRoomAccess('/join/:roomId', req, hostCfg, authHost, roomList, roomId); + const allowRoomAccess = isAllowedRoomAccess('/join/:roomId', req, hostCfg, roomList, roomId); if (allowRoomAccess) { - if (hostCfg.protected) authHost.setRoomActive(); - res.sendFile(views.room); } else { - if (!OIDC.enabled && hostCfg.protected) { - return res.sendFile(views.login); - } - res.redirect('/'); + !OIDC.enabled && hostCfg.protected ? res.redirect('/login') : res.redirect('/'); } }); @@ -2922,30 +2921,30 @@ function startServer() { return roomPeersArray; } - function isAllowedRoomAccess(logMessage, req, hostCfg, authHost, roomList, roomId) { + function isAllowedRoomAccess(logMessage, req, hostCfg, roomList, roomId) { const OIDCUserAuthenticated = OIDC.enabled && req.oidc.isAuthenticated(); const hostUserAuthenticated = hostCfg.protected && hostCfg.authenticated; - const roomActive = authHost.isRoomActive(); const roomExist = roomList.has(roomId); const roomCount = roomList.size; const allowRoomAccess = (!hostCfg.protected && !OIDC.enabled) || // No host protection and OIDC mode enabled (default) - OIDCUserAuthenticated || // User authenticated via OIDC - hostUserAuthenticated || // User authenticated via Login + (OIDCUserAuthenticated && roomExist) || // User authenticated via OIDC and room Exist + (hostUserAuthenticated && roomExist) || // User authenticated via Login and room Exist ((OIDCUserAuthenticated || hostUserAuthenticated) && roomCount === 0) || // User authenticated joins the first room roomExist; // User Or Guest join an existing Room log.debug(logMessage, { - OIDCUserEnabled: OIDC.enabled, OIDCUserAuthenticated: OIDCUserAuthenticated, hostUserAuthenticated: hostUserAuthenticated, - hostProtected: hostCfg.protected, - hostAuthenticated: hostCfg.authenticated, - roomActive: roomActive, roomExist: roomExist, roomCount: roomCount, - roomId: roomId, + extraInfo: { + roomId: roomId, + OIDCUserEnabled: OIDC.enabled, + hostProtected: hostCfg.protected, + hostAuthenticated: hostCfg.authenticated, + }, allowRoomAccess: allowRoomAccess, }); @@ -3039,12 +3038,10 @@ function startServer() { function allowedIP(ip) { const authorizedIPs = authHost.getAuthorizedIPs(); const authorizedIP = authHost.isAuthorizedIP(ip); - const isRoomActive = authHost.isRoomActive(); log.info('Allowed IPs', { ip: ip, authorizedIP: authorizedIP, authorizedIPs: authorizedIPs, - isRoomActive: isRoomActive, }); return authHost != null && authorizedIP; } @@ -3058,7 +3055,6 @@ function startServer() { log.info('Remove IP from auth', { ip: ip, authorizedIps: authHost.getAuthorizedIPs(), - roomActive: authHost.isRoomActive(), }); } } diff --git a/package.json b/package.json index f0b4da5e..0512769b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.82", + "version": "1.5.83", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -65,7 +65,7 @@ "cors": "2.8.5", "crypto-js": "4.2.0", "dompurify": "^3.1.7", - "express": "4.21.0", + "express": "4.21.1", "express-openid-connect": "^2.17.1", "fluent-ffmpeg": "^2.1.3", "he": "^1.2.0", @@ -77,7 +77,7 @@ "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.67.2", + "openai": "^4.67.3", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/js/Room.js b/public/js/Room.js index aab5ebb3..dfad3ee2 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.82 + * @version 1.5.83 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.82', + title: 'WebRTC SFU v1.5.83', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 7067c34f..76acac8b 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.82 + * @version 1.5.83 * */ From f13fa1496da98c119b66862da36af0f6fda3b9c5 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 12 Oct 2024 21:44:58 +0200 Subject: [PATCH 026/119] [mirotalksfu] - fix meta, update dep, sec --- SECURITY.md | 2 +- app/src/Server.js | 2 +- package.json | 4 ++-- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- public/views/Room.html | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 570fea68..ae64fd10 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -28,7 +28,7 @@ We would like to extend our gratitude to the following individuals for their res | Name | Contact | | ----------------- | ------------------------------- | | `Hendrik Siewert` | hendrik.siewert@upb.de | -| `Caio Fook` | caio.fook@gmail.com | +| `Caio Fook` | https://github.com/caiofook | | `Nishant Jain` | https://twitter.com/realArcherL | Their dedication to security has contributed to the continuous improvement of our systems, ensuring the safety and privacy of our users and data. diff --git a/app/src/Server.js b/app/src/Server.js index ada62c4d..c588f7a0 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.83 + * @version 1.5.84 * */ diff --git a/package.json b/package.json index 0512769b..d6555c06 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.83", + "version": "1.5.84", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,7 +57,7 @@ "node": ">=18" }, "dependencies": { - "@sentry/node": "^8.33.1", + "@sentry/node": "^8.34.0", "axios": "^1.7.7", "body-parser": "1.20.3", "colors": "1.4.0", diff --git a/public/js/Room.js b/public/js/Room.js index dfad3ee2..be09e475 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.83 + * @version 1.5.84 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.83', + title: 'WebRTC SFU v1.5.84', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 76acac8b..d01b8695 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.83 + * @version 1.5.84 * */ diff --git a/public/views/Room.html b/public/views/Room.html index e16903ac..f1633abe 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -11,7 +11,7 @@ - + Date: Sat, 12 Oct 2024 21:54:32 +0200 Subject: [PATCH 027/119] [mirotalksfu] - fix typo --- public/views/Room.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/views/Room.html b/public/views/Room.html index f1633abe..3e7d4fee 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -11,8 +11,10 @@ - - + Date: Mon, 14 Oct 2024 18:19:26 +0200 Subject: [PATCH 028/119] [mirotalksfu] - #168 fix target --- app/src/Server.js | 2 +- app/src/XSS.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 4 +++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index c588f7a0..63e7af71 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.84 + * @version 1.5.85 * */ diff --git a/app/src/XSS.js b/app/src/XSS.js index c734d32b..d2001042 100644 --- a/app/src/XSS.js +++ b/app/src/XSS.js @@ -14,7 +14,7 @@ const log = new Logger('Xss'); // Configure DOMPurify purify.setConfig({ ALLOWED_TAGS: ['a', 'img', 'div', 'span', 'svg', 'g', 'p'], // Allow specific tags - ALLOWED_ATTR: ['href', 'src', 'title', 'id', 'class'], // Allow specific attributes + ALLOWED_ATTR: ['href', 'src', 'title', 'id', 'class', 'target'], // Allow specific attributes ALLOWED_URI_REGEXP: /^(?!data:|javascript:|vbscript:|file:|view-source:).*/, // Disallow dangerous URIs }); diff --git a/package.json b/package.json index d6555c06..1d58a4a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.84", + "version": "1.5.85", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index be09e475..a8ccacb9 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.84 + * @version 1.5.85 * */ @@ -4490,7 +4490,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.84', + title: 'WebRTC SFU v1.5.85', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index d01b8695..a5088bcf 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.84 + * @version 1.5.85 * */ @@ -4260,6 +4260,7 @@ class RoomClient { if (this.isImageURL(message)) return this.getImage(message); //if (this.isVideoTypeSupported(message)) return this.getIframe(message); return this.getLink(message); + return message; } if (isChatMarkdownOn) return marked.parse(message); if (isChatPasteTxt && this.getLineBreaks(message) > 1) { @@ -4296,6 +4297,7 @@ class RoomClient { const pattern = new RegExp( '^(https?:\\/\\/)?' + // protocol '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + 'localhost|' + // allow localhost '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string From 78bc02a5754829ba8bd9cfdc62fcc9b1b4e25788 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 14 Oct 2024 18:26:53 +0200 Subject: [PATCH 029/119] [mirotalksfu] - #168 ops --- public/js/RoomClient.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a5088bcf..aebd5a3c 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -4260,7 +4260,6 @@ class RoomClient { if (this.isImageURL(message)) return this.getImage(message); //if (this.isVideoTypeSupported(message)) return this.getIframe(message); return this.getLink(message); - return message; } if (isChatMarkdownOn) return marked.parse(message); if (isChatPasteTxt && this.getLineBreaks(message) > 1) { From ba9951caddbb8b25c47afb50cc17b82c1fd59141 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 13:01:17 +0200 Subject: [PATCH 030/119] [mirotalksfu] - allow screen sharing up to 8k, improvements --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 7 +- public/js/RoomClient.js | 174 +++++++++++++--------------------------- public/views/Room.html | 14 ++++ 5 files changed, 76 insertions(+), 123 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 63e7af71..66438834 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.85 + * @version 1.5.86 * */ diff --git a/package.json b/package.json index 1d58a4a9..7b1d311d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.85", + "version": "1.5.86", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index a8ccacb9..59bfb7a3 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.85 + * @version 1.5.86 * */ @@ -2286,6 +2286,9 @@ function handleSelects() { videoQuality.onchange = () => { rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value); }; + screenQuality.onchange = () => { + rc.closeThenProduce(RoomClient.mediaType.screen); + }; videoFps.onchange = () => { rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value); localStorageSettings.video_fps = videoFps.selectedIndex; @@ -4490,7 +4493,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.85', + title: 'WebRTC SFU v1.5.86', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index aebd5a3c..a799bcbb 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.85 + * @version 1.5.86 * */ @@ -1510,7 +1510,7 @@ class RoomClient { } // #################################################### - // AUDIO/VIDEO CONSTRAINTS + // AUDIO/VIDEO/SCREEN CONSTRAINTS // #################################################### getAudioConstraints(deviceId) { @@ -1555,149 +1555,85 @@ class RoomClient { const defaultFrameRate = { ideal: 30 }; const selectedValue = this.getSelectedIndexValue(videoFps); const customFrameRate = parseInt(selectedValue, 10); - const frameRate = selectedValue == 'max' ? defaultFrameRate : customFrameRate; - let videoConstraints = { + const frameRate = selectedValue === 'max' ? defaultFrameRate : { ideal: customFrameRate }; + + // Base constraints structure with dynamic values for resolution and frame rate + const videoBaseConstraints = (width, height, exact = false) => ({ audio: false, video: { - width: { ideal: 3840 }, - height: { ideal: 2160 }, + width: exact ? { exact: width } : { ideal: width }, + height: exact ? { exact: height } : { ideal: height }, deviceId: deviceId, - aspectRatio: 1.777, // 16:9 + aspectRatio: 1.777, // 16:9 aspect ratio frameRate: frameRate, }, - }; // Init auto detect max cam resolution and fps + }); - videoFps.disabled = false; + const videoResolutionMap = { + qvga: { width: 320, height: 240, exact: true }, + vga: { width: 640, height: 480, exact: true }, + hd: { width: 1280, height: 720, exact: true }, + fhd: { width: 1920, height: 1080, exact: true }, + '2k': { width: 2560, height: 1440, exact: true }, + '4k': { width: 3840, height: 2160, exact: true }, + '6k': { width: 6144, height: 3456, exact: true }, + '8k': { width: 7680, height: 4320, exact: true }, + }; + + let videoConstraints; switch (videoQuality.value) { case 'default': - // This will make the browser use HD Video and 30fps as default. - videoConstraints = { - audio: false, - video: { - width: { ideal: 1280 }, - height: { ideal: 720 }, - deviceId: deviceId, - aspectRatio: 1.777, - }, - }; + // Default ideal HD resolution + videoConstraints = videoBaseConstraints(1280, 720); videoFps.selectedIndex = 0; videoFps.disabled = true; break; - case 'qvga': - videoConstraints = { - audio: false, - video: { - width: { exact: 320 }, - height: { exact: 240 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints low bandwidth - break; - case 'vga': - videoConstraints = { - audio: false, - video: { - width: { exact: 640 }, - height: { exact: 480 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints medium bandwidth - break; - case 'hd': - videoConstraints = { - audio: false, - video: { - width: { exact: 1280 }, - height: { exact: 720 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints high bandwidth - break; - case 'fhd': - videoConstraints = { - audio: false, - video: { - width: { exact: 1920 }, - height: { exact: 1080 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints very high bandwidth - break; - case '2k': - videoConstraints = { - audio: false, - video: { - width: { exact: 2560 }, - height: { exact: 1440 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints ultra high bandwidth - break; - case '4k': - videoConstraints = { - audio: false, - video: { - width: { exact: 3840 }, - height: { exact: 2160 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints ultra high bandwidth - break; - case '6k': - videoConstraints = { - audio: false, - video: { - width: { exact: 6144 }, - height: { exact: 3456 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints Very ultra high bandwidth - break; - case '8k': - videoConstraints = { - audio: false, - video: { - width: { exact: 7680 }, - height: { exact: 4320 }, - deviceId: deviceId, - aspectRatio: 1.777, - frameRate: frameRate, - }, - }; // video cam constraints Very ultra high bandwidth - break; default: + // Ideal Full HD if no match found in the video resolution map + const { width, height, exact } = videoResolutionMap[videoQuality.value] || { + width: 1920, + height: 1080, + }; + videoConstraints = videoBaseConstraints(width, height, exact); break; } + this.videoQualitySelectedIndex = videoQuality.selectedIndex; + return videoConstraints; } getScreenConstraints() { + const defaultFrameRate = { ideal: 30 }; const selectedValue = this.getSelectedIndexValue(screenFps); - const frameRate = selectedValue == 'max' ? 30 : parseInt(selectedValue, 10); - return { + const customFrameRate = parseInt(selectedValue, 10); + const frameRate = selectedValue === 'max' ? defaultFrameRate : { ideal: customFrameRate }; + + // Base constraints structure with dynamic values for resolution and frame rate + const screenBaseConstraints = (width, height) => ({ audio: true, video: { - width: { ideal: 1920 }, - height: { ideal: 1080 }, + width: { ideal: width }, + height: { ideal: height }, + aspectRatio: 1.777, // 16:9 aspect ratio frameRate: frameRate, }, + }); + + const screenResolutionMap = { + hd: { width: 1280, height: 720 }, + fhd: { width: 1920, height: 1080 }, + '2k': { width: 2560, height: 1440 }, + '4k': { width: 3840, height: 2160 }, + '6k': { width: 6144, height: 3456 }, + '8k': { width: 7680, height: 4320 }, }; + + // Default to Full HD if no match found in the screen resolution map + const { width, height } = screenResolutionMap[screenQuality.value] || { width: 1920, height: 1080 }; + + return screenBaseConstraints(width, height); } // #################################################### diff --git a/public/views/Room.html b/public/views/Room.html index 3e7d4fee..a099a2d4 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -399,6 +399,20 @@

Loading

+
+
+ +

Screen Quality:

+
+
From 8505e04a0ae756a1248aa6675a856b876976f1df Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 14:47:48 +0200 Subject: [PATCH 031/119] [mirotalksfu] - fix typo --- public/js/Room.js | 1 + public/views/Room.html | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/public/js/Room.js b/public/js/Room.js index 59bfb7a3..e75b11e7 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -1372,6 +1372,7 @@ function roomIsReady() { if (navigator.getDisplayMedia || navigator.mediaDevices.getDisplayMedia) { if (BUTTONS.main.startScreenButton) { show(startScreenButton); + show(ScreenQualityDiv); show(ScreenFpsDiv); } BUTTONS.main.snapshotRoomButton && show(snapshotRoomButton); diff --git a/public/views/Room.html b/public/views/Room.html index a099a2d4..3bff7e18 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -400,19 +400,21 @@

Loading


-
- -

Screen Quality:

+ -
From 512457351b129b026dc3a29c4d3a679f4e444e17 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 16:08:33 +0200 Subject: [PATCH 032/119] [mirotalksfu] - remove timeout --- app/src/Server.js | 7 ------- public/js/RoomClient.js | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 66438834..850b8565 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -2140,7 +2140,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }); const data = { response: response.data.data }; @@ -2163,7 +2162,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }); const data = { response: response.data.data }; @@ -2196,7 +2194,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2227,7 +2224,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2256,7 +2252,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2287,7 +2282,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); @@ -2343,7 +2337,6 @@ function startServer() { 'Content-Type': 'application/json', 'X-Api-Key': config.videoAI.apiKey, }, - timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a799bcbb..4467d2d3 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -7885,7 +7885,7 @@ class RoomClient { 'default', ]; - //console.log('AVATARS LISTS', completion.response.avatars); + console.log('AVATARS LISTS', completion.response.avatars); completion.response.avatars.forEach((avatar) => { avatar.avatar_states.forEach((avatarUi) => { if ( From 511bde4d943767ea60dbf45546e39d840b40f3d9 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 16:09:12 +0200 Subject: [PATCH 033/119] [mirotalksfu] - fix typo --- public/js/RoomClient.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 4467d2d3..a799bcbb 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -7885,7 +7885,7 @@ class RoomClient { 'default', ]; - console.log('AVATARS LISTS', completion.response.avatars); + //console.log('AVATARS LISTS', completion.response.avatars); completion.response.avatars.forEach((avatar) => { avatar.avatar_states.forEach((avatarUi) => { if ( From 7d5a38cc7de9413f27a2d0972a78530cb4b7cf87 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 20:09:16 +0200 Subject: [PATCH 034/119] [mirotalksfu] - fix avatars --- app/src/Server.js | 25 +++++++++++++++---------- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 16 ++++++++-------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 850b8565..c6f2de25 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.86 + * @version 1,5,87 * */ @@ -2129,8 +2129,7 @@ function startServer() { } }); - // https://docs.heygen.com/reference/overview-copy - + // https://docs.heygen.com/reference/avatar-list socket.on('getAvatarList', async ({}, cb) => { if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); @@ -2153,6 +2152,7 @@ function startServer() { } }); + // https://docs.heygen.com/reference/get-voices socket.on('getVoiceList', async ({}, cb) => { if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); @@ -2175,24 +2175,25 @@ function startServer() { } }); - socket.on('streamingNew', async ({ quality, avatar_name, voice_id }, cb) => { + // https://docs.heygen.com/reference/new-session + socket.on('streamingNew', async ({ quality, avatar_id, voice_id }, cb) => { if (!roomList.has(socket.room_id)) return; if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); try { + const voice = voice_id ? { voice_id: voice_id } : {}; const response = await axios.post( `${config.videoAI.basePath}/v1/streaming.new`, { quality, - avatar_name, - voice: { - voice_id: voice_id, - }, + avatar_id, + voice: voice, }, { headers: { - 'Content-Type': 'application/json', - 'X-Api-Key': config.videoAI.apiKey, + 'accept': 'application/json', + 'content-type': 'application/json', + 'x-api-key': config.videoAI.apiKey, }, }, ); @@ -2210,6 +2211,7 @@ function startServer() { } }); + // https://docs.heygen.com/reference/start-session socket.on('streamingStart', async ({ session_id, sdp }, cb) => { if (!roomList.has(socket.room_id)) return; if (!config.videoAI.enabled || !config.videoAI.apiKey) @@ -2238,6 +2240,7 @@ function startServer() { } }); + // https://docs.heygen.com/reference/submit-ice-information socket.on('streamingICE', async ({ session_id, candidate }, cb) => { if (!roomList.has(socket.room_id)) return; if (!config.videoAI.enabled || !config.videoAI.apiKey) @@ -2266,6 +2269,7 @@ function startServer() { } }); + // https://docs.heygen.com/reference/send-task socket.on('streamingTask', async ({ session_id, text }, cb) => { if (!roomList.has(socket.room_id)) return; if (!config.videoAI.enabled || !config.videoAI.apiKey) @@ -2322,6 +2326,7 @@ function startServer() { } }); + // https://docs.heygen.com/reference/close-session socket.on('streamingStop', async ({ session_id }, cb) => { if (!roomList.has(socket.room_id)) return; if (!config.videoAI.enabled || !config.videoAI.apiKey) diff --git a/package.json b/package.json index 7b1d311d..f668784b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.86", + "version": "1,5,87", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index e75b11e7..9a7a5953 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.86 + * @version 1,5,87 * */ @@ -4494,7 +4494,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.86', + title: 'WebRTC SFU v1,5,87', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a799bcbb..5426a59f 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.86 + * @version 1,5,87 * */ @@ -168,9 +168,9 @@ const VideoAI = { enabled: true, active: false, info: {}, - avatar: null, + avatarId: null, avatarName: 'Monica', - avatarVoice: '', + avatarVoice: null, quality: 'medium', virtualBackground: true, background: '../images/virtual/1.jpg', @@ -7885,7 +7885,7 @@ class RoomClient { 'default', ]; - //console.log('AVATARS LISTS', completion.response.avatars); + console.log('AVATARS LISTS', completion.response.avatars); completion.response.avatars.forEach((avatar) => { avatar.avatar_states.forEach((avatarUi) => { if ( @@ -7928,9 +7928,9 @@ class RoomClient { img.style.border = 'var(--border)'; const avatarData = img.getAttribute('avatarData'); const avatarDataArr = avatarData.split('|'); - VideoAI.avatar = avatarDataArr[0]; + VideoAI.avatarId = avatarDataArr[0]; VideoAI.avatarName = avatarDataArr[1]; - VideoAI.avatarVoice = avatarDataArr[2] ? avatarDataArr[2] : ''; + //VideoAI.avatarVoice = avatarDataArr[2] ? avatarDataArr[2] : ''; use the default one avatarVideoAIPreview.setAttribute('src', avatarUi.video_url.grey); avatarVideoAIPreview.play(); @@ -8091,11 +8091,11 @@ class RoomClient { async streamingNew() { try { - const { quality, avatar, avatarVoice } = VideoAI; + const { quality, avatarId, avatarVoice } = VideoAI; const response = await this.socket.request('streamingNew', { quality: quality, - avatar_name: avatar, + avatar_id: avatarId, voice_id: avatarVoice, }); From 0c7af73c2756a5f4529bbb138edeca99fe0ec01d Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 20:12:02 +0200 Subject: [PATCH 035/119] [mirotalksfu] - ops --- app/src/Server.js | 4 ++-- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index c6f2de25..6bbefd83 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1,5,87 + * @version 1.5.87 * */ @@ -2191,7 +2191,7 @@ function startServer() { }, { headers: { - 'accept': 'application/json', + accept: 'application/json', 'content-type': 'application/json', 'x-api-key': config.videoAI.apiKey, }, diff --git a/package.json b/package.json index f668784b..368cc5e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1,5,87", + "version": "1.5.87", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index 9a7a5953..07188f4b 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1,5,87 + * @version 1.5.87 * */ @@ -4494,7 +4494,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1,5,87', + title: 'WebRTC SFU v1.5.87', html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 5426a59f..0a2b4c4e 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1,5,87 + * @version 1.5.87 * */ From f230b4e5a05f70882a759358c4f8ca540f6c1d39 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 16 Oct 2024 20:41:18 +0200 Subject: [PATCH 036/119] [mirotalksfu] - avatars improvements --- app/src/config.template.js | 2 +- public/js/RoomClient.js | 9 +++++---- public/views/Room.html | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/config.template.js b/app/src/config.template.js index 53174f3a..be025fa3 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -234,7 +234,7 @@ module.exports = { basePath: 'https://api.heygen.com', apiKey: '', systemLimit: - 'You are a streaming avatar from MiroTalk SFU, an industry-leading product that specialize in videos communications. Audience will try to have a conversation with you, please try answer the questions or respond their comments naturally, and concisely. - please try your best to response with short answers, and only answer the last question.', + 'You are a streaming avatar from MiroTalk SFU, an industry-leading product that specialize in videos communications.', }, email: { /* diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 0a2b4c4e..d63f7f6d 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -3003,7 +3003,7 @@ class RoomClient { } } - msgPopup(type, message) { + msgPopup(type, message, timer = 3000) { switch (type) { case 'warning': case 'error': @@ -3048,7 +3048,7 @@ class RoomClient { showConfirmButton: false, timerProgressBar: true, toast: true, - timer: 3000, + timer: timer, }); Toast.fire({ icon: 'info', @@ -7853,6 +7853,7 @@ class RoomClient { // ############################################## getAvatarList() { + this.msgPopup('toast', 'Please hold on, we are processing the avatar lists...', 10000); this.socket .request('getAvatarList') .then(function (completion) { @@ -7885,7 +7886,7 @@ class RoomClient { 'default', ]; - console.log('AVATARS LISTS', completion.response.avatars); + //console.log('AVATARS LISTS', completion.response.avatars); completion.response.avatars.forEach((avatar) => { avatar.avatar_states.forEach((avatarUi) => { if ( @@ -7994,7 +7995,7 @@ class RoomClient { const selectedPreviewURL = completion.response.list.find( (flag) => flag.voice_id === selectedVoiceID, )?.preview?.movio; - VideoAI.avatarVoice = selectedVoiceID; + VideoAI.avatarVoice = selectedVoiceID ? selectedVoiceID : null; if (selectedPreviewURL) { const avatarPreviewAudio = document.getElementById('avatarPreviewAudio'); avatarPreviewAudio.src = selectedPreviewURL; diff --git a/public/views/Room.html b/public/views/Room.html index 3bff7e18..7e3a3fe9 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -937,7 +937,7 @@

Moderator options

- +
From d177bbb6b0c1ff0d32a6255fbbb622eed25f4bc6 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 17 Oct 2024 12:07:01 +0200 Subject: [PATCH 037/119] [mirotalksfu] - #169 fix private messaging when new peer joins the room --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 18 ++++++++++++------ public/js/RoomClient.js | 9 +++++++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 6bbefd83..f6276d28 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.87 + * @version 1.5.88 * */ diff --git a/package.json b/package.json index 368cc5e7..9790914f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.87", + "version": "1.5.88", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index 07188f4b..4edf57f5 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.87 + * @version 1.5.88 * */ @@ -3932,12 +3932,14 @@ function getParticipantsList(peers) { // CHAT-GPT if (chatGPT) { + const chatgpt_active = rc.chatPeerName === 'ChatGPT' ? ' active' : ''; + li = `
  • `; } + const public_chat_active = rc.chatPeerName === 'all' ? ' active' : ''; + // ALL li += `
  • diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index d63f7f6d..83a98b0a 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.87 + * @version 1.5.88 * */ @@ -235,6 +235,8 @@ class RoomClient { this.chatMessageNotifyDelay = 10000; // ms this.chatMessageSpamCount = 0; this.chatMessageSpamCountToBan = 10; + this.chatPeerId = 'all'; + this.chatPeerName = 'all'; // HeyGen Video AI this.videoAIContainer = null; @@ -3704,7 +3706,7 @@ class RoomClient { } this.chatCenter(); this.sound('open'); - this.showPeerAboutAndMessages('all', 'all'); + this.showPeerAboutAndMessages(this.chatPeerId, this.chatPeerName); } isParticipantsListOpen = !isParticipantsListOpen; this.isChatOpen = !this.isChatOpen; @@ -7442,6 +7444,9 @@ class RoomClient { showPeerAboutAndMessages(peer_id, peer_name, event = null) { this.hidePeerMessages(); + this.chatPeerId = peer_id; + this.chatPeerName = peer_name; + const chatAbout = this.getId('chatAbout'); const participant = this.getId(peer_id); const participantsList = this.getId('participantsList'); From c29e777611260ca91b6d8c62b104325cb41ee6b7 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 18 Oct 2024 21:03:12 +0200 Subject: [PATCH 038/119] [mirotalksfu] - add roomsAllowed, fix, update dep --- app/src/Server.js | 57 +++++++++++++++++++++++++++++++++---- app/src/config.template.js | 2 ++ package.json | 6 ++-- public/css/landing.css | 8 ++++++ public/js/Login.js | 31 ++++++++++++++++++++ public/js/Room.js | 4 +-- public/js/RoomClient.js | 2 +- public/views/login.html | 58 +++++++++++++++++++++++--------------- 8 files changed, 133 insertions(+), 35 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index f6276d28..2341a6da 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.88 + * @version 1.5.89 * */ @@ -141,6 +141,7 @@ const hostCfg = { user_auth: config.host.user_auth, users_from_db: config.host.users_from_db, users_api_room_allowed: config.host.users_api_room_allowed, + users_api_rooms_allowed: config.host.users_api_rooms_allowed, users_api_endpoint: config.host.users_api_endpoint, users_api_secret_key: config.host.users_api_secret_key, users: config.host.users, @@ -647,7 +648,9 @@ function startServer() { config.presenters.list.includes(username).toString(); const token = encodeToken({ username: username, password: password, presenter: isPresenter }); - return res.status(200).json({ message: token }); + const allowedRooms = await getUserAllowedRooms(username, password); + + return res.status(200).json({ message: token, allowedRooms: allowedRooms }); } if (isPeerValid) { @@ -655,7 +658,8 @@ function startServer() { const isPresenter = config.presenters && config.presenters.list && config.presenters.list.includes(username).toString(); const token = encodeToken({ username: username, password: password, presenter: isPresenter }); - return res.status(200).json({ message: token }); + const allowedRooms = await getUserAllowedRooms(username, password); + return res.status(200).json({ message: token, allowedRooms: allowedRooms }); } else { return res.status(401).json({ message: 'unauthorized' }); } @@ -1254,10 +1258,9 @@ function startServer() { }); return cb('unauthorized'); } + } else { + if (!hostCfg.users_from_db) return cb('unauthorized'); } - // else { - // return cb('unauthorized'); - // } if (!hostCfg.users_from_db) { const roomAllowedForUser = isRoomAllowedForUser('[Join]', peer_name, room.id); @@ -2949,6 +2952,48 @@ function startServer() { return allowRoomAccess; } + async function getUserAllowedRooms(username, password) { + // Gel user allowed rooms from db... + if (hostCfg.protected && hostCfg.users_from_db && hostCfg.users_api_rooms_allowed) { + try { + // Using either email or username, as the username can also be an email here. + const response = await axios.post( + hostCfg.users_api_rooms_allowed, + { + email: username, + username: username, + password: password, + api_secret_key: hostCfg.users_api_secret_key, + }, + { + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) + }, + ); + const allowedRooms = response.data ? response.data.message : {}; + log.debug('AXIOS getUserAllowedRooms', allowedRooms); + return allowedRooms; + } catch (error) { + log.error('AXIOS getUserAllowedRooms error', error.message); + return {}; + } + } + + // Get allowed rooms for user from config.js file + if (hostCfg.protected && !hostCfg.users_from_db) { + const isOIDCEnabled = config.oidc && config.oidc.enabled; + + const user = hostCfg.users.find((user) => user.displayname === username || user.username === username); + + if (!isOIDCEnabled && !user) { + log.debug('getUserAllowedRooms - user not found', username); + return false; + } + return user.allowed_rooms; + } + + return ['*']; + } + async function isRoomAllowedForUser(message, username, room) { const logData = { message, username, room }; diff --git a/app/src/config.template.js b/app/src/config.template.js index be025fa3..019afb0f 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -174,8 +174,10 @@ module.exports = { users_from_db: false, // if true ensure that api.token is also set to true. users_api_endpoint: 'http://localhost:9000/api/v1/user/isAuth', users_api_room_allowed: 'http://localhost:9000/api/v1/user/isRoomAllowed', + users_api_rooms_allowed: 'http://localhost:9000/api/v1/user/roomsAllowed', //users_api_endpoint: 'https://webrtc.mirotalk.com/api/v1/user/isAuth', //users_api_room_allowed: 'https://webrtc.mirotalk.com/api/v1/user/isRoomAllowed', + //users_api_rooms_allowed: 'https://webrtc.mirotalk.com/api/v1/user/roomsAllowed', users_api_secret_key: 'mirotalkweb_default_secret', users: [ { diff --git a/package.json b/package.json index 9790914f..463c9ae6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.88", + "version": "1.5.89", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -73,11 +73,11 @@ "js-yaml": "^4.1.0", "jsdom": "^25.0.1", "jsonwebtoken": "^9.0.2", - "mediasoup": "3.14.15", + "mediasoup": "3.14.16", "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.67.3", + "openai": "^4.68.1", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/css/landing.css b/public/css/landing.css index bc673742..e8554337 100644 --- a/public/css/landing.css +++ b/public/css/landing.css @@ -2106,3 +2106,11 @@ main { /* #roomName { text-align: left; } */ + +/*-------------------------------------------------------------- +# Login and Join ROOM +--------------------------------------------------------------*/ + +#joinRoomForm { + display: none; +} diff --git a/public/js/Login.js b/public/js/Login.js index 312f6f90..faeace62 100644 --- a/public/js/Login.js +++ b/public/js/Login.js @@ -4,8 +4,13 @@ console.log(window.location); const usernameInput = document.getElementById('username'); const passwordInput = document.getElementById('password'); +const loginForm = document.getElementById('loginForm'); const loginBtn = document.getElementById('loginButton'); +const joinRoomForm = document.getElementById('joinRoomForm'); +const selectRoom = document.getElementById('selectRoom'); +const joinSelectRoomBtn = document.getElementById('joinSelectRoomButton'); + usernameInput.onkeyup = (e) => { if (e.keyCode === 13) { e.preventDefault(); @@ -23,6 +28,10 @@ loginBtn.onclick = (e) => { login(); }; +joinSelectRoomBtn.onclick = (e) => { + join(); +}; + function login() { const username = filterXSS(document.getElementById('username').value); const password = filterXSS(document.getElementById('password').value); @@ -50,6 +59,21 @@ function login() { const token = response.data.message; window.sessionStorage.peer_token = token; + // Allowed rooms + const allowedRooms = response.data.allowedRooms; + if (allowedRooms && !allowedRooms.includes('*')) { + console.log('User detected with limited join room access!', allowedRooms); + loginForm.style.display = 'none'; + joinRoomForm.style.display = 'block'; + allowedRooms.forEach((room) => { + const option = document.createElement('option'); + option.value = room; + option.text = room; + selectRoom.appendChild(option); + }); + return; + } + if (room) { return (window.location.href = '/join/' + window.location.search); // return (window.location.href = '/join/?room=' + room + '&token=' + token); @@ -80,3 +104,10 @@ function login() { return; } } + +function join() { + //window.location.href = '/join/' + selectRoom.value; + const username = filterXSS(document.getElementById('username').value); + const roomId = filterXSS(document.getElementById('selectRoom').value); + window.location.href = '/join/?room=' + roomId + '&name=' + username + '&token=' + window.sessionStorage.peer_token; +} diff --git a/public/js/Room.js b/public/js/Room.js index 4edf57f5..02fc6a3e 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.88 + * @version 1.5.89 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.88', + title: 'WebRTC SFU v1.5.89', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 83a98b0a..9a880485 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.88 + * @version 1.5.89 * */ diff --git a/public/views/login.html b/public/views/login.html index ac3e3529..72f8130a 100644 --- a/public/views/login.html +++ b/public/views/login.html @@ -42,6 +42,20 @@ + + + + + @@ -63,24 +77,7 @@ @@ -119,6 +116,25 @@

    + +
    +
    +

    + Pick name.
    + Share URL.
    + Start conference. +

    +
    +
    +
    + +
    +
    + +
    +
    @@ -143,11 +159,7 @@

  • Privacy Policy
  • +
  • + Rest API +
  • Contact: Privacy Policy
  • About
  • +
  • + Rest API +
  • Contact: Date: Sat, 19 Oct 2024 19:25:43 +0200 Subject: [PATCH 040/119] [mirotalksfu] - add whoAreYou and api_room_exists endpoint --- app/src/Server.js | 49 ++++++++- app/src/config.template.js | 2 + package.json | 2 +- public/js/Login.js | 2 +- public/js/Room.js | 4 +- public/js/RoomClient.js | 2 +- public/js/WhoAreYou.js | 17 +++ public/views/whoAreYou.html | 202 ++++++++++++++++++++++++++++++++++++ 8 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 public/js/WhoAreYou.js create mode 100755 public/views/whoAreYou.html diff --git a/app/src/Server.js b/app/src/Server.js index aaa8763e..760ffcc6 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.90 + * @version 1.5.91 * */ @@ -144,6 +144,7 @@ const hostCfg = { users_api_rooms_allowed: config.host.users_api_rooms_allowed, users_api_endpoint: config.host.users_api_endpoint, users_api_secret_key: config.host.users_api_secret_key, + api_room_exists: config.host.api_room_exists, users: config.host.users, authenticated: !config.host.protected, }; @@ -228,6 +229,7 @@ const views = { privacy: path.join(__dirname, '../../', 'public/views/privacy.html'), room: path.join(__dirname, '../../', 'public/views/Room.html'), rtmpStreamer: path.join(__dirname, '../../', 'public/views/RtmpStreamer.html'), + whoAreYou: path.join(__dirname, '../../', 'public/views/whoAreYou.html'), }; const authHost = new Host(); // Authenticated IP by Login @@ -550,7 +552,7 @@ function startServer() { }); // join room by id - app.get('/join/:roomId', (req, res) => { + app.get('/join/:roomId', async (req, res) => { // const { roomId } = req.params; @@ -567,8 +569,17 @@ function startServer() { const allowRoomAccess = isAllowedRoomAccess('/join/:roomId', req, hostCfg, roomList, roomId); if (allowRoomAccess) { + // Protect unauthorized room access... + if (!OIDC.enabled && hostCfg.protected && hostCfg.users_from_db) { + const roomExists = await roomExistsForUser(roomId); + return roomExists ? res.sendFile(views.room) : res.redirect('/login'); + } res.sendFile(views.room); } else { + // Who are you? + if (!OIDC.enabled && hostCfg.protected && hostCfg.users_from_db) { + return res.redirect('/whoAreYou/' + roomId); + } !OIDC.enabled && hostCfg.protected ? res.redirect('/login') : res.redirect('/'); } }); @@ -600,6 +611,11 @@ function startServer() { res.send(stats); }); + // handle who are you: Presenter or Guest + app.get(['/whoAreYou/:roomId'], (req, res) => { + res.sendFile(views.whoAreYou); + }); + // handle login if user_auth enabled app.get(['/login'], (req, res) => { res.sendFile(views.login); @@ -2952,6 +2968,31 @@ function startServer() { return allowRoomAccess; } + async function roomExistsForUser(room) { + if (hostCfg.protected || hostCfg.user_auth) { + // Check if passed room exists + if (hostCfg.users_from_db && hostCfg.api_room_exists) { + try { + const response = await axios.post( + hostCfg.api_room_exists, + { + room: room, + api_secret_key: hostCfg.users_api_secret_key, + }, + { + timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) + }, + ); + log.debug('AXIOS roomExistsForUser', { room: room, exists: true }); + return response.data && response.data.message === true; + } catch (error) { + log.error('AXIOS roomExistsForUser error', error.message); + return false; + } + } + } + } + async function getUserAllowedRooms(username, password) { // Gel user allowed rooms from db... if (hostCfg.protected && hostCfg.users_from_db && hostCfg.users_api_rooms_allowed) { @@ -3018,10 +3059,10 @@ function startServer() { timeout: 5000, // Timeout set to 5 seconds (5000 milliseconds) }, ); - + log.debug('AXIOS isRoomAllowedForUser', { room: room, allowed: true }); return response.data && response.data.message === true; } catch (error) { - log.error('AXIOS isRoomAllowedForUserDb error', error.message); + log.error('AXIOS isRoomAllowedForUser error', error.message); return false; } } diff --git a/app/src/config.template.js b/app/src/config.template.js index 019afb0f..909df2d6 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -175,9 +175,11 @@ module.exports = { users_api_endpoint: 'http://localhost:9000/api/v1/user/isAuth', users_api_room_allowed: 'http://localhost:9000/api/v1/user/isRoomAllowed', users_api_rooms_allowed: 'http://localhost:9000/api/v1/user/roomsAllowed', + api_room_exists: 'http://localhost:9000/api/v1/room/exists', //users_api_endpoint: 'https://webrtc.mirotalk.com/api/v1/user/isAuth', //users_api_room_allowed: 'https://webrtc.mirotalk.com/api/v1/user/isRoomAllowed', //users_api_rooms_allowed: 'https://webrtc.mirotalk.com/api/v1/user/roomsAllowed', + //api_room_exists: 'https://webrtc.mirotalk.com//api/v1/room/exists', users_api_secret_key: 'mirotalkweb_default_secret', users: [ { diff --git a/package.json b/package.json index 25e0a4ed..982044ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.90", + "version": "1.5.91", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Login.js b/public/js/Login.js index faeace62..1e273f65 100644 --- a/public/js/Login.js +++ b/public/js/Login.js @@ -44,7 +44,7 @@ function login() { // http://localhost:3010/join/test const pathParts = window.location.pathname.split('/'); - const roomPath = pathParts[pathParts.length - 1]; + const roomPath = filterXSS(pathParts[pathParts.length - 1]); if (username && password) { axios diff --git a/public/js/Room.js b/public/js/Room.js index 29632140..82885b02 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.90 + * @version 1.5.91 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.90', + title: 'WebRTC SFU v1.5.91', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 0b357966..4acc66e5 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.90 + * @version 1.5.91 * */ diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js new file mode 100644 index 00000000..73a1f175 --- /dev/null +++ b/public/js/WhoAreYou.js @@ -0,0 +1,17 @@ +'use strict'; + +console.log(window.location); + +const presenterLoginBtn = document.getElementById('presenterLoginButton'); +const guestJoinRoomBtn = document.getElementById('guestJoinRoomButton'); + +const pathParts = window.location.pathname.split('/'); +const roomPath = filterXSS(pathParts[pathParts.length - 1]); + +presenterLoginBtn.onclick = (e) => { + window.location.href = '/login'; +}; + +guestJoinRoomBtn.onclick = (e) => { + window.location.href = '/join/' + roomPath; +}; diff --git a/public/views/whoAreYou.html b/public/views/whoAreYou.html new file mode 100755 index 00000000..d7baf3dc --- /dev/null +++ b/public/views/whoAreYou.html @@ -0,0 +1,202 @@ + + + + + + MiroTalk SFU - Who are you. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b25d80fd7d575db99363c19220b40d96974ecfa1 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 19 Oct 2024 21:15:27 +0200 Subject: [PATCH 041/119] [mirotalksfu] - add missing --- app/src/Server.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/Server.js b/app/src/Server.js index 760ffcc6..3f30e0cb 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -139,6 +139,7 @@ const jwtCfg = { const hostCfg = { protected: config.host.protected, user_auth: config.host.user_auth, + users: config.host.users, users_from_db: config.host.users_from_db, users_api_room_allowed: config.host.users_api_room_allowed, users_api_rooms_allowed: config.host.users_api_rooms_allowed, @@ -569,11 +570,18 @@ function startServer() { const allowRoomAccess = isAllowedRoomAccess('/join/:roomId', req, hostCfg, roomList, roomId); if (allowRoomAccess) { - // Protect unauthorized room access... + // Protect unauthorized room access check from db... if (!OIDC.enabled && hostCfg.protected && hostCfg.users_from_db) { const roomExists = await roomExistsForUser(roomId); + log.debug('/join/:roomId exists from api endpoint', roomExists); return roomExists ? res.sendFile(views.room) : res.redirect('/login'); } + // Protect unauthorized room access check from config file... + if (!OIDC.enabled && hostCfg.protected && !hostCfg.users_from_db) { + const roomExists = hostCfg.users.some((user) => user.allowed_rooms.includes(roomId)); + log.debug('/join/:roomId exists from config allowed rooms', roomExists); + return roomExists ? res.sendFile(views.room) : res.redirect('/whoAreYou/' + roomId); + } res.sendFile(views.room); } else { // Who are you? From c1d9680f803edafabe5c8d928c768304fc8c3cd0 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 19 Oct 2024 21:55:47 +0200 Subject: [PATCH 042/119] [mirotalksfu] - logic improvements --- app/src/Server.js | 17 ++++++++--------- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 3f30e0cb..ebec6e84 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.91 + * @version 1.5.92 * */ @@ -570,25 +570,24 @@ function startServer() { const allowRoomAccess = isAllowedRoomAccess('/join/:roomId', req, hostCfg, roomList, roomId); if (allowRoomAccess) { - // Protect unauthorized room access check from db... + // 1. Protect room access with database check if (!OIDC.enabled && hostCfg.protected && hostCfg.users_from_db) { const roomExists = await roomExistsForUser(roomId); - log.debug('/join/:roomId exists from api endpoint', roomExists); + log.debug('/join/:roomId exists from API endpoint', roomExists); return roomExists ? res.sendFile(views.room) : res.redirect('/login'); } - // Protect unauthorized room access check from config file... + // 2. Protect room access with configuration check if (!OIDC.enabled && hostCfg.protected && !hostCfg.users_from_db) { - const roomExists = hostCfg.users.some((user) => user.allowed_rooms.includes(roomId)); + const roomExists = hostCfg.users.some(user => + user.allowed_rooms && user.allowed_rooms.includes(roomId) + ); log.debug('/join/:roomId exists from config allowed rooms', roomExists); return roomExists ? res.sendFile(views.room) : res.redirect('/whoAreYou/' + roomId); } res.sendFile(views.room); } else { // Who are you? - if (!OIDC.enabled && hostCfg.protected && hostCfg.users_from_db) { - return res.redirect('/whoAreYou/' + roomId); - } - !OIDC.enabled && hostCfg.protected ? res.redirect('/login') : res.redirect('/'); + !OIDC.enabled && hostCfg.protected ? res.redirect('/whoAreYou/' + roomId) : res.redirect('/'); } }); diff --git a/package.json b/package.json index 982044ca..eefaa210 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.91", + "version": "1.5.92", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index 82885b02..d6114091 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.91 + * @version 1.5.92 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.91', + title: 'WebRTC SFU v1.5.92', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 4acc66e5..cf79a00a 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.91 + * @version 1.5.92 * */ From b198ba80a8e712878438ee86a6ea7bfd6efcf46c Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 19 Oct 2024 22:34:39 +0200 Subject: [PATCH 043/119] [mirotalksfu] - improvements --- app/src/Server.js | 19 +++++++++++++------ package.json | 2 +- public/js/Common.js | 3 ++- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index ebec6e84..e60bdebe 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.92 + * @version 1.5.93 * */ @@ -511,7 +511,12 @@ function startServer() { if (isPeerPresenter && !hostCfg.users_from_db) { const roomAllowedForUser = await isRoomAllowedForUser('Direct Join with token', username, room); if (!roomAllowedForUser) { - return res.status(401).json({ message: 'Direct Room Join for this User is Unauthorized' }); + log.warn('Direct Room Join for this User is Unauthorized', { + username: username, + room: room, + }); + return res.redirect('/whoAreYou/' + room); + //return res.status(401).json({ message: 'Direct Room Join for this User is Unauthorized' }); } } } catch (err) { @@ -524,7 +529,9 @@ function startServer() { const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, roomList, room); const roomAllowedForUser = await isRoomAllowedForUser('Direct Join without token', name, room); if (!allowRoomAccess && !roomAllowedForUser) { - return res.status(401).json({ message: 'Direct Room Join Unauthorized' }); + log.warn('Direct Room Join Unauthorized', room); + return res.redirect('/whoAreYou/' + room); + //return res.status(401).json({ message: 'Direct Room Join Unauthorized' }); } } @@ -578,9 +585,9 @@ function startServer() { } // 2. Protect room access with configuration check if (!OIDC.enabled && hostCfg.protected && !hostCfg.users_from_db) { - const roomExists = hostCfg.users.some(user => - user.allowed_rooms && user.allowed_rooms.includes(roomId) - ); + const roomExists = hostCfg.users.some( + (user) => user.allowed_rooms && user.allowed_rooms.includes(roomId), + ); log.debug('/join/:roomId exists from config allowed rooms', roomExists); return roomExists ? res.sendFile(views.room) : res.redirect('/whoAreYou/' + roomId); } diff --git a/package.json b/package.json index eefaa210..4f0b6fa6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.92", + "version": "1.5.93", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Common.js b/public/js/Common.js index 383a2a7a..51cdf1a8 100644 --- a/public/js/Common.js +++ b/public/js/Common.js @@ -226,7 +226,8 @@ function joinRoom() { return; } - window.location.href = '/join/' + roomName; + //window.location.href = '/join/' + roomName; + window.location.href = '/join/?room=' + roomName; window.localStorage.lastRoom = roomName; } diff --git a/public/js/Room.js b/public/js/Room.js index d6114091..9cc470f3 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.92 + * @version 1.5.93 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.92', + title: 'WebRTC SFU v1.5.93', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index cf79a00a..fd36518c 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.92 + * @version 1.5.93 * */ From c0ed93740180780336531a8eed8af010742386c2 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sun, 20 Oct 2024 22:27:03 +0200 Subject: [PATCH 044/119] [mirotalksfu] - fix typo --- public/views/whoAreYou.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/views/whoAreYou.html b/public/views/whoAreYou.html index d7baf3dc..1f71179f 100755 --- a/public/views/whoAreYou.html +++ b/public/views/whoAreYou.html @@ -72,10 +72,10 @@

    -

    Who are you?

    +

    Who are you?

    - Please log in if you are the Presenter. Otherwise, kindly wait for the presenter to - join. + If you're the presenter, please log in now.
    + Otherwise, kindly wait for the presenter to join.

    LOGIN From 114943715df64dbcba1bfdc48707b237e1b54eb1 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sun, 20 Oct 2024 23:19:49 +0200 Subject: [PATCH 045/119] [mirotalksfu] - fix typo --- public/views/whoAreYou.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/views/whoAreYou.html b/public/views/whoAreYou.html index 1f71179f..86a34515 100755 --- a/public/views/whoAreYou.html +++ b/public/views/whoAreYou.html @@ -46,7 +46,6 @@ - @@ -72,7 +71,7 @@

    -

    Who are you?

    +

    Who are you?

    If you're the presenter, please log in now.
    Otherwise, kindly wait for the presenter to join. @@ -196,6 +195,7 @@

    Who are you?

    + From 7a6dca51a3669ddc7e82c665ab3e9de18cefc6f1 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 21 Oct 2024 02:00:28 +0200 Subject: [PATCH 046/119] [mirotalksfu] - improve whoAreYou logic --- app/src/Server.js | 14 +++++++++++++- package.json | 2 +- public/css/landing.css | 16 ++++++++++++++++ public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- public/js/WhoAreYou.js | 38 +++++++++++++++++++++++++++++++++---- public/views/whoAreYou.html | 7 ++++++- 7 files changed, 73 insertions(+), 10 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index e60bdebe..ecd4a3cf 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.93 + * @version 1.5.94 * */ @@ -468,6 +468,14 @@ function startServer() { } }); + // Check if room active (exists) + app.post(['/isRoomActive'], (req, res) => { + const { roomId } = checkXSS(req.body); + const roomActive = roomList.has(roomId); + if (roomActive) log.debug('isRoomActive', { roomId, roomActive }); + res.status(200).json({ message: roomActive }); + }); + // Handle Direct join room with params app.get('/join/', async (req, res) => { if (Object.keys(req.query).length > 0) { @@ -2937,6 +2945,10 @@ function startServer() { return payload; } + function isRoomActive(roomId) { + return roomList.has(roomId); + } + function getActiveRooms() { const roomIds = Array.from(roomList.keys()); const roomPeersArray = roomIds.map((roomId) => { diff --git a/package.json b/package.json index 4f0b6fa6..1007b823 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.93", + "version": "1.5.94", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/css/landing.css b/public/css/landing.css index e8554337..a651eee2 100644 --- a/public/css/landing.css +++ b/public/css/landing.css @@ -2114,3 +2114,19 @@ main { #joinRoomForm { display: none; } + +/*-------------------------------------------------------------- +# Who are you +--------------------------------------------------------------*/ + +#whoAreYouDiv { + display: inline-flex; +} +#roomActiveDiv { + display: none; +} + +.disabled { + pointer-events: none; + opacity: 0.5; +} diff --git a/public/js/Room.js b/public/js/Room.js index 9cc470f3..c511c384 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.93 + * @version 1.5.94 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.93', + title: 'WebRTC SFU v1.5.94', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index fd36518c..40edc76b 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.93 + * @version 1.5.94 * */ diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js index 73a1f175..f73a5ad3 100644 --- a/public/js/WhoAreYou.js +++ b/public/js/WhoAreYou.js @@ -2,16 +2,46 @@ console.log(window.location); +const autoJoinRoom = false; // automatically join the guest to the meeting + const presenterLoginBtn = document.getElementById('presenterLoginButton'); const guestJoinRoomBtn = document.getElementById('guestJoinRoomButton'); +guestJoinRoomBtn.classList.add('disabled'); + const pathParts = window.location.pathname.split('/'); -const roomPath = filterXSS(pathParts[pathParts.length - 1]); +const roomId = filterXSS(pathParts[pathParts.length - 1]); -presenterLoginBtn.onclick = (e) => { +presenterLoginBtn.onclick = () => { window.location.href = '/login'; }; -guestJoinRoomBtn.onclick = (e) => { - window.location.href = '/join/' + roomPath; +guestJoinRoomBtn.onclick = () => { + window.location.href = '/join/' + roomId; }; + +function checkRoomStatus(roomId) { + if (!roomId) { + console.warn('Room ID empty!'); + return; + } + axios + .post('/isRoomActive', { roomId }) + .then((response) => { + console.log('isRoomActive', response.data); + const roomActive = response.data.message; + if (roomActive) { + guestJoinRoomBtn.classList.remove('disabled'); + presenterLoginBtn.style.display = 'none'; + if (autoJoinRoom) guestJoinRoomBtn.click(); + } else { + guestJoinRoomBtn.classList.add('disabled'); + presenterLoginBtn.style.display = 'inline-flex'; + } + }) + .catch((error) => { + console.error('Error checking room status', error); + }); +} + +setInterval(() => checkRoomStatus(roomId), 5000); // Start checking room status every 5 seconds diff --git a/public/views/whoAreYou.html b/public/views/whoAreYou.html index 86a34515..dec468ba 100755 --- a/public/views/whoAreYou.html +++ b/public/views/whoAreYou.html @@ -51,6 +51,10 @@ + + + + @@ -74,7 +78,8 @@

    Who are you?

    If you're the presenter, please log in now.
    - Otherwise, kindly wait for the presenter to join. + Otherwise, kindly wait for the presenter to join.
    +

    LOGIN From b24a64dc8143c8e0165328e8b0c4147319d8566a Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 21 Oct 2024 02:13:25 +0200 Subject: [PATCH 047/119] [mirotalksfu] - fix typo --- app/src/Server.js | 15 ++++++++------- public/css/landing.css | 7 ------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index ecd4a3cf..47a7d4a8 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -471,9 +471,14 @@ function startServer() { // Check if room active (exists) app.post(['/isRoomActive'], (req, res) => { const { roomId } = checkXSS(req.body); - const roomActive = roomList.has(roomId); - if (roomActive) log.debug('isRoomActive', { roomId, roomActive }); - res.status(200).json({ message: roomActive }); + + if (roomId && (hostCfg.protected || hostCfg.user_auth)) { + const roomActive = roomList.has(roomId); + if (roomActive) log.debug('isRoomActive', { roomId, roomActive }); + res.status(200).json({ message: roomActive }); + } else { + res.status(400).json({ message: 'Unauthorized' }); + } }); // Handle Direct join room with params @@ -2945,10 +2950,6 @@ function startServer() { return payload; } - function isRoomActive(roomId) { - return roomList.has(roomId); - } - function getActiveRooms() { const roomIds = Array.from(roomList.keys()); const roomPeersArray = roomIds.map((roomId) => { diff --git a/public/css/landing.css b/public/css/landing.css index a651eee2..e31bf8bc 100644 --- a/public/css/landing.css +++ b/public/css/landing.css @@ -2119,13 +2119,6 @@ main { # Who are you --------------------------------------------------------------*/ -#whoAreYouDiv { - display: inline-flex; -} -#roomActiveDiv { - display: none; -} - .disabled { pointer-events: none; opacity: 0.5; From f6b9ba4a2f003d931d09e15b3c8adb73e84da22f Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 21 Oct 2024 09:46:04 +0200 Subject: [PATCH 048/119] [mirotalksfu] - add sound --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- public/js/WhoAreYou.js | 17 +++++++++++++++++ public/sounds/roomActive.wav | Bin 0 -> 32632 bytes public/sounds/roomDisactive.wav | Bin 0 -> 32718 bytes 7 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 public/sounds/roomActive.wav create mode 100644 public/sounds/roomDisactive.wav diff --git a/app/src/Server.js b/app/src/Server.js index 47a7d4a8..61c885ca 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.94 + * @version 1.5.95 * */ diff --git a/package.json b/package.json index 1007b823..d377750b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.94", + "version": "1.5.95", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index c511c384..f9840785 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.94 + * @version 1.5.95 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.94', + title: 'WebRTC SFU v1.5.95', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 40edc76b..8af1dcdf 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.94 + * @version 1.5.95 * */ diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js index f73a5ad3..87238eb6 100644 --- a/public/js/WhoAreYou.js +++ b/public/js/WhoAreYou.js @@ -2,6 +2,10 @@ console.log(window.location); +const settings = JSON.parse(localStorage.getItem('SFU_SETTINGS')); + +console.log('Settings', settings); + const autoJoinRoom = false; // automatically join the guest to the meeting const presenterLoginBtn = document.getElementById('presenterLoginButton'); @@ -20,6 +24,16 @@ guestJoinRoomBtn.onclick = () => { window.location.href = '/join/' + roomId; }; +function sound(name) { + if (!settings.sounds) return; + const sound = '../sounds/' + name + '.wav'; + const audio = new Audio(sound); + audio.volume = 0.5; + audio.play().catch((err) => { + return false; + }); +} + function checkRoomStatus(roomId) { if (!roomId) { console.warn('Room ID empty!'); @@ -31,6 +45,7 @@ function checkRoomStatus(roomId) { console.log('isRoomActive', response.data); const roomActive = response.data.message; if (roomActive) { + sound('roomActive'); guestJoinRoomBtn.classList.remove('disabled'); presenterLoginBtn.style.display = 'none'; if (autoJoinRoom) guestJoinRoomBtn.click(); @@ -44,4 +59,6 @@ function checkRoomStatus(roomId) { }); } +checkRoomStatus(roomId); + setInterval(() => checkRoomStatus(roomId), 5000); // Start checking room status every 5 seconds diff --git a/public/sounds/roomActive.wav b/public/sounds/roomActive.wav new file mode 100644 index 0000000000000000000000000000000000000000..a2dc0eda9772dbc75de6ed1c6769edceb2bd4c2d GIT binary patch literal 32632 zcmdT}J&z>IQeCickg&0^G0?-oM8e=oS9$`8_XPHn(DRTGyED^W-Bs09)n7BS_djz^ zL`GypR!#3*Jz&M;{@w5Y8r`4&<)?rB`FB74{x8w~?H`{1_z!>occ{Pl&6h9#`G;?R z_*-Z>ji^5?(=^Y^ay~EfbQ*@kVZYy%vfm$$<9I&5-oL;9^8Nk&eqWYxJREkrr{`}d zPfxpD-_P^)`igSDUoO)O4aa>)1^fN+aDw#x{{9BxxBKmUo~C~24!ive=v~+M)9G@) z-ynLsUgjCPkGt-9_w@4g{PNQ6hkia?mfPiaxxl;ebR71_m+qO;`@>-zmg#zVRq5+; zKF$5?PP_4Wca=X3V zVflW)UZ8#eu02pg6q=XuI=#+s%iDaPF5}eqhi<=nd47I*cFWUkxhY=VJN&{tDNY=`{Ao!=dXA`@TCJ&%^EX zI=#(mdB$`gl+S?tw0l16hHg5Zff|4&$%Ny};i>z&|GIzbXnTO|<$AuIZ}atZ>CcCG zcX}CL#@%>0fkxYK?0#jm=4l)O?AXD0f52?^m+^MGPxt9|x{Px_9*-RYvD@!D%n75h z!0u%}&j`k;AG=}Kzx2=j%K*3M@jS!s<$k%J@AGZE^vhxHrfxb+NRVYgB<{C2)Yl7A zjA_&l$NtcF<6$~3{dKsHuc!NX8z^|{`rYAW|Ga+&C}4*AVHuYZ=`|vEdt}&w^ZhKu z9=74ub-qs5@eFay^$xM#pUn23L_xq+N&eaXA1t-90TxKdg%T1xav5 zrXWY5;5Z%-io<+Zj+g${-%)Qp5(G|6|;Su;1L#NcR(T> zk9|K5r*S&Xr+JztarxApFr(9M-YJUe3Ehcn`EKA)L>NP96Bnh?}O_l3-9WJbh0Wi;;Yo;HjgLxz&=@FJA>fzE|y6gVBzw9o%^KQX3 zB0)PWAK>+h*z_nzOhJdt-D9>{VIPsj#4T_d6|M6@)XI!wNxupfVDe6GYg{h^aoIBGr%za2EBd6`?|s45$F*^@M#zF(bhzCLl;;8YH8Rmm^ek zm;Ggb-LV$bm`ZF09cP`GIrFGUHy|cvAl?)4B9+L2y(4zuwTkIPIt@r?#A=+dA1Gq^ z+b;mXDFQnY12a%F);$6$IfX+)EASd(x{G8imB=e@M-Ifm%uN89g=GiKw*eJv_l8_% zHY37<_qMyq7xCVo0fCz!qOF(#mxy%}z?mSJUuLPx3o6kwD}F zVw^`Te4GvH`bA@mzX%?{F!MmeoB%b>2*g?O5;3Mp#Sm!;Qwh`+?%q0t4?$#(12L+s zC~gDT_lX(PLBwx|x9)BKwtwBd?(VVf@2JFm5!A?US;<_-sMtAC74!5wJAGNZrR7=v?T5x5P%wJ)OB5uOw@u`5X*YwUW2o7#)`m(CwQ?+WSS((5Wr%L z$w}1Aa-A?i%w5DVpNYA@BgSvt`yO@2`c^Av0TrmRXfCp=;8epFs+frw`xj2&7a&&5 zUl*(2mM6sf8S$6h4KpKm1VkG7jZ=ych#89ztEyC-7*e^~dagSJ3#)KJW^&^jnA5V+ z>I9YTR+i(-)#?sg65PFD-{geVILm6n27kOC1atR&|I7ZD-7mZEsE!_}fxCO{?wmT= zRZciH6t(QwymL$e^Za%GAE{r_`i5M0)Os&E;eeN|n42%tls+g@oR6%I_l6q^&Xx(c zKHfxdw=mRP2-xm;#4ygNvf*A{P;uDEs^WRUm5-&tIAiBT1Cyrq95ry)Dv|Gy^O%!Y zp4UhhT%oav@azC;WH(U*^XcXEjQTWvL;Y%%nJ$Ljm*IEz(oY7EhEkR#+tq= zPPq$Ve;H8aM#g*nm8ZGfzVwiT+uYKLSt_){qTN#JHGa>dM^V%4jiJ^SQEA8wqia#oxWKme!BS)n6V3U zP3xJ(y^QB2BdmDu;~h6|TrYTyt(f&_=W$NdJj%ISpz7_Q{M9`~PfI!E^{kN9q;qVx zj)^qej8CwjJRPI)D!M$ zeCHTudD_Zdvh3j8PqCvS!obV72CtEZ8E+b{Y2LxGu9>35EVy_V!+ctmdy&MMRNnvO zV#B;jsA*01GF{ogeGtU`_u(B?FoOe_d9{#(7N`ZYFK{6DyG;&-L6Yr`Pn1 z{KtC$?*d-gW#(};@!gcC7Ge!QMvXBLg`~m2jhEdMD{(7o?A@%$Zp4{yN_nQ}m7SQ&T|v+4g1N+ajhU#4x$NMKv|N?=PR3J+ z+T~72yi(;-!E5`Gm>FrVCR|bU8DysxB7MLrE{MO6@2B?@Fb`PKe0AW65Y)I*;lRPV zEIXOJWnYd&jc7NB5o^R5uMm2L)qpAE(+rh6Di^6?<};z>wLA;?P~yA5FBiTA^NKFd zB0dG6RjMH_tDN!oT~l`uP8jbd$Q#6(>zaER_N;fT;_n0M2+WMLtY_}r#4P!ZolIX= zJ?`Ayu*Zv%Z%S0Wuz+u}JDKG6giOaSCo39v7+}ULi>NW}7C8DaUhx}@u4G-!*thve z;Dw4$LOE(VO()*Danj>f1jGe1G^5V8uW_Br^GHt$V&+}HV8$%-9w;XUZe{&j|6ULi zGZ9Oaff$%^O3QOW?*2Tp@W|~Q^MGGPa6>_r-C7ZUtC)FS$-5Gh#z^zIp`MKR6$EE7 zFk|m}#XtSUgl|82m=?^qI-}y}2Hasi%NS+35z2i}ZheB6zYg)N;GKZCKkgrzS8~+z zu3u1N&th~LWnktWhTExTHt!|C9M3E~Z4LDc)-*A557ie3*D+!&l{Yo+F99>6#oM>d z|AN~Ge(WIL`IYh3-%J=|xq-_2lMe>|+JLhTm^I4;v)uDApIZ4SVw4p#*As$-8RlDq zYe}v*qF49MJ9e#tn)`N-6S`p5C@W^3)I78B#ya9RMCNvhGBC@1bB9xzH#A2r_fY(* zf!#-=%(tatM%Ljp;;#vUc>-qsK2;w6d}*N4Q|34KG6Y&~Mnui*W@gKL7Svclb~nbC z>j_s9+dufi5sii#mR=1t5X-IPaOX=?GaFHsOC4_~cqrl51N@|g{KjunCCd7SCT>Pt z@8USS5OujP@K*&{&zyO|j7Uoa@UF*+ENdEwc~;=G(04}p6^?iXv%IQhZE;0&_Y%y^ zBK{`BR~%4#KX>rXrqX~)YKwe6w&X$j|%?q3#ZL9DptFYFm+SxKUa zsAc~KW<`CMy$dgER>T>R#v7=vW<`t#0}em?l}P8?bKCAl{A#w#DN^o7yu=!2ZY^AC z%gCM47*r@)pXU#{5?k``tt{yTrO=JMTw8tan2B-9#f@_EW*k8v}pC z;chJzzZ~!tt*B+QFHx4?$pkYT5oC@!#5o`in9E%s>pEkWSDn7^_`c=&ESP!gCTbj! zKrEQ$oyGH#^UJ+NPDhQc{MEkTXFq=K z(9BlMbYFf-j<|LMVbG$m|@!H z85R8Tfa^`x8olGr-C_pr;-Un}@oJO_ zfUb*Gu`5fn2rawC&nDKuq6?chp z*}-HBp#t53c*bga4uaZt?|8?S)g_TAvDVwa>|lHt*Yme*P!e(d-AvcC#96%7wG888 zwc1w9)L$|Qn1u&cBp-Ftr{6@4`J`sXnJbC8ML}*1h&B*woI#aE5;Ls0EpsZb+mPS9 z4eD+J3i7}sA&5()Js7-87q!;Wp1K%ok3kuuqq4`Dl6FMyn0ev1#w!Q z>YAWd#QaO&q}r?$lV-UhHq<6SMFDM`uDVwiL=A2`=mw6<|B1Y?e0Q(2SN9iW$1WdG9B zN-vj{M3#zK;5ueU{SdLm+5N}5_5g&-dqpf%cNB7((s&nnZU<$S4jFef;fmBtgPAa6 zuqj|JC1VzAbwUbHvLTw(Sas78)3JyeZadA@IAVDMe-iatO+oC-Sf7cCyuqv8fSFez zbpwOun9=Pk092Lvz+;&-lJSC3#m?GXhr30o095L46wVH8WMDoB%V6w zimqxjwDQGpE>z%-c{DZ645gls*0XF=z16OrT4LE%YWkZu0XL>nHiqJ^dKFQxlG>e8 z3xsSzPPPH57TeGqwNVYVEIeXU^=>4%Dl{sv*$#Gzp9Qpx*+xMrsw8cjPyMaS#ipc(A%!^LB20#a0iQ9#`l5VQFbW}Bl zsIN*{9_WZ0k_N_#69sdKxM`rgw8dCxs_`%yj8*~lNBV}>H&u70qJDrm*!!Rv9B{A8 zn42;laVDXL6POL7+c)8hc8y{EC086(+&)rWX<9B6%{*v}M(A)k$xqAfkW`hUgdpRV z8~~5cS>u09JX4i1RVOn&OlO1Dy5@UaNT#D|t*t@}sB?Z-)TUX!;%-E(c^_m~m@8_v zS*FfYWaX2pbh^kJOnmFkrk;syS7Ml}RU=gjl~ERwwgE`L8cCRCZ9l{eX;Bcwvek-N zBWYC2?@CuaLZ{YJxURJnzct5<&Fxmb+R9#W%n-|V8!S`+oKI0$HxpgaaFXYo)2l

    2}{xyH;szs21^u z#2}QRdT-kW9gVJAJMahp+>Wu?H?TX;!!aoRG~*9g9b?;gWWgMd-@qR*i}lE+?ZEsw zAoT9jLZ69t3%B$i+js~hqHY-e5JCu3P7w)yxJX8Q@v)CI(!i*xnKRaAHda~eRW zyh^ITM$0hAw+B&g;Wfmf#sbQ>R(a)Y_V`eVfOW2+>*%JAz@x2}5sfwc|HE*7k>QQJt3^kc+Zv%i6ut_Hh5jC5x9 z-WFnxeH3XI47Ls7)^`ha5N*^|Zw&FqK^DZfET*wWzlv5Xxg|FL7qv34(_l@HqHX85+2YJZIyVpfvlA6QGn6?YO1o^U)CV8*=1k<>0~l9BCBW8-6$ z)Zd~OVKbaukH+k`$~eaMXHc7R{i^+DDk2Mf2*t34A#WNjL4c}uqPc&E3=d*v*Kxb< z2Mt--en)Z9ptf~@_ML1t^Ecab<~%IDN{bpyzmLg^a@0X6riVyv*w`2%YBTcD*Ns~v zGTK=9f*eb9GLExdXhB$;4WXir%A{RITirkEuT+`QIF(g>Vh_V?x@5Ik$Jok6XpM@b zMulY`an)I&Nw0KgOIy80Q88e4OtF1!T)#GoZz7nTJjz}uK{z&(qP2o%q*@M|Kh`WNXk?l!HlY0p#y@iO#S%&7cE#c|x* zkzu19Y=5??HkCWrcZ<2PVUt3khz=9lW;ZIonIlp{J2RzTu>81bmRc?w59Vr+iraKcDz_e|NGgHF$6YUN#}a*suV!NU9vgi?vlBsknVeg`)BbDvzdKu~iioYSmj>b^2T+@Fbl< z8Cj&;Fa%LoN4|%p(JQlVLD6Ke3u0I^+6F!*sXfANEaPZN({DA##1f z1>rCsPP177vEgv`4YMB&xrLw~O;?qNANPt-Ybq$qBq0QqiYTBCG&V(lQBjl%M;y-< zKJK-)P5s8W*m(5E{0`QNdt07?l*Pxe`*HbzmejKI z05hqnB<4iXPEamtoh1<3CKr!;PO6S-Hg;8bQ zCc7FjRc*W0PdBQpwjk(3YulB^mJ}aanQZ8FR@QoLM3q@Df8CJy2U;0e+5O>wN!nKg zN+;XYUbI~3AK8YM%wec2!5BXC-Lm{ccpD6c)V_gb)3FV^>TVFM&4eV1YCDmC+=&W` zQM&!Bi($2IRIu%ZS}71_3+=2+u^tt; zLy5bNS}T!1?rgE!7`~q_hE=~=%xS?5vyq0-vGHg-4x(MUA{p4@aM0Q`t3W1{@$C4+ zUiPYGP1NLSwu@dBRU!0~G+qN;s@iJC48wb7*O7^N{%vAGPHAl;ACs`2` z4tK-oAm!p5RI#EK-pcfWu&R#^o5AKAS+dg}Bbq1%T{xSSp0GGWg4L4P&jlm3tf=4> z73J?rG*Oka@KmLtmDvM9nwc8?YMm}#nF0ugB5oLo-%M63mEKTAQN)~dgBoZlQ0hU| zYpp1dFbPAZCi=>;VwrM9ETcAy&Jf5Hh$WJW=gE~!H+%6LIHF={CsiL&eJT?}P|Ieq zXe{VA#VGP^$Svlzu<0+~s5@e{cA_WCA*c$I3PqA5PN zbQcJgg(t`gPoTpsFKhWMUFb<#I?<6tUCBS77EpzwsC3`hNW$i)#wcIm1l5aET}PB9 zTa{B587T5a+GW{zq&?C;&>Vad4%e-Yn1&B5xAAo8O}{cVS>CiAQ3u%^&4MdLMLdtP zEiKI%W{kD(w~@7*SwaFx|PjAqmez6ZX}ZsQt+rW^H9bwffoQde#_ zEcP4-lrDUE8!b*m2zhfviwp(k<+xv?tqX>*2el10ZY ztDc5jEW3^Do=mXQwotq0YA9&06m12Pc~y*o-Y^G~(yWXkn&h)y_8Mgk!vkt-)>x_1 ziw(+97$-xeY0HJAk*Ktl^rDkWQI=E`4HRWfC23C-b~4pPWjL8N-7Ec~(gm{t4x3;E zCF5qBPD@GN=ur73kAP5=M^ literal 0 HcmV?d00001 diff --git a/public/sounds/roomDisactive.wav b/public/sounds/roomDisactive.wav new file mode 100644 index 0000000000000000000000000000000000000000..9d1f0e03f462d293585bed328f72e46e8c0a458b GIT binary patch literal 32718 zcmeI1O^@Ta5r&Yso9$6tQ<_vhdJX0=-VV)e^a z^Cz4fRyh0B>f4Xseg9ire*Ei)zkU4f!}q_&`L~~*fB54cevkgmH>=gZK7IbwK&8=k zY_uP_$(5Y@U)&sNUV+A#i&N8{&h4eWp0DSZ%l&e{zM|i+FPGc-(wY3G46N(#92SsG%e7(Fxdhind zQf?5*lPVte`wHG{sx>?lHTIGeBWhAa410=qWJnKugxV}Zx>2ZByrMcRX^%C?beyS+d7<_~xYm%p=jjIY(s?2W1oG!cuNyT*` zru9M%3+r?|)#wN6E&BOzt}pfVcs<@4^b>k}MOk0a`G*v^pRT7%b7{`U7So&ku{vy} zq&H9N&+E_6u0K6Luh;9%X1lFiC6a?}d%j$**W1g>{r>v;`u6tz{zdxRm$xsk@AtPC zEFCJ!)43rN$9*m9a9eG*=+xHKw-97B4LWZ`&&<6!Y{6X}cg?=pBbhZ4 zd*lRDq6z&>9SNgOwBV)eBEQ_Zly8?CGka=O5Hq(f%eocPwg3;F)=$sq+JLOgRkhRV zhVAxzMxHg%ZWlMC zrcQMeQ&(H=ut%M@a>V^mff-pIV8&Zls+(6dF-vzD=i>?K>Auec9pdM(h)71hn(J$S!Tt|i;T zjhBvW=int`Fz>+(zZ%-2;}s3NvWwvt%(|E1=&IdN1C$#PJ7x|)58#>%;t7a!+< z)*Uw{R%ZUv!DpU)j&ZJO2N!N)l`h1>j2DeE%iGma?@&6S^Xm&Qun}g-w54tXGpK!+ zeNIqYG$odB(VmD%a;AkEA0_xKp-&yDJtUYLr3U*peJ|Eh-JEHvAl@NC?Ya4!woKkW z=;g}H`h^RPJsJt3DK%N;S2i&t1L&M*WSV@Go!c=Z-l3ydsdL7=)c62(jkkQ6#(G$4 zpr)57y+&yl7jF0yfZ<1nf9*Bk6=Q++a=h`zP<7sC8kO47wcaW*dEYuWb`SZ&8;*W}~%#>;Q z2=&zbZg9-BYohZ~;yn9I^Ivd?oo1V4xqxWlu=SYPSGUVFs0}m4GU5(-rZb1idp`Xr zGymo3GL4rgQX{-_aSJq;T9R6JPKq@#hfMRTMul_pmI5~U-P(5j`8=NcFHq#*kbC48{TN6B%{f{W2k*-f{Giz2!%BK zN`09Cvmp_3x;QesR2hEZg>cj0K<%JSrYWAo-A2YubiBNwiX&o2sU5u>#mPX7MDv>F zO5<4a>Jj+xt1F8BT$L_CM$~8**TxpGY&tzq8*b;l<}kslmE~-@NjL^-*}J>Bh7WOb zPMS=^wh$|4oNL@*xGhMRszw?|25!&Tyw226z4T9dpnt__u)7UFb6BvdPK~dHZcpbt8G`=y-XWsu5Br; zM4rWxu`N}HU!N7@HQAh`v?I)1rzegOx3Su(Z9LI7!rZHESKXePCp)E(XBXXI-)AAL z!Qi>&nLZEm=*;VR3q5Y{g?BV&b}L$UZ%wy5NNsCY#9&O_iL$e1{P8}j zt~hHJGdg$7`e7oL9X5_aYIv2I?Xfvkh*YBs=K~RsG7G~nxjY;Gjj5x2cauSm1!Qu^ zHv`>2<$UN+nDdPmQoqH-8O+{^>=Vx%J7X++w7CPWs4_hXLm3+eEDxyJ{%x zI@wIq1Ba+P`BqO1u5-x9Gg}|oW|>CYOtT8oO$j%&bncsBHic#E_D&s8??JfXhUn27 z%Q=BVQ8Q~RdWV`pJ!Y{JGe@=!wb4nP#yF`_Ml<11SxyO`^ z`7+TwB~Ka|91TpG9(pkC#DH0to6&NKBM38TzyZ0{n=sd@q;ldxKDTk-d1*A=t*N7# zGJF~d%%IoJW>|FOZe(wOF?yci&w#{;_4tvum0`yXVSBMm#+A1;;BN1kGnG8{L^3>} zA;wZtJAPoMWZLj{Vxj((k@kM|NBKv+;gkM!rVeNi-BLS~>d^q0%5FUn=O+~1>F_Z! z*}v#a%65oXa$j!zjvC80(m@*+_k$;f(PKlM?Tie}5RZqjsaZz6cd=0Um7x{wS?-j6 zht4wMnJ2$ZGQ$ut&vJzZXBx4?V6dPux0NY9e~kAhW7a&EQg-J>)TBMLb@ei?+2jl} z`IX&;8F8jNbcR0|3YX?K%$d~;^@On=ical$I5;rdDOT-iPTY8adO}$q=OIP0>`lpt zfEUPe$`2}{_p`@OJjR6k-gTOgY!f2%n1zx8-3J+hZpfHlJz2qVQwNSRApJWqMQ)iX zU8|$lNx{?uH8d(39{M~R|2UDu5A<%zc65K9BhIBrBJZNmkR{GDG(5_AKL0qZmvMK# zDVf3P%g|2^LC79xuwK|WRfU!xWhR#kP4l!;>PMId{=cj!@;^PdF3JMKoM)Q;6&hp; zn|d+RhliumY~l%X7e-qDkszTw?{=vR^Q^eh#n!Y;oX&&C;#AMKTV~3y z=)nC|R(H|jo()~bEVa=irw9}^4qZ{fm08qO6*K;)O zwAA^e4i8Ap9=M+;NTUWOCvFYpbJ$KopnH3Ga(ov_$!YPV^i`&un#|3z*fRy|*S)#d zt@a$OXp9#~y;mODP0HewqT>Cn$+y$MfK`QiyL-m*sg_il1 zQf!&2i!IBOf3z%Ox53!Lhe5@wr3ZXX1OTN<*eeSA?`yZ?ikj`>M9aq zPZAcxZ9ipZlntksfT}we1Cjyy#eHsm01r%k!p-!>4foa#M4J@``SwAr*1!N7ZEGTHcxse z+HP_$>QN|o)Ps3-mVO4uB@#b_BrXU`1eORa5m+LyL|}=)5`iTGO9Yk(ED=~DutZ>q zz!HHa0!svz2rLm;BCteYiNF$pB?3zXmIy2nSR$}QV2QvIfh7V<1eORa5m+Md{}h4$ E0*|<=W&i*H literal 0 HcmV?d00001 From 12fad5668dcf9a1d24b588ece24a4d1e2034c383 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 21 Oct 2024 14:01:06 +0200 Subject: [PATCH 049/119] [mirotalksfu] - fix UI --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- public/js/WhoAreYou.js | 17 +++++++++++++++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 61c885ca..4926a618 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.95 + * @version 1.5.96 * */ diff --git a/package.json b/package.json index d377750b..68b0f349 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.95", + "version": "1.5.96", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index f9840785..033b4e92 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.95 + * @version 1.5.96 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.95', + title: 'WebRTC SFU v1.5.96', html: `

    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 8af1dcdf..a3ed78d8 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.95 + * @version 1.5.96 * */ diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js index 87238eb6..5e12de1a 100644 --- a/public/js/WhoAreYou.js +++ b/public/js/WhoAreYou.js @@ -2,6 +2,8 @@ console.log(window.location); +const mediaQuery = window.matchMedia('(max-width: 640px)'); + const settings = JSON.parse(localStorage.getItem('SFU_SETTINGS')); console.log('Settings', settings); @@ -16,6 +18,8 @@ guestJoinRoomBtn.classList.add('disabled'); const pathParts = window.location.pathname.split('/'); const roomId = filterXSS(pathParts[pathParts.length - 1]); +let roomActive = false; + presenterLoginBtn.onclick = () => { window.location.href = '/login'; }; @@ -34,6 +38,11 @@ function sound(name) { }); } +function handleScreenResize(e) { + if (roomActive) return; + presenterLoginBtn.style.display = e.matches ? 'flex' : 'inline-flex'; +} + function checkRoomStatus(roomId) { if (!roomId) { console.warn('Room ID empty!'); @@ -43,7 +52,7 @@ function checkRoomStatus(roomId) { .post('/isRoomActive', { roomId }) .then((response) => { console.log('isRoomActive', response.data); - const roomActive = response.data.message; + roomActive = response.data.message; if (roomActive) { sound('roomActive'); guestJoinRoomBtn.classList.remove('disabled'); @@ -51,7 +60,7 @@ function checkRoomStatus(roomId) { if (autoJoinRoom) guestJoinRoomBtn.click(); } else { guestJoinRoomBtn.classList.add('disabled'); - presenterLoginBtn.style.display = 'inline-flex'; + handleScreenResize(mediaQuery); } }) .catch((error) => { @@ -59,6 +68,10 @@ function checkRoomStatus(roomId) { }); } +handleScreenResize(mediaQuery); + checkRoomStatus(roomId); +mediaQuery.addEventListener('change', handleScreenResize); + setInterval(() => checkRoomStatus(roomId), 5000); // Start checking room status every 5 seconds From 6d54f0df0989888a84a9b2c07f30c13cffb42056 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 21 Oct 2024 14:38:46 +0200 Subject: [PATCH 050/119] [mirotalksfu] - improvements for mobile --- public/js/WhoAreYou.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js index 5e12de1a..227a5991 100644 --- a/public/js/WhoAreYou.js +++ b/public/js/WhoAreYou.js @@ -10,6 +10,8 @@ console.log('Settings', settings); const autoJoinRoom = false; // automatically join the guest to the meeting +const intervalTime = 5000; // check room status every 5 seconds + const presenterLoginBtn = document.getElementById('presenterLoginButton'); const guestJoinRoomBtn = document.getElementById('guestJoinRoomButton'); @@ -18,6 +20,7 @@ guestJoinRoomBtn.classList.add('disabled'); const pathParts = window.location.pathname.split('/'); const roomId = filterXSS(pathParts[pathParts.length - 1]); +let intervalId; let roomActive = false; presenterLoginBtn.onclick = () => { @@ -74,4 +77,36 @@ checkRoomStatus(roomId); mediaQuery.addEventListener('change', handleScreenResize); -setInterval(() => checkRoomStatus(roomId), 5000); // Start checking room status every 5 seconds +function startCheckingRoomStatus() { + // Function to run every 5 seconds + intervalId = setInterval(() => { + if (document.visibilityState === 'visible') { + checkRoomStatus(roomId); + } + }, intervalTime); +} + +// Fallback to setTimeout if needed for better control +function fallbackCheckRoomStatus() { + if (document.visibilityState === 'visible') { + checkRoomStatus(roomId); + } + setTimeout(fallbackCheckRoomStatus, intervalTime); +} + +// Use Page Visibility API to pause/resume the checks +document.addEventListener('visibilitychange', () => { + checkRoomStatus(roomId); + // + if (document.visibilityState === 'visible') { + console.log('Page is visible. Resuming room status checks.'); + if (!intervalId) startCheckingRoomStatus(); + } else { + console.log('Page is hidden. Pausing room status checks.'); + clearInterval(intervalId); + intervalId = null; + } +}); + +// Start checking room status when the page is first loaded +startCheckingRoomStatus(); From dbfb374bf5d2928af2954bc9853ce84e6ddf8300 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 21 Oct 2024 14:52:25 +0200 Subject: [PATCH 051/119] [mirotalksfu] - refactoring --- public/js/WhoAreYou.js | 123 ++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js index 227a5991..a0933dc8 100644 --- a/public/js/WhoAreYou.js +++ b/public/js/WhoAreYou.js @@ -4,81 +4,86 @@ console.log(window.location); const mediaQuery = window.matchMedia('(max-width: 640px)'); -const settings = JSON.parse(localStorage.getItem('SFU_SETTINGS')); +const settings = JSON.parse(localStorage.getItem('SFU_SETTINGS')) || {}; +console.log('Settings:', settings); -console.log('Settings', settings); - -const autoJoinRoom = false; // automatically join the guest to the meeting - -const intervalTime = 5000; // check room status every 5 seconds +const autoJoinRoom = false; // Automatically join the guest to the meeting +const intervalTime = 5000; // Interval to check room status const presenterLoginBtn = document.getElementById('presenterLoginButton'); const guestJoinRoomBtn = document.getElementById('guestJoinRoomButton'); +// Disable the guest join button initially guestJoinRoomBtn.classList.add('disabled'); +// Extract room ID from URL path using XSS filtering const pathParts = window.location.pathname.split('/'); const roomId = filterXSS(pathParts[pathParts.length - 1]); -let intervalId; +let intervalId = null; let roomActive = false; -presenterLoginBtn.onclick = () => { +// Button event handlers +presenterLoginBtn.addEventListener('click', () => { window.location.href = '/login'; -}; +}); -guestJoinRoomBtn.onclick = () => { - window.location.href = '/join/' + roomId; -}; +guestJoinRoomBtn.addEventListener('click', () => { + window.location.href = `/join/${roomId}`; +}); -function sound(name) { +// Function to play sound +function playSound(name) { if (!settings.sounds) return; - const sound = '../sounds/' + name + '.wav'; - const audio = new Audio(sound); + + const soundSrc = `../sounds/${name}.wav`; + const audio = new Audio(soundSrc); audio.volume = 0.5; + audio.play().catch((err) => { - return false; + console.error(`Error playing sound: ${err}`); }); } +// Handle screen resize to adjust presenter login button visibility function handleScreenResize(e) { - if (roomActive) return; - presenterLoginBtn.style.display = e.matches ? 'flex' : 'inline-flex'; + if (!roomActive) { + presenterLoginBtn.style.display = e.matches ? 'flex' : 'inline-flex'; + } } -function checkRoomStatus(roomId) { +// Function to check room status from the server +async function checkRoomStatus(roomId) { if (!roomId) { - console.warn('Room ID empty!'); + console.warn('Room ID is empty!'); return; } - axios - .post('/isRoomActive', { roomId }) - .then((response) => { - console.log('isRoomActive', response.data); - roomActive = response.data.message; - if (roomActive) { - sound('roomActive'); - guestJoinRoomBtn.classList.remove('disabled'); - presenterLoginBtn.style.display = 'none'; - if (autoJoinRoom) guestJoinRoomBtn.click(); - } else { - guestJoinRoomBtn.classList.add('disabled'); - handleScreenResize(mediaQuery); + + try { + const response = await axios.post('/isRoomActive', { roomId }); + const isActive = response.data.message; + console.log('Room active status:', isActive); + + roomActive = isActive; + if (roomActive) { + playSound('roomActive'); + guestJoinRoomBtn.classList.remove('disabled'); + presenterLoginBtn.style.display = 'none'; + + if (autoJoinRoom) { + guestJoinRoomBtn.click(); } - }) - .catch((error) => { - console.error('Error checking room status', error); - }); + } else { + guestJoinRoomBtn.classList.add('disabled'); + handleScreenResize(mediaQuery); + } + } catch (error) { + console.error('Error checking room status:', error); + } } -handleScreenResize(mediaQuery); - -checkRoomStatus(roomId); - -mediaQuery.addEventListener('change', handleScreenResize); - -function startCheckingRoomStatus() { - // Function to run every 5 seconds +// Start interval to check room status every 5 seconds +function startRoomStatusCheck() { intervalId = setInterval(() => { if (document.visibilityState === 'visible') { checkRoomStatus(roomId); @@ -86,27 +91,33 @@ function startCheckingRoomStatus() { }, intervalTime); } -// Fallback to setTimeout if needed for better control -function fallbackCheckRoomStatus() { +// Fallback to setTimeout for room status checks +function fallbackRoomStatusCheck() { if (document.visibilityState === 'visible') { checkRoomStatus(roomId); } - setTimeout(fallbackCheckRoomStatus, intervalTime); + setTimeout(fallbackRoomStatusCheck, intervalTime); } -// Use Page Visibility API to pause/resume the checks -document.addEventListener('visibilitychange', () => { - checkRoomStatus(roomId); - // +// Page visibility change handler to pause or resume status checks +function handleVisibilityChange() { if (document.visibilityState === 'visible') { console.log('Page is visible. Resuming room status checks.'); - if (!intervalId) startCheckingRoomStatus(); + checkRoomStatus(roomId); + if (!intervalId) startRoomStatusCheck(); } else { console.log('Page is hidden. Pausing room status checks.'); clearInterval(intervalId); intervalId = null; } -}); +} + +// Initialize event listeners +mediaQuery.addEventListener('change', handleScreenResize); +document.addEventListener('visibilitychange', handleVisibilityChange); + +// Start checking room status on page load +handleScreenResize(mediaQuery); +checkRoomStatus(roomId); +startRoomStatusCheck(); -// Start checking room status when the page is first loaded -startCheckingRoomStatus(); From 4a3df0c7c91b745e52caee4719a4f1bf9b1234fa Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Tue, 22 Oct 2024 12:39:11 +0200 Subject: [PATCH 052/119] [mirotalksfu] - fix chat --- app/src/Server.js | 2 +- package.json | 4 ++-- public/js/Room.js | 10 +++++----- public/js/RoomClient.js | 2 +- public/js/WhoAreYou.js | 9 ++++----- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 4926a618..6bbddcfa 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.96 + * @version 1.5.97 * */ diff --git a/package.json b/package.json index 68b0f349..1ac41c3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.96", + "version": "1.5.97", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,7 +57,7 @@ "node": ">=18" }, "dependencies": { - "@sentry/node": "^8.34.0", + "@sentry/node": "^8.35.0", "axios": "^1.7.7", "body-parser": "1.20.3", "colors": "1.4.0", diff --git a/public/js/Room.js b/public/js/Room.js index 033b4e92..dd11ae56 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.96 + * @version 1.5.97 * */ @@ -3932,7 +3932,7 @@ function getParticipantsList(peers) { // CHAT-GPT if (chatGPT) { - const chatgpt_active = rc.chatPeerName === 'ChatGPT' ? ' active' : ''; + const chatgpt_active = !rc.isChatOpen && rc.chatPeerName === 'ChatGPT' ? ' active' : ''; li = `
  • `; } - const public_chat_active = rc.chatPeerName === 'all' ? ' active' : ''; + const public_chat_active = !rc.isChatOpen && rc.chatPeerName === 'all' ? ' active' : ''; // ALL li += ` @@ -4036,7 +4036,7 @@ function getParticipantsList(peers) { const peer_id = peer_info.peer_id; const avatarImg = getParticipantAvatar(peer_name); - const peer_chat_active = rc.chatPeerId === peer_id ? ' active' : ''; + const peer_chat_active = !rc.isChatOpen && rc.chatPeerId === peer_id ? ' active' : ''; // NOT ME if (socket.id !== peer_id) { @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.96', + title: 'WebRTC SFU v1.5.97', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a3ed78d8..5a78b46f 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.96 + * @version 1.5.97 * */ diff --git a/public/js/WhoAreYou.js b/public/js/WhoAreYou.js index a0933dc8..29ffdfa2 100644 --- a/public/js/WhoAreYou.js +++ b/public/js/WhoAreYou.js @@ -35,11 +35,11 @@ guestJoinRoomBtn.addEventListener('click', () => { // Function to play sound function playSound(name) { if (!settings.sounds) return; - + const soundSrc = `../sounds/${name}.wav`; const audio = new Audio(soundSrc); audio.volume = 0.5; - + audio.play().catch((err) => { console.error(`Error playing sound: ${err}`); }); @@ -63,13 +63,13 @@ async function checkRoomStatus(roomId) { const response = await axios.post('/isRoomActive', { roomId }); const isActive = response.data.message; console.log('Room active status:', isActive); - + roomActive = isActive; if (roomActive) { playSound('roomActive'); guestJoinRoomBtn.classList.remove('disabled'); presenterLoginBtn.style.display = 'none'; - + if (autoJoinRoom) { guestJoinRoomBtn.click(); } @@ -120,4 +120,3 @@ document.addEventListener('visibilitychange', handleVisibilityChange); handleScreenResize(mediaQuery); checkRoomStatus(roomId); startRoomStatusCheck(); - From 60a1e383b74128250deb62049ba9a4a0a3ba54a2 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 24 Oct 2024 00:05:42 +0200 Subject: [PATCH 053/119] [mirotalksfu] - server refactoring --- app/src/Server.js | 152 +++++++++++++++++++--------------------- package.json | 4 +- public/js/Room.js | 4 +- public/js/RoomClient.js | 2 +- 4 files changed, 76 insertions(+), 86 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 6bbddcfa..e0bbcaee 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.97 + * @version 1.5.98 * */ @@ -1419,9 +1419,12 @@ function startServer() { return callback({ error: 'Room not found' }); } - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); + + const { peer_name } = peer || 'undefined'; + + log.debug('Get RouterRtpCapabilities', peer_name); - log.debug('Get RouterRtpCapabilities', getPeerName(room)); try { const getRouterRtpCapabilities = room.getRtpCapabilities(); @@ -1441,9 +1444,11 @@ function startServer() { return callback({ error: 'Room not found' }); } - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); + + const { peer_name } = peer || 'undefined'; - log.debug('Create WebRtc transport', getPeerName(room)); + log.debug('Create WebRtc transport', peer_name); try { const createWebRtcTransport = await room.createWebRtcTransport(socket.id); @@ -1464,9 +1469,9 @@ function startServer() { return callback({ error: 'Room not found' }); } - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); - const peer_name = getPeerName(room, false); + const { peer_name } = peer || 'undefined'; log.debug('Connect transport', { peer_name: peer_name, transport_id: transport_id }); @@ -1489,11 +1494,13 @@ function startServer() { return callback({ error: 'Room not found' }); } - const room = roomList.get(socket.room_id); + const { peer } = getRoomAndPeer(socket); - const peer = room.getPeer(socket.id); + if (!peer) { + return callback({ error: 'Peer not found' }); + } - const peer_name = getPeerName(room, false); + const { peer_name } = peer || 'undefined'; log.debug('Restart ICE', { peer_name: peer_name, transport_id: transport_id }); @@ -1522,9 +1529,13 @@ function startServer() { return callback({ error: 'Room not found' }); } - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); + + if (!peer) { + return callback({ error: 'Peer not found' }); + } - const peer_name = getPeerName(room, false); + const { peer_name } = peer || 'undefined'; // peer_info.audio OR video ON const data = { @@ -1536,8 +1547,6 @@ function startServer() { status: true, }; - const peer = room.getPeer(socket.id); - peer.updatePeerInfo(data); try { @@ -1581,9 +1590,9 @@ function startServer() { return callback({ error: 'Room not found' }); } - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); - const peer_name = getPeerName(room, false); + const { peer_name } = peer || 'undefined'; try { const params = await room.consume(socket.id, consumerTransportId, producerId, rtpCapabilities); @@ -1608,9 +1617,9 @@ function startServer() { socket.on('producerClosed', (data) => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); - const peer = room.getPeer(socket.id); + if (!peer) return; peer.updatePeerInfo(data); // peer_info.audio OR video OFF @@ -1620,22 +1629,18 @@ function startServer() { socket.on('pauseProducer', async ({ producer_id }, callback) => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); - - const peer_name = getPeerName(room, false); - - const peer = room.getPeer(socket.id); + const { peer } = getRoomAndPeer(socket); if (!peer) { return callback({ - error: `peer with ID: ${socket.id} for producer with id "${producer_id}" not found`, + error: `Peer with ID: ${socket.id} for producer with id "${producer_id}" not found`, }); } const producer = peer.getProducer(producer_id); if (!producer) { - return callback({ error: `producer with id "${producer_id}" not found` }); + return callback({ error: `Producer with id "${producer_id}" not found` }); } try { @@ -1644,6 +1649,8 @@ function startServer() { return callback({ error: error.message }); } + const { peer_name } = peer || 'undefined'; + log.debug('Producer paused', { peer_name: peer_name, producer_id: producer_id }); callback('successfully'); @@ -1652,11 +1659,7 @@ function startServer() { socket.on('resumeProducer', async ({ producer_id }, callback) => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); - - const peer_name = getPeerName(room, false); - - const peer = room.getPeer(socket.id); + const { peer } = getRoomAndPeer(socket); if (!peer) { return callback({ @@ -1676,6 +1679,8 @@ function startServer() { return callback({ error: error.message }); } + const { peer_name } = peer || 'undefined'; + log.debug('Producer resumed', { peer_name: peer_name, producer_id: producer_id }); callback('successfully'); @@ -1684,11 +1689,7 @@ function startServer() { socket.on('resumeConsumer', async ({ consumer_id }, callback) => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); - - const peer_name = getPeerName(room, false); - - const peer = room.getPeer(socket.id); + const { peer } = getRoomAndPeer(socket); if (!peer) { return callback({ @@ -1708,6 +1709,8 @@ function startServer() { return callback({ error: error.message }); } + const { peer_name } = peer || 'undefined'; + log.debug('Consumer resumed', { peer_name: peer_name, consumer_id: consumer_id }); callback('successfully'); @@ -1716,9 +1719,11 @@ function startServer() { socket.on('getProducers', () => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); + + const { peer_name } = peer || 'undefined'; - log.debug('Get producers', getPeerName(room)); + log.debug('Get producers', peer_name); // send all the current producer to newly joined member const producerList = room.getProducerListForPeer(); @@ -1907,14 +1912,12 @@ function startServer() { socket.on('updatePeerInfo', (dataObject) => { if (!roomList.has(socket.room_id)) return; - const data = checkXSS(dataObject); - - const room = roomList.get(socket.room_id); - - const peer = room.getPeer(socket.id); + const { room, peer } = getRoomAndPeer(socket); if (!peer) return; + const data = checkXSS(dataObject); + peer.updatePeerInfo(data); if (data.broadcast) { @@ -1972,9 +1975,11 @@ function startServer() { socket.on('getRoomInfo', async (_, cb) => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); + + const { peer_name } = peer || 'undefined'; - log.debug('Send Room Info to', getPeerName(room)); + log.debug('Send Room Info to', peer_name); cb(room.toJson()); }); @@ -2108,14 +2113,15 @@ function startServer() { const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); - // check if the message coming from real peer - const realPeer = isRealPeer(data.peer_name, socket.id, socket.room_id); + const { peer_name } = peer || 'undefined'; + + const realPeer = data.peer_name === peer_name; if (!realPeer) { - const peer_name = getPeerName(room, false); - log.debug('Fake message detected', { + log.warn('Fake message detected', { + ip: getIpSocket(socket), realFrom: peer_name, fakeFrom: data.peer_name, msg: data.peer_msg, @@ -2427,6 +2433,7 @@ function startServer() { const rtmp = await room.startRTMP(socket.id, room, host, 1935, `../${rtmpDir}/${file}`); if (rtmp !== false) rtmpFileStreamsCount++; + log.debug('startRTMP - rtmpFileStreamsCount ---->', rtmpFileStreamsCount); cb(rtmp); @@ -2438,6 +2445,7 @@ function startServer() { const room = roomList.get(socket.room_id); rtmpFileStreamsCount--; + log.debug('stopRTMP - rtmpFileStreamsCount ---->', rtmpFileStreamsCount); await room.stopRTMP(); @@ -2467,6 +2475,7 @@ function startServer() { const rtmp = await room.startRTMPfromURL(socket.id, room, host, 1935, inputVideoURL); if (rtmp !== false) rtmpUrlStreamsCount++; + log.debug('startRTMPfromURL - rtmpUrlStreamsCount ---->', rtmpUrlStreamsCount); cb(rtmp); @@ -2478,6 +2487,7 @@ function startServer() { const room = roomList.get(socket.room_id); rtmpUrlStreamsCount--; + log.debug('stopRTMPfromURL - rtmpUrlStreamsCount ---->', rtmpUrlStreamsCount); await room.stopRTMPfromURL(); @@ -2485,7 +2495,9 @@ function startServer() { socket.on('endOrErrorRTMPfromURL', async () => { if (!roomList.has(socket.room_id)) return; + rtmpUrlStreamsCount--; + log.debug('endRTMPfromURL - rtmpUrlStreamsCount ---->', rtmpUrlStreamsCount); }); @@ -2516,13 +2528,14 @@ function startServer() { const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const { room, peer } = getRoomAndPeer(socket); + + const { peer_name } = peer || socket.id; const roomPolls = room.getPolls(); const poll = roomPolls[data.pollIndex]; if (poll) { - const peer_name = getPeerName(room, false) || socket.id; poll.voters.set(peer_name, data.option); room.sendToAll('updatePolls', room.convertPolls(roomPolls)); log.debug('[Poll] vote', roomPolls); @@ -2620,9 +2633,7 @@ function startServer() { socket.on('disconnect', async () => { if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); - - const peer = room.getPeer(socket.id); + const { room, peer } = getRoomAndPeer(socket); const { peer_name, peer_uuid } = peer || {}; @@ -2665,9 +2676,7 @@ function startServer() { }); } - const room = roomList.get(socket.room_id); - - const peer = room.getPeer(socket.id); + const { room, peer } = getRoomAndPeer(socket); const { peer_name, peer_uuid } = peer || {}; @@ -2706,33 +2715,13 @@ function startServer() { }); // common - function getPeerName(room, json = true) { - try { - const DEFAULT_PEER_NAME = 'undefined'; - const peer = room.getPeer(socket.id); - const peerName = peer.peer_name || DEFAULT_PEER_NAME; - if (json) { - return { peer_name: peerName }; - } - return peerName; - } catch (err) { - log.error('getPeerName', err); - return json ? { peer_name: DEFAULT_PEER_NAME } : DEFAULT_PEER_NAME; - } - } - - function isRealPeer(name, id, roomId) { - if (!roomList.has(socket.room_id)) return false; - - const room = roomList.get(roomId); - - const peer = room.getPeer(id); - if (!peer) return false; + function getRoomAndPeer(socket) { + const room = roomList.get(socket.room_id) || {}; - const { peer_name } = peer; + const peer = room.getPeer ? room.getPeer(socket.id) || {} : {}; - return peer_name == name; + return { room, peer }; } function isValidFileName(fileName) { @@ -2744,6 +2733,7 @@ function startServer() { const pattern = new RegExp( '^(https?:\\/\\/)?' + // protocol '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + 'localhost|' + // allow localhost '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string diff --git a/package.json b/package.json index 1ac41c3f..b945f92e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.97", + "version": "1.5.98", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -77,7 +77,7 @@ "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.68.1", + "openai": "^4.68.3", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/js/Room.js b/public/js/Room.js index dd11ae56..f297d0af 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.97 + * @version 1.5.98 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.97', + title: 'WebRTC SFU v1.5.98', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 5a78b46f..b298cb72 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.97 + * @version 1.5.98 * */ From f58b0f3a2df474cb399728941efac22043e2fdf8 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 24 Oct 2024 08:44:17 +0200 Subject: [PATCH 054/119] [mirotalksfu] - server refactoring, improve readability, update dep --- app/src/Server.js | 217 +++++++++++++++++++++++----------------- package.json | 4 +- public/js/Room.js | 4 +- public/js/RoomClient.js | 2 +- 4 files changed, 129 insertions(+), 98 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index e0bbcaee..d1d80614 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.98 + * @version 1.5.99 * */ @@ -1230,7 +1230,7 @@ function startServer() { }); socket.on('join', async (dataObject, cb) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return cb({ error: 'Room does not exist', }); @@ -1253,7 +1253,7 @@ function startServer() { return cb('invalid'); } - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const { peer_name, peer_id, peer_uuid, peer_token, os_name, os_version, browser_name, browser_version } = data.peer_info; @@ -1415,7 +1415,7 @@ function startServer() { }); socket.on('getRouterRtpCapabilities', (_, callback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Room not found' }); } @@ -1440,7 +1440,7 @@ function startServer() { }); socket.on('createWebRtcTransport', async (_, callback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Room not found' }); } @@ -1465,7 +1465,7 @@ function startServer() { }); socket.on('connectTransport', async ({ transport_id, dtlsParameters }, callback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Room not found' }); } @@ -1490,11 +1490,11 @@ function startServer() { }); socket.on('restartIce', async ({ transport_id }, callback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Room not found' }); } - const { peer } = getRoomAndPeer(socket); + const peer = getPeer(socket); if (!peer) { return callback({ error: 'Peer not found' }); @@ -1525,7 +1525,7 @@ function startServer() { }); socket.on('produce', async ({ producerTransportId, kind, appData, rtpParameters }, callback, errback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Room not found' }); } @@ -1586,7 +1586,7 @@ function startServer() { }); socket.on('consume', async ({ consumerTransportId, producerId, rtpCapabilities }, callback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Room not found' }); } @@ -1615,7 +1615,7 @@ function startServer() { }); socket.on('producerClosed', (data) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const { room, peer } = getRoomAndPeer(socket); @@ -1627,9 +1627,9 @@ function startServer() { }); socket.on('pauseProducer', async ({ producer_id }, callback) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const { peer } = getRoomAndPeer(socket); + const peer = getPeer(socket); if (!peer) { return callback({ @@ -1657,9 +1657,9 @@ function startServer() { }); socket.on('resumeProducer', async ({ producer_id }, callback) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const { peer } = getRoomAndPeer(socket); + const peer = getPeer(socket); if (!peer) { return callback({ @@ -1687,9 +1687,9 @@ function startServer() { }); socket.on('resumeConsumer', async ({ consumer_id }, callback) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const { peer } = getRoomAndPeer(socket); + const peer = getPeer(socket); if (!peer) { return callback({ @@ -1717,7 +1717,7 @@ function startServer() { }); socket.on('getProducers', () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const { room, peer } = getRoomAndPeer(socket); @@ -1732,9 +1732,9 @@ function startServer() { }); socket.on('getPeerCounts', async ({}, callback) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const peerCounts = room.getPeersCount(); @@ -1744,13 +1744,13 @@ function startServer() { }); socket.on('cmd', async (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); log.debug('cmd', data); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); switch (data.type) { case 'privacy': @@ -1771,13 +1771,13 @@ function startServer() { }); socket.on('roomAction', async (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); const isPresenter = await isPeerPresenter(socket.room_id, socket.id, data.peer_name, data.peer_uuid); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); log.debug('Room action:', data); @@ -1846,11 +1846,11 @@ function startServer() { }); socket.on('roomLobby', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); data.room = room.toJson(); @@ -1872,7 +1872,7 @@ function startServer() { }); socket.on('peerAction', async (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); @@ -1900,7 +1900,7 @@ function startServer() { if (!isPresenter) return; } - const room = roomList.get(socket.room_id); + const room = getRoom(socket); if (data.action === 'ban') room.addBannedPeer(data.to_peer_uuid); @@ -1910,7 +1910,7 @@ function startServer() { }); socket.on('updatePeerInfo', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const { room, peer } = getRoomAndPeer(socket); @@ -1927,11 +1927,11 @@ function startServer() { }); socket.on('updateRoomModerator', async (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const isPresenter = await isPeerPresenter(socket.room_id, socket.id, data.peer_name, data.peer_uuid); @@ -1955,11 +1955,11 @@ function startServer() { }); socket.on('updateRoomModeratorALL', async (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const isPresenter = await isPeerPresenter(socket.room_id, socket.id, data.peer_name, data.peer_uuid); @@ -1973,7 +1973,7 @@ function startServer() { }); socket.on('getRoomInfo', async (_, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const { room, peer } = getRoomAndPeer(socket); @@ -1985,7 +1985,7 @@ function startServer() { }); socket.on('fileInfo', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); @@ -1996,37 +1996,41 @@ function startServer() { log.debug('Send File Info', data); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); data.broadcast ? room.broadCast(socket.id, 'fileInfo', data) : room.sendTo(data.peer_id, 'fileInfo', data); }); socket.on('file', (data) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); data.broadcast ? room.broadCast(socket.id, 'file', data) : room.sendTo(data.peer_id, 'file', data); }); socket.on('fileAbort', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - roomList.get(socket.room_id).broadCast(socket.id, 'fileAbort', data); + const room = getRoom(socket); + + room.broadCast(socket.id, 'fileAbort', data); }); socket.on('receiveFileAbort', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - roomList.get(socket.room_id).broadCast(socket.id, 'receiveFileAbort', data); + const room = getRoom(socket); + + room.broadCast(socket.id, 'receiveFileAbort', data); }); socket.on('shareVideoAction', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); @@ -2037,7 +2041,7 @@ function startServer() { log.debug('Share video: ', data); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); data.peer_id == 'all' ? room.broadCast(socket.id, 'shareVideoAction', data) @@ -2045,11 +2049,11 @@ function startServer() { }); socket.on('wbCanvasToJson', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); // const objLength = bytesToSize(Object.keys(data).length); @@ -2059,44 +2063,44 @@ function startServer() { }); socket.on('whiteboardAction', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); log.debug('Whiteboard', data); room.broadCast(socket.id, 'whiteboardAction', data); }); socket.on('setVideoOff', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); log.debug('Video off data', data.peer_name); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); room.broadCast(socket.id, 'setVideoOff', data); }); socket.on('recordingAction', async (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); log.debug('Recording action', data); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); room.broadCast(socket.id, 'recordingAction', data); }); socket.on('refreshParticipantsCount', () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const peerCounts = room.getPeers().size; @@ -2109,7 +2113,7 @@ function startServer() { }); socket.on('message', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); @@ -2137,8 +2141,10 @@ function startServer() { }); socket.on('getChatGPT', async ({ time, room, name, prompt, context }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.chatGPT.enabled) return cb({ message: 'ChatGPT seems disabled, try later!' }); + // https://platform.openai.com/docs/api-reference/completions/create try { // Add the prompt to the context @@ -2229,7 +2235,8 @@ function startServer() { // https://docs.heygen.com/reference/new-session socket.on('streamingNew', async ({ quality, avatar_id, voice_id }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); try { @@ -2265,7 +2272,8 @@ function startServer() { // https://docs.heygen.com/reference/start-session socket.on('streamingStart', async ({ session_id, sdp }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); @@ -2294,7 +2302,8 @@ function startServer() { // https://docs.heygen.com/reference/submit-ice-information socket.on('streamingICE', async ({ session_id, candidate }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); @@ -2323,7 +2332,8 @@ function startServer() { // https://docs.heygen.com/reference/send-task socket.on('streamingTask', async ({ session_id, text }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); try { @@ -2353,7 +2363,8 @@ function startServer() { }); socket.on('talkToOpenAI', async ({ text, context }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); try { @@ -2380,7 +2391,8 @@ function startServer() { // https://docs.heygen.com/reference/close-session socket.on('streamingStop', async ({ session_id }, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); try { @@ -2409,14 +2421,17 @@ function startServer() { }); socket.on('getRTMP', async ({}, cb) => { - if (!roomList.has(socket.room_id)) return; - const room = roomList.get(socket.room_id); + if (!roomExists(socket)) return; + + const room = getRoom(socket); + const rtmpFiles = await room.getRTMP(rtmpDir); + cb(rtmpFiles); }); socket.on('startRTMP', async (dataObject, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; if (rtmpCfg && rtmpFileStreamsCount >= rtmpCfg.maxStreams) { log.warn('RTMP max file streams reached', rtmpFileStreamsCount); @@ -2428,7 +2443,7 @@ function startServer() { const isPresenter = await isPeerPresenter(socket.room_id, socket.id, peer_name, peer_uuid); if (!isPresenter) return cb(false); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const host = config.ngrok.enabled ? 'localhost' : socket.handshake.headers.host.split(':')[0]; const rtmp = await room.startRTMP(socket.id, room, host, 1935, `../${rtmpDir}/${file}`); @@ -2440,9 +2455,9 @@ function startServer() { }); socket.on('stopRTMP', async () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); rtmpFileStreamsCount--; @@ -2452,13 +2467,15 @@ function startServer() { }); socket.on('endOrErrorRTMP', async () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; + rtmpFileStreamsCount--; + log.debug('endRTMP - rtmpFileStreamsCount ---->', rtmpFileStreamsCount); }); socket.on('startRTMPfromURL', async (dataObject, cb) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; if (rtmpCfg && rtmpUrlStreamsCount >= rtmpCfg.maxStreams) { log.warn('RTMP max Url streams reached', rtmpUrlStreamsCount); @@ -2470,7 +2487,7 @@ function startServer() { const isPresenter = await isPeerPresenter(socket.room_id, socket.id, peer_name, peer_uuid); if (!isPresenter) return cb(false); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const host = config.ngrok.enabled ? 'localhost' : socket.handshake.headers.host.split(':')[0]; const rtmp = await room.startRTMPfromURL(socket.id, room, host, 1935, inputVideoURL); @@ -2482,9 +2499,9 @@ function startServer() { }); socket.on('stopRTMPfromURL', async () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); rtmpUrlStreamsCount--; @@ -2494,7 +2511,7 @@ function startServer() { }); socket.on('endOrErrorRTMPfromURL', async () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; rtmpUrlStreamsCount--; @@ -2502,13 +2519,13 @@ function startServer() { }); socket.on('createPoll', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); const { question, options } = data; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const newPoll = { question: question, @@ -2524,7 +2541,7 @@ function startServer() { }); socket.on('vote', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); @@ -2543,9 +2560,9 @@ function startServer() { }); socket.on('updatePoll', () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const roomPolls = room.getPolls(); @@ -2556,13 +2573,13 @@ function startServer() { }); socket.on('editPoll', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); const { index, question, options } = data; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const roomPolls = room.getPolls(); @@ -2575,7 +2592,7 @@ function startServer() { }); socket.on('deletePoll', async (data) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const { index, peer_name, peer_uuid } = checkXSS(data); @@ -2583,7 +2600,7 @@ function startServer() { // const isPresenter = await isPeerPresenter(socket.room_id, socket.id, peer_name, peer_uuid); // if (!isPresenter) return; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); const roomPolls = room.getPolls(); @@ -2597,22 +2614,22 @@ function startServer() { // Room collaborative editor socket.on('editorChange', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; //const data = checkXSS(dataObject); const data = dataObject; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); room.broadCast(socket.id, 'editorChange', data); }); socket.on('editorActions', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const data = checkXSS(dataObject); - const room = roomList.get(socket.room_id); + const room = getRoom(socket); log.debug('editorActions', data); @@ -2620,18 +2637,18 @@ function startServer() { }); socket.on('editorUpdate', (dataObject) => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; //const data = checkXSS(dataObject); const data = dataObject; - const room = roomList.get(socket.room_id); + const room = getRoom(socket); room.broadCast(socket.id, 'editorUpdate', data); }); socket.on('disconnect', async () => { - if (!roomList.has(socket.room_id)) return; + if (!roomExists(socket)) return; const { room, peer } = getRoomAndPeer(socket); @@ -2670,7 +2687,7 @@ function startServer() { }); socket.on('exitRoom', async (_, callback) => { - if (!roomList.has(socket.room_id)) { + if (!roomExists(socket)) { return callback({ error: 'Not currently in a room', }); @@ -2717,13 +2734,27 @@ function startServer() { // common function getRoomAndPeer(socket) { - const room = roomList.get(socket.room_id) || {}; + const room = getRoom(socket); - const peer = room.getPeer ? room.getPeer(socket.id) || {} : {}; + const peer = getPeer(socket); return { room, peer }; } + function getRoom(socket) { + return roomList.get(socket.room_id) || {}; + } + + function getPeer(socket) { + const room = getRoom(socket); // Reusing getRoom to retrieve the room + + return room.getPeer ? room.getPeer(socket.id) || {} : {}; + } + + function roomExists(socket) { + return roomList.has(socket.room_id); + } + function isValidFileName(fileName) { const invalidChars = /[\\\/\?\*\|:"<>]/; return !invalidChars.test(fileName); diff --git a/package.json b/package.json index b945f92e..59964c10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.98", + "version": "1.5.99", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -77,7 +77,7 @@ "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.15", - "openai": "^4.68.3", + "openai": "^4.68.4", "qs": "6.13.0", "socket.io": "4.8.0", "swagger-ui-express": "5.0.1", diff --git a/public/js/Room.js b/public/js/Room.js index f297d0af..abcc617b 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.98 + * @version 1.5.99 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.98', + title: 'WebRTC SFU v1.5.99', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index b298cb72..bb285ce3 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.98 + * @version 1.5.99 * */ From fad947d25eaa3e049fca75ffc7d3b1faa7b871cc Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 24 Oct 2024 22:37:09 +0200 Subject: [PATCH 055/119] [mirotalksfu] - add Discord bot, update dep --- README.md | 1 + app/src/Discord.js | 73 ++++++++++++++++++++++++++++++++++++++ app/src/Server.js | 13 +++++-- app/src/config.template.js | 22 ++++++++++++ package.json | 3 +- public/js/Room.js | 4 +-- public/js/RoomClient.js | 2 +- 7 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 app/src/Discord.js diff --git a/README.md b/README.md index f2791293..faada0a3 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ - Right-click options on video elements for additional controls. - Supports [REST API](app/api/README.md) (Application Programming Interface). - Integration with [Slack](https://api.slack.com/apps/) for enhanced communication. +- Integration with [Discord](https://discord.com) for enhanced communication. - Utilizes [Sentry](https://sentry.io/) for error reporting. - And much more... diff --git a/app/src/Discord.js b/app/src/Discord.js new file mode 100644 index 00000000..1665ff57 --- /dev/null +++ b/app/src/Discord.js @@ -0,0 +1,73 @@ +'use strict'; + +const { Client, GatewayIntentBits } = require('discord.js'); + +const Logger = require('./Logger'); + +const log = new Logger('Discord'); + +// Discord Bot Class Implementation +class Discord { + constructor(token, commands) { + this.token = token; + this.commands = commands; + this.discordClient = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, // Make sure this is enabled in your Discord Developer Portal + ], + }); + + this.setupEventHandlers(); + + this.discordClient.login(this.token).catch((error) => { + log.error('Failed to login to Discord:', error); + }); + } + + setupEventHandlers() { + this.discordClient.once('ready', () => { + log.info(`Discord Bot Logged in as ${this.discordClient.user.tag}!`, '😎'); + }); + + this.discordClient.on('error', (error) => { + log.error(`Discord Client Error: ${error.message}`, { stack: error.stack }); + }); + + this.discordClient.on('messageCreate', async (message) => { + if (message.author.bot) return; + + for (const command of this.commands) { + if (message.content.startsWith(command.name)) { + switch (command.name) { + case '/sfu': + const roomId = this.generateMeetingRoom(command.baseUrl); + await this.sendMessage(message.channel, `${command.message} ${roomId}`); + break; + //.... + default: + await this.sendMessage(message.channel, command.message); + break; + } + break; // Exit the loop after finding the command + } + } + }); + } + + generateMeetingRoom(baseUrl) { + const roomId = Math.random().toString(36).substring(2, 10); + return `${baseUrl}${roomId}`; + } + + async sendMessage(channel, content) { + try { + await channel.send(content); + } catch (error) { + log.error(`Failed to send message: ${error.message}`); + } + } +} + +module.exports = Discord; diff --git a/app/src/Server.js b/app/src/Server.js index d1d80614..fa3dbb5b 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.99 + * @version 1.6.00 * */ @@ -86,6 +86,7 @@ const yaml = require('js-yaml'); const swaggerUi = require('swagger-ui-express'); const swaggerDocument = yaml.load(fs.readFileSync(path.join(__dirname, '/../api/swagger.yaml'), 'utf8')); const Sentry = require('@sentry/node'); +const Discord = require('./Discord.js'); const restrictAccessByIP = require('./middleware/IpWhitelist.js'); const packageJson = require('../../package.json'); @@ -180,6 +181,14 @@ if (sentryEnabled) { */ } +// Discord Bot +const { enabled, commands, token } = config.discord || {}; + +if (enabled && commands.length > 0 && token) { + const discordBot = new Discord(token, commands); + log.info('Discord bot is enabled and starting'); +} + // Stats const defaultStats = { enabled: true, @@ -2236,7 +2245,7 @@ function startServer() { // https://docs.heygen.com/reference/new-session socket.on('streamingNew', async ({ quality, avatar_id, voice_id }, cb) => { if (!roomExists(socket)) return; - + if (!config.videoAI.enabled || !config.videoAI.apiKey) return cb({ error: 'Video AI seems disabled, try later!' }); try { diff --git a/app/src/config.template.js b/app/src/config.template.js index 909df2d6..92980937 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -284,6 +284,28 @@ module.exports = { enabled: false, signingSecret: '', }, + discord: { + /* + Discord + 1. Go to the Discord Developer Portal: https://discord.com/developers/. + 2. Create a new application and name it whatever you like. + 3. Under the Bot section, click Add Bot and confirm. + 4. Copy your bot token (this will be used later). + 5. Under OAuth2 -> URL Generator, select bot scope, and under Bot Permissions, select the permissions you need (e.g., Send Messages and Read Messages). + 6. Copy the generated invite URL, open it in a browser, and invite the bot to your Discord server. + 7. Add the Bot in the Server channel permissions + 8. Type /sfu (commands.name) in the channel, the response will return a URL for the meeting + */ + enabled: false, + token: '', + commands: [ + { + name: '/sfu', + message: 'Here is your SFU meeting room:', + baseUrl: 'https://sfu.mirotalk.com/join/', + }, + ], + }, IPLookup: { /* GeoJS diff --git a/package.json b/package.json index 59964c10..4f25bac0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.5.99", + "version": "1.6.00", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -64,6 +64,7 @@ "compression": "1.7.4", "cors": "2.8.5", "crypto-js": "4.2.0", + "discord.js": "^14.16.3", "dompurify": "^3.1.7", "express": "4.21.1", "express-openid-connect": "^2.17.1", diff --git a/public/js/Room.js b/public/js/Room.js index abcc617b..efe7c088 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.99 + * @version 1.6.00 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.5.99', + title: 'WebRTC SFU v1.6.00', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index bb285ce3..ac66fda3 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.5.99 + * @version 1.6.00 * */ From 3e4664bba855c0eb133efe0d6d7c3f9c0278b307 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 24 Oct 2024 22:45:49 +0200 Subject: [PATCH 056/119] [mirotalksfu] - add missing --- app/src/Server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/Server.js b/app/src/Server.js index fa3dbb5b..b0d9a4a1 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -16,6 +16,7 @@ prod dependencies: { colors : https://www.npmjs.com/package/colors cors : https://www.npmjs.com/package/cors crypto-js : https://www.npmjs.com/package/crypto-js + discord.js : https://www.npmjs.com/package/discord.js dompurify : https://www.npmjs.com/package/dompurify express : https://www.npmjs.com/package/express express-openid-connect : https://www.npmjs.com/package/express-openid-connect From ca93835780469b455116785a3baa8cfad6d3308b Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 24 Oct 2024 23:57:06 +0200 Subject: [PATCH 057/119] [mirotalksfu] - use uuid4 --- app/src/Discord.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/Discord.js b/app/src/Discord.js index 1665ff57..2b8f5ffd 100644 --- a/app/src/Discord.js +++ b/app/src/Discord.js @@ -2,6 +2,8 @@ const { Client, GatewayIntentBits } = require('discord.js'); +const { v4: uuidV4 } = require('uuid'); + const Logger = require('./Logger'); const log = new Logger('Discord'); @@ -57,7 +59,7 @@ class Discord { } generateMeetingRoom(baseUrl) { - const roomId = Math.random().toString(36).substring(2, 10); + const roomId = uuidV4(); return `${baseUrl}${roomId}`; } From 8c5ace0a20e7763b970da39ccbcf15ee7f55c5ab Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 26 Oct 2024 01:32:30 +0200 Subject: [PATCH 058/119] [mirotalksfu] - #170 add Mattermost integration, update dep --- README.md | 1 + app/src/Mattermost.js | 99 ++++++++++++++++++++++++++++++++++++++ app/src/Server.js | 17 ++++--- app/src/config.template.js | 34 +++++++++++++ package.json | 6 +-- public/js/Room.js | 4 +- public/js/RoomClient.js | 2 +- 7 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 app/src/Mattermost.js diff --git a/README.md b/README.md index faada0a3..d325b767 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ - Supports [REST API](app/api/README.md) (Application Programming Interface). - Integration with [Slack](https://api.slack.com/apps/) for enhanced communication. - Integration with [Discord](https://discord.com) for enhanced communication. +- Integration with [Mattermost](https://mattermost.com/) for enhanced communication. - Utilizes [Sentry](https://sentry.io/) for error reporting. - And much more... diff --git a/app/src/Mattermost.js b/app/src/Mattermost.js new file mode 100644 index 00000000..e9afba56 --- /dev/null +++ b/app/src/Mattermost.js @@ -0,0 +1,99 @@ +'use strict'; + +const { Client4 } = require('@mattermost/client'); + +const { v4: uuidV4 } = require('uuid'); + +const config = require('./config'); + +const Logger = require('./Logger'); + +const log = new Logger('Mattermost'); + +class Mattermost { + constructor(app) { + const { + enabled, + token, + serverUrl, + username, + password, + commands = '/sfu', + texts = '/sfu', + } = config.mattermost || {}; + + if (!enabled) return; // Check if Mattermost integration is enabled + + this.app = app; + this.allowed = config.api.allowed && config.api.allowed.mattermost; + this.token = token; + this.serverUrl = serverUrl; + this.username = username; + this.password = password; + this.commands = commands; + this.texts = texts; + + this.client = new Client4(); + this.client.setUrl(this.serverUrl); + this.authenticate(); + this.setupEventHandlers(); + } + + async authenticate() { + try { + const user = await this.client.login(this.username, this.password); + log.debug('--------> Logged into Mattermost as', user.username); + } catch (error) { + log.error('Failed to log into Mattermost:', error); + } + } + + setupEventHandlers() { + this.app.post('/mattermost', (req, res) => { + // + if (!this.allowed) { + return res + .status(403) + .send('This endpoint has been disabled. Please contact the administrator for further information.'); + } + + log.debug('Mattermost request received:', { header: req.header, body: req.body }); + + const { token, text, command, channel_id } = req.body; + if (token !== this.token) { + return res.status(403).send('Invalid token'); + } + + const payload = { text: '', channel_id }; + if (this.processInput(command, payload, req) || this.processInput(text, payload, req)) { + return res.json(payload); + } + + return res.status(200).send('Command not recognized'); + }); + } + + processInput(input, payload, req) { + for (const cmd of [...this.commands, ...this.texts]) { + if (input.trim() === cmd.name) { + switch (cmd.name) { + case '/sfu': + payload.text = `${cmd.message} ${this.getMeetingURL(req)}`; + break; + default: + break; + } + return true; + } + } + return false; + } + + getMeetingURL(req) { + const host = req.headers.host; + const protocol = host.includes('localhost') ? 'http' : 'https'; + return `${protocol}://${host}/join/${uuidV4()}`; + } +} + +module.exports = Mattermost; diff --git a/app/src/Server.js b/app/src/Server.js index b0d9a4a1..84c81c9d 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -8,7 +8,7 @@ ███████ ███████ ██  ██   ████   ███████ ██  ██                                        prod dependencies: { - @ffmpeg-installer/ffmpeg: https://www.npmjs.com/package/@ffmpeg-installer/ffmpeg + @mattermost/client : https://www.npmjs.com/package/@mattermost/client @sentry/node : https://www.npmjs.com/package/@sentry/node axios : https://www.npmjs.com/package/axios body-parser : https://www.npmjs.com/package/body-parser @@ -56,7 +56,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.00 + * @version 1.6.10 * */ @@ -88,6 +88,7 @@ const swaggerUi = require('swagger-ui-express'); const swaggerDocument = yaml.load(fs.readFileSync(path.join(__dirname, '/../api/swagger.yaml'), 'utf8')); const Sentry = require('@sentry/node'); const Discord = require('./Discord.js'); +const Mattermost = require('./Mattermost.js'); const restrictAccessByIP = require('./middleware/IpWhitelist.js'); const packageJson = require('../../package.json'); @@ -110,7 +111,6 @@ const CryptoJS = require('crypto-js'); const qS = require('qs'); const slackEnabled = config.slack.enabled; const slackSigningSecret = config.slack.signingSecret; -const bodyParser = require('body-parser'); const app = express(); @@ -328,12 +328,12 @@ function OIDCAuth(req, res, next) { function startServer() { // Start the app + app.use(express.static(dir.public)); app.use(cors(corsOptions)); app.use(compression()); - app.use(express.json({ limit: '50mb' })); // Ensure the body parser can handle large files - app.use(express.static(dir.public)); - app.use(bodyParser.urlencoded({ extended: true })); - app.use(bodyParser.raw({ type: 'video/webm', limit: '50mb' })); // handle raw binary data + app.use(express.json({ limit: '50mb' })); // Handles JSON payloads + app.use(express.urlencoded({ extended: true, limit: '50mb' })); // Handles URL-encoded payloads + app.use(express.raw({ type: 'video/webm', limit: '50mb' })); // Handles raw binary data app.use(restApi.basePath + '/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // api docs // IP Whitelist check ... @@ -352,6 +352,9 @@ function startServer() { }); */ + // Mattermost + const mattermost = new Mattermost(app); + // POST start from here... app.post('*', function (next) { next(); diff --git a/app/src/config.template.js b/app/src/config.template.js index 92980937..51aec0cc 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -121,6 +121,7 @@ module.exports = { join: true, token: false, slack: true, + mattermost: true, //... }, }, @@ -273,6 +274,39 @@ module.exports = { DSN: '', tracesSampleRate: 0.5, }, + mattermost: { + /* + Mattermost: https://mattermost.com + 1. Navigate to Main Menu > Integrations > Slash Commands in Mattermost. + 2. Click on Add Slash Command and configure the following settings: + - Title: Enter a descriptive title (e.g., `P2P Command`). + - Command Trigger Word: Set the trigger word to `p2p`. + - Callback URLs: Enter the URL for your Express server (e.g., `https://yourserver.com/mattermost`). + - Request Method: Select POST. + - Enable Autocomplete: Check the box for **Autocomplete**. + - Autocomplete Description: Provide a brief description (e.g., `Get MiroTalk P2P meeting room`). + 3. Save the slash command and copy the generated token here as MATTERMOST_TOKEN. + */ + enabled: false, + serverUrl: 'YourMattermostServerUrl', + username: 'YourMattermostUsername', + password: 'YourMattermostPassword', + token: 'YourMattermostToken', + commands: [ + { + name: '/sfu', + message: 'Here is your meeting room:', + }, + //.... + ], + texts: [ + { + name: '/sfu', + message: 'Here is your meeting room:', + }, + //.... + ], + }, slack: { /* Slack diff --git a/package.json b/package.json index 4f25bac0..38aa1dab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.6.00", + "version": "1.6.10", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -57,9 +57,9 @@ "node": ">=18" }, "dependencies": { + "@mattermost/client": "^10.0.0", "@sentry/node": "^8.35.0", "axios": "^1.7.7", - "body-parser": "1.20.3", "colors": "1.4.0", "compression": "1.7.4", "cors": "2.8.5", @@ -80,7 +80,7 @@ "nodemailer": "^6.9.15", "openai": "^4.68.4", "qs": "6.13.0", - "socket.io": "4.8.0", + "socket.io": "4.8.1", "swagger-ui-express": "5.0.1", "uuid": "10.0.0" }, diff --git a/public/js/Room.js b/public/js/Room.js index efe7c088..459a1c11 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.00 + * @version 1.6.10 * */ @@ -4500,7 +4500,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.6.00', + title: 'WebRTC SFU v1.6.10', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index ac66fda3..a5934d26 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.00 + * @version 1.6.10 * */ From 2b17efc79d57c97fa4af6b475a296c07cc728b77 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 26 Oct 2024 01:41:23 +0200 Subject: [PATCH 059/119] [mirotalksfu] - #170 fix typo --- app/src/config.template.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/config.template.js b/app/src/config.template.js index 51aec0cc..8154b28c 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -279,13 +279,13 @@ module.exports = { Mattermost: https://mattermost.com 1. Navigate to Main Menu > Integrations > Slash Commands in Mattermost. 2. Click on Add Slash Command and configure the following settings: - - Title: Enter a descriptive title (e.g., `P2P Command`). - - Command Trigger Word: Set the trigger word to `p2p`. + - Title: Enter a descriptive title (e.g., `SFU Command`). + - Command Trigger Word: Set the trigger word to `sfu`. - Callback URLs: Enter the URL for your Express server (e.g., `https://yourserver.com/mattermost`). - Request Method: Select POST. - - Enable Autocomplete: Check the box for **Autocomplete**. - - Autocomplete Description: Provide a brief description (e.g., `Get MiroTalk P2P meeting room`). - 3. Save the slash command and copy the generated token here as MATTERMOST_TOKEN. + - Enable Autocomplete: Check the box for Autocomplete. + - Autocomplete Description: Provide a brief description (e.g., `Get MiroTalk SFU meeting room`). + 3. Save the slash command and copy the generated token (YourMattermostToken). */ enabled: false, serverUrl: 'YourMattermostServerUrl', From 113ccc89d9bd8fa47284e5edf8a2f8eb67d36480 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 26 Oct 2024 20:42:15 +0200 Subject: [PATCH 060/119] [mirotalksfu] - add log --- app/src/Mattermost.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/Mattermost.js b/app/src/Mattermost.js index e9afba56..d463b27c 100644 --- a/app/src/Mattermost.js +++ b/app/src/Mattermost.js @@ -61,6 +61,7 @@ class Mattermost { const { token, text, command, channel_id } = req.body; if (token !== this.token) { + log.error('Invalid token attempt', { token }); return res.status(403).send('Invalid token'); } From 3cddb8fd354f91f89470fe4036f8bd0802ae09dd Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 26 Oct 2024 22:01:24 +0200 Subject: [PATCH 061/119] [mirotalksfu] - fix typo --- app/src/Server.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 84c81c9d..82fe3912 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -2270,8 +2270,6 @@ function startServer() { }, ); - log.warn('STREAMING NEW', response); - const data = { response: response.data }; log.debug('streamingNew', data); From c40a0a8f733cbbf7771e235a17b07bd974bdd96a Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sun, 27 Oct 2024 12:26:03 +0100 Subject: [PATCH 062/119] [mirotalksfu] - improvements --- app/src/Server.js | 56 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 82fe3912..95353fcf 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -1063,29 +1063,53 @@ function startServer() { function getServerConfig(tunnel = false) { return { - app_version: packageJson.version, - node_version: process.versions.node, - cors_options: corsOptions, - middleware: config.middleware, + // General Server Information server_listen: host, server_tunnel: tunnel, - hostConfig: hostCfg, + + // Core Configurations + cors_options: corsOptions, jwtCfg: jwtCfg, - presenters: config.presenters, rest_api: restApi, + + // Middleware and UI + middleware: config.middleware, + configUI: config.ui, + + // Security, Authorization, and User Management + oidc: OIDC.enabled ? OIDC : false, + hostProtected: hostCfg.protected || hostCfg.user_auth ? hostCfg : false, + ip_lookup_enabled: config.IPLookup?.enabled ? config.IPLookup : false, + presenters: config.presenters, + + // Communication Integrations + discord_enabled: config.discord?.enabled ? config.discord : false, + mattermost_enabled: config.mattermost?.enabled ? config.mattermost : false, + slack_enabled: slackEnabled ? config.slack : false, + chatGPT_enabled: config.chatGPT?.enabled ? config.chatGPT : false, + + // Media and Video Configurations + mediasoup_listenInfos: config.mediasoup.webRtcTransport.listenInfos, mediasoup_worker_bin: mediasoup.workerBin, + rtmp_enabled: rtmpCfg.enabled ? rtmpCfg : false, + videAI_enabled: config.videoAI.enabled ? config.videoAI : false, + serverRec: config?.server?.recording, + + // Centralized Logging + sentry_enabled: sentryEnabled ? config.sentry : false, + + // Additional Configurations and Features + survey_enabled: config.survey?.enabled ? config.survey : false, + redirect_enabled: config.redirect?.enabled ? config.redirect : false, + stats_enabled: config.stats?.enabled ? config.stats : false, + ngrok_enabled: config.ngrok?.enabled ? config.ngrok : false, + email_alerts: config.email?.alert ? config.email : false, + + // Version Information + app_version: packageJson.version, + node_version: process.versions.node, mediasoup_server_version: mediasoup.version, mediasoup_client_version: mediasoupClient.version, - mediasoup_listenInfos: config.mediasoup.webRtcTransport.listenInfos, - ip_lookup_enabled: config.IPLookup.enabled, - sentry_enabled: sentryEnabled, - redirect_enabled: config.redirect.enabled, - slack_enabled: slackEnabled, - stats_enabled: config.stats.enabled, - chatGPT_enabled: config.chatGPT.enabled, - configUI: config.ui, - serverRec: config?.server?.recording, - oidc: OIDC.enabled ? OIDC : false, }; } From b4f0e76c2933b5b3d07845c4128714af4bdf569d Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 09:20:18 +0100 Subject: [PATCH 063/119] [mirotalksfu] - #171 add new feature and UI/UX improvements --- app/src/Server.js | 3 +- package.json | 10 +- public/css/Room.css | 16 ++- public/css/VideoGrid.css | 31 +++- public/js/Room.js | 51 +++++-- public/js/RoomClient.js | 295 +++++++++++++++++++++------------------ public/views/Room.html | 3 +- 7 files changed, 256 insertions(+), 153 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 95353fcf..4ad5f3fd 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -11,7 +11,6 @@ prod dependencies: { @mattermost/client : https://www.npmjs.com/package/@mattermost/client @sentry/node : https://www.npmjs.com/package/@sentry/node axios : https://www.npmjs.com/package/axios - body-parser : https://www.npmjs.com/package/body-parser compression : https://www.npmjs.com/package/compression colors : https://www.npmjs.com/package/colors cors : https://www.npmjs.com/package/cors @@ -56,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.10 + * @version 1.6.11 * */ diff --git a/package.json b/package.json index 38aa1dab..55622cd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.6.10", + "version": "1.6.11", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -77,15 +77,15 @@ "mediasoup": "3.14.16", "mediasoup-client": "3.7.17", "ngrok": "^5.0.0-beta.2", - "nodemailer": "^6.9.15", - "openai": "^4.68.4", + "nodemailer": "^6.9.16", + "openai": "^4.69.0", "qs": "6.13.0", "socket.io": "4.8.1", "swagger-ui-express": "5.0.1", - "uuid": "10.0.0" + "uuid": "11.0.2" }, "devDependencies": { - "mocha": "^10.7.3", + "mocha": "^10.8.2", "node-fetch": "^3.3.2", "nodemon": "^3.1.7", "prettier": "3.3.3", diff --git a/public/css/Room.css b/public/css/Room.css index 77a01101..56622bda 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -163,7 +163,7 @@ body { #control { z-index: 3; position: absolute; - display: none; + display: flex; padding: 5px; top: var(--btns-top); @@ -247,6 +247,20 @@ body { background: var(--body-bg) !important; } +@media screen and (max-width: 500px) { + #bottomButtons button { + width: 46px; + font-size: 1.2rem; + } +} + +@media screen and (max-width: 350px) { + #bottomButtons button { + width: 36px; + font-size: 1rem; + } +} + /*-------------------------------------------------------------- # Room QR --------------------------------------------------------------*/ diff --git a/public/css/VideoGrid.css b/public/css/VideoGrid.css index 77690dbc..8e3b2c35 100644 --- a/public/css/VideoGrid.css +++ b/public/css/VideoGrid.css @@ -117,6 +117,22 @@ } .videoMenuBar { + z-index: 2; + position: fixed; + display: inline; + top: 0; + left: 0; + padding: 20px; + background: rgba(0, 0, 0, 0.9); + font-size: small; + font-weight: bold; + text-align: center; + width: 100%; + cursor: default; + overflow: hidden; +} + +.videoMenuBarShare { z-index: 2; position: absolute; display: inline; @@ -133,7 +149,9 @@ } .videoMenuBar input, -.videoMenuBar button { +.videoMenuBar button, +.videoMenuBarShare button { + font-size: 1.2rem; float: right; color: #fff; background: transparent; @@ -142,6 +160,7 @@ border: none; } +.videoMenuBarShare button:hover, .videoMenuBar button:hover { color: grey; transition: all 0.3s ease-in-out; @@ -247,9 +266,19 @@ input[type='range'] { .username { font-size: 12px; } + .videoMenuBar input, + .videoMenuBar button, + .videoMenuBarShare button { + font-size: 1rem; + } } @media screen and (max-width: 500px) { .username { font-size: 10px; } + .videoMenuBar input, + .videoMenuBar button, + .videoMenuBarShare button { + font-size: 0.9rem; + } } diff --git a/public/js/Room.js b/public/js/Room.js index 459a1c11..2af69fc2 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.10 + * @version 1.6.11 * */ @@ -397,6 +397,7 @@ function refreshMainButtonsToolTipPlacement() { setTippy('aboutButton', 'About this project', placement); // Bottom buttons + setTippy('toggleExtraButton', 'Toggle extra buttons', bPlacement); setTippy('startAudioButton', 'Start the audio', bPlacement); setTippy('stopAudioButton', 'Stop the audio', bPlacement); setTippy('startVideoButton', 'Start the video', bPlacement); @@ -1306,6 +1307,7 @@ function roomIsReady() { } else { myProfileAvatar.setAttribute('src', rc.genAvatarSvg(peer_name, 64)); } + show(toggleExtraButton); //* BUTTONS.main.exitButton && show(exitButton); BUTTONS.main.shareButton && show(shareButton); BUTTONS.main.hideMeButton && show(hideMeButton); @@ -1543,6 +1545,7 @@ function handleButtons() { } isHideMeActive = !isHideMeActive; rc.handleHideMe(); + hideClassElements('videoMenuBar'); }; settingsButton.onclick = () => { rc.toggleMySettings(); @@ -1801,10 +1804,14 @@ function handleButtons() { }; raiseHandButton.onclick = () => { rc.updatePeerInfo(peer_name, socket.id, 'hand', true); + hideClassElements('videoMenuBar'); }; lowerHandButton.onclick = () => { rc.updatePeerInfo(peer_name, socket.id, 'hand', false); }; + toggleExtraButton.onclick = async () => { + toggleExtraButtons(); + }; startAudioButton.onclick = async () => { const moderator = rc.getModerator(); if (moderator.audio_cant_unmute) { @@ -2941,6 +2948,7 @@ function handleRoomClientEvents() { show(stopVideoButton); setColor(startVideoButton, 'red'); setVideoButtonsDisabled(false); + hideClassElements('videoMenuBar'); // if (isParticipantsListOpen) getRoomParticipants(); }); rc.on(RoomClient.EVENTS.pauseVideo, () => { @@ -2949,6 +2957,7 @@ function handleRoomClientEvents() { show(startVideoButton); setColor(startVideoButton, 'red'); setVideoButtonsDisabled(false); + hideClassElements('videoMenuBar'); }); rc.on(RoomClient.EVENTS.resumeVideo, () => { console.log('Room event: Client resume video'); @@ -2956,6 +2965,7 @@ function handleRoomClientEvents() { show(stopVideoButton); setVideoButtonsDisabled(false); isVideoPrivacyActive = false; + hideClassElements('videoMenuBar'); }); rc.on(RoomClient.EVENTS.stopVideo, () => { console.log('Room event: Client stop video'); @@ -2963,28 +2973,33 @@ function handleRoomClientEvents() { show(startVideoButton); setVideoButtonsDisabled(false); isVideoPrivacyActive = false; + hideClassElements('videoMenuBar'); // if (isParticipantsListOpen) getRoomParticipants(); }); rc.on(RoomClient.EVENTS.startScreen, () => { console.log('Room event: Client start screen'); hide(startScreenButton); show(stopScreenButton); + hideClassElements('videoMenuBar'); // if (isParticipantsListOpen) getRoomParticipants(); }); rc.on(RoomClient.EVENTS.pauseScreen, () => { console.log('Room event: Client pause screen'); hide(startScreenButton); show(stopScreenButton); + hideClassElements('videoMenuBar'); }); rc.on(RoomClient.EVENTS.resumeScreen, () => { console.log('Room event: Client resume screen'); hide(stopScreenButton); show(startScreenButton); + hideClassElements('videoMenuBar'); }); rc.on(RoomClient.EVENTS.stopScreen, () => { console.log('Room event: Client stop screen'); hide(stopScreenButton); show(startScreenButton); + hideClassElements('videoMenuBar'); // if (isParticipantsListOpen) getRoomParticipants(); }); rc.on(RoomClient.EVENTS.roomLock, () => { @@ -3188,16 +3203,14 @@ function showButtons() { (rc.isMobileDevice && rc.isMySettingsOpen) ) return; - toggleClassElements('videoMenuBar', 'inline'); - control.style.display = 'flex'; bottomButtons.style.display = 'flex'; isButtonsVisible = true; } function checkButtonsBar() { if (!isButtonsBarOver) { - toggleClassElements('videoMenuBar', 'none'); - control.style.display = 'none'; + // hideClassElements('videoMenuBar'); + hide(control); bottomButtons.style.display = 'none'; isButtonsVisible = false; } @@ -3206,13 +3219,33 @@ function checkButtonsBar() { }, 10000); } -function toggleClassElements(className, displayState) { - let elements = rc.getEcN(className); +function hideClassElements(className) { + const elements = rc.getEcN(className); for (let i = 0; i < elements.length; i++) { - elements[i].style.display = displayState; + hide(elements[i]); } } +function toggleExtraButtons() { + control.classList.contains('hidden') ? show(control) : hide(control); + hideClassElements('videoMenuBar'); +} + +// https://animate.style + +function animateCSS(element, animation, prefix = 'animate__') { + return new Promise((resolve, reject) => { + const animationName = `${prefix}${animation}`; + element.classList.add(`${prefix}animated`, animationName); + function handleAnimationEnd(event) { + event.stopPropagation(); + element.classList.remove(`${prefix}animated`, animationName); + resolve('Animation ended'); + } + element.addEventListener('animationend', handleAnimationEnd, { once: true }); + }); +} + function setAudioButtonsDisabled(disabled) { startAudioButton.disabled = disabled; stopAudioButton.disabled = disabled; @@ -4500,7 +4533,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.6.10', + title: 'WebRTC SFU v1.6.11', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index a5934d26..1272b718 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -1435,11 +1435,15 @@ class RoomClient { console.log('Producer transport close', { id: producer.id, type }); if (!audio) { const d = this.getId(producer.id + '__video'); + const vb = this.getId(producer.id + '__vb'); + elem.srcObject.getTracks().forEach(function (track) { track.stop(); }); elem.parentNode.removeChild(elem); + d.parentNode.removeChild(d); + vb.parentNode.removeChild(vb); handleAspectRatio(); console.log('[transportClose] Video-element-count', this.videoMediaContainer.childElementCount); @@ -1457,11 +1461,15 @@ class RoomClient { console.log('Closing producer', { id: producer.id, type }); if (!audio) { const d = this.getId(producer.id + '__video'); + const vb = this.getId(producer.id + '__vb'); + elem.srcObject.getTracks().forEach(function (track) { track.stop(); }); elem.parentNode.removeChild(elem); + d.parentNode.removeChild(d); + vb.parentNode.removeChild(vb); handleAspectRatio(); console.log('[closingProducer] Video-element-count', this.videoMediaContainer.childElementCount); @@ -1784,6 +1792,17 @@ class RoomClient { return { encodings, codec }; } + // #################################################### + // HELPERS + // #################################################### + + createButton = (id, className) => { + const button = document.createElement('button'); + button.id = id; + button.className = className; + return button; + }; + // #################################################### // PRODUCER // #################################################### @@ -1846,29 +1865,18 @@ class RoomClient { elem.style.objectFit = isScreen || isBroadcastingEnabled ? 'contain' : 'var(--videoObjFit)'; elem.className = this.isMobileDevice || isScreen ? '' : 'mirror'; vb = document.createElement('div'); - vb.setAttribute('id', this.peer_id + '__vb'); - vb.className = 'videoMenuBar fadein'; - pip = document.createElement('button'); - pip.id = id + '__pictureInPicture'; - pip.className = html.pip; - fs = document.createElement('button'); - fs.id = id + '__fullScreen'; - fs.className = html.fullScreen; - ts = document.createElement('button'); - ts.id = id + '__snapshot'; - ts.className = html.snapshot; - mv = document.createElement('button'); - mv.id = id + '__mirror'; - mv.className = html.mirror; - pn = document.createElement('button'); - pn.id = id + '__pin'; - pn.className = html.pin; - vp = document.createElement('button'); - vp.id = this.peer_id + '__vp'; - vp.className = html.videoPrivacy; - au = document.createElement('button'); - au.id = this.peer_id + '__audio'; - au.className = this.peer_info.peer_audio ? html.audioOn : html.audioOff; + vb.id = id + '__vb'; + vb.className = 'videoMenuBar hidden'; + pip = this.createButton(id + '__pictureInPicture', html.pip); + fs = this.createButton(id + '__fullScreen', html.fullScreen); + ts = this.createButton(id + '__snapshot', html.snapshot); + mv = this.createButton(id + '__mirror', html.mirror); + pn = this.createButton(id + '__pin', html.pin); + vp = this.createButton(this.peer_id + '__vp', html.videoPrivacy); + au = this.createButton( + this.peer_id + '__audio', + this.peer_info.peer_audio ? html.audioOn : html.audioOff, + ); au.style.cursor = 'default'; p = document.createElement('p'); p.id = this.peer_id + '__name'; @@ -1893,27 +1901,37 @@ class RoomClient { vb.appendChild(pip); BUTTONS.producerVideo.videoMirrorButton && vb.appendChild(mv); BUTTONS.producerVideo.fullScreenButton && this.isVideoFullScreenSupported && vb.appendChild(fs); + if (!this.isMobileDevice) vb.appendChild(pn); + + vb.appendChild(p); d.appendChild(elem); d.appendChild(pm); d.appendChild(i); d.appendChild(p); - d.appendChild(vb); + //d.appendChild(vb); + document.body.appendChild(vb); this.videoMediaContainer.appendChild(d); await this.attachMediaStream(elem, stream, type, 'Producer'); this.myVideoEl = elem; this.isVideoPictureInPictureSupported && this.handlePIP(elem.id, pip.id); this.isVideoFullScreenSupported && this.handleFS(elem.id, fs.id); + this.handleVB(d.id, vb.id); this.handleDD(elem.id, this.peer_id, true); this.handleTS(elem.id, ts.id); this.handleMV(elem.id, mv.id); this.handlePN(elem.id, pn.id, d.id, isScreen); this.handleZV(elem.id, d.id, this.peer_id); + if (!isScreen) this.handleVP(elem.id, vp.id); + this.popupPeerInfo(p.id, this.peer_info); this.checkPeerInfoStatus(this.peer_info); + if (isScreen) pn.click(); + handleAspectRatio(); + if (!this.isMobileDevice) { this.setTippy(pn.id, 'Toggle Pin', 'bottom'); this.setTippy(mv.id, 'Toggle mirror', 'bottom'); @@ -1922,6 +1940,7 @@ class RoomClient { this.setTippy(vp.id, 'Toggle video privacy', 'bottom'); this.setTippy(au.id, 'Audio status', 'bottom'); } + console.log('[addProducer] Video-element-count', this.videoMediaContainer.childElementCount); break; case mediaType.audio: @@ -2030,10 +2049,12 @@ class RoomClient { if (type !== mediaType.audio) { const elem = this.getId(producer_id); const d = this.getId(producer_id + '__video'); + const vb = this.getId(producer_id + '__vb'); elem.srcObject.getTracks().forEach(function (track) { track.stop(); }); d.parentNode.removeChild(d); + vb.parentNode.removeChild(vb); //alert(this.pinnedVideoPlayerId + '==' + producer_id); if (this.isVideoPinned && this.pinnedVideoPlayerId == producer_id) { @@ -2240,14 +2261,12 @@ class RoomClient { elem.poster = image.poster; elem.style.objectFit = remoteIsScreen || isBroadcastingEnabled ? 'contain' : 'var(--videoObjFit)'; vb = document.createElement('div'); - vb.setAttribute('id', remotePeerId + '__vb'); - vb.className = 'videoMenuBar fadein'; + vb.id = id + '__vb'; + vb.className = 'videoMenuBar hidden'; eDiv = document.createElement('div'); eDiv.className = 'expand-video'; - eBtn = document.createElement('button'); - eBtn.id = remotePeerId + '_videoExpandBtn'; - eBtn.className = html.expand; + eBtn = this.createButton(remotePeerId + '_videoExpandBtn', html.expand); eVc = document.createElement('div'); eVc.className = 'expand-video-content'; @@ -2257,48 +2276,22 @@ class RoomClient { pv.min = 0; pv.max = 100; pv.value = 100; - pip = document.createElement('button'); - pip.id = id + '__pictureInPicture'; - pip.className = html.pip; - mv = document.createElement('button'); - mv.id = id + '__videoMirror'; - mv.className = html.mirror; - fs = document.createElement('button'); - fs.id = id + '__fullScreen'; - fs.className = html.fullScreen; - ts = document.createElement('button'); - ts.id = id + '__snapshot'; - ts.className = html.snapshot; - pn = document.createElement('button'); - pn.id = id + '__pin'; - pn.className = html.pin; - ha = document.createElement('button'); - ha.id = id + '__hideALL'; - ha.className = html.hideALL + ' focusMode'; - sf = document.createElement('button'); - sf.id = id + '___' + remotePeerId + '___sendFile'; - sf.className = html.sendFile; - sm = document.createElement('button'); - sm.id = id + '___' + remotePeerId + '___sendMsg'; - sm.className = html.sendMsg; - sv = document.createElement('button'); - sv.id = id + '___' + remotePeerId + '___sendVideo'; - sv.className = html.sendVideo; - cm = document.createElement('button'); - cm.id = id + '___' + remotePeerId + '___video'; - cm.className = html.videoOn; - au = document.createElement('button'); - au.id = remotePeerId + '__audio'; - au.className = remotePeerAudio ? html.audioOn : html.audioOff; - gl = document.createElement('button'); - gl.id = id + '___' + remotePeerId + '___geoLocation'; - gl.className = html.geolocation; - ban = document.createElement('button'); - ban.id = id + '___' + remotePeerId + '___ban'; - ban.className = html.ban; - ko = document.createElement('button'); - ko.id = id + '___' + remotePeerId + '___kickOut'; - ko.className = html.kickOut; + + pip = this.createButton(id + '__pictureInPicture', html.pip); + mv = this.createButton(id + '__videoMirror', html.mirror); + fs = this.createButton(id + '__fullScreen', html.fullScreen); + ts = this.createButton(id + '__snapshot', html.snapshot); + pn = this.createButton(id + '__pin', html.pin); + ha = this.createButton(id + '__hideALL', html.hideALL + ' focusMode'); + sf = this.createButton(id + '___' + remotePeerId + '___sendFile', html.sendFile); + sm = this.createButton(id + '___' + remotePeerId + '___sendMsg', html.sendMsg); + sv = this.createButton(id + '___' + remotePeerId + '___sendVideo', html.sendVideo); + cm = this.createButton(id + '___' + remotePeerId + '___video', html.videoOn); + au = this.createButton(remotePeerId + '__audio', remotePeerAudio ? html.audioOn : html.audioOff); + gl = this.createButton(id + '___' + remotePeerId + '___geoLocation', html.geolocation); + ban = this.createButton(id + '___' + remotePeerId + '___ban', html.ban); + ko = this.createButton(id + '___' + remotePeerId + '___kickOut', html.kickOut); + i = document.createElement('i'); i.id = remotePeerId + '__hand'; i.className = html.userHand; @@ -2334,16 +2327,20 @@ class RoomClient { BUTTONS.consumerVideo.videoMirrorButton && vb.appendChild(mv); BUTTONS.consumerVideo.fullScreenButton && this.isVideoFullScreenSupported && vb.appendChild(fs); BUTTONS.consumerVideo.focusVideoButton && vb.appendChild(ha); + if (!this.isMobileDevice) vb.appendChild(pn); + d.appendChild(elem); d.appendChild(i); d.appendChild(p); d.appendChild(pm); - d.appendChild(vb); + //d.appendChild(vb); + document.body.appendChild(vb); this.videoMediaContainer.appendChild(d); await this.attachMediaStream(elem, stream, type, 'Consumer'); this.isVideoPictureInPictureSupported && this.handlePIP(elem.id, pip.id); this.isVideoFullScreenSupported && this.handleFS(elem.id, fs.id); + this.handleVB(d.id, vb.id); this.handleDD(elem.id, remotePeerId); this.handleTS(elem.id, ts.id); this.handleMV(elem.id, mv.id); @@ -2361,8 +2358,11 @@ class RoomClient { this.handleZV(elem.id, d.id, remotePeerId); this.popupPeerInfo(p.id, peer_info); this.checkPeerInfoStatus(peer_info); + if (!remoteIsScreen && remotePrivacyOn) this.setVideoPrivacyStatus(remotePeerId, remotePrivacyOn); + if (remoteIsScreen && !isHideALLVideosActive) pn.click(); + if (isHideALLVideosActive) { isHideALLVideosActive = false; const children = this.videoMediaContainer.children; @@ -2374,7 +2374,9 @@ class RoomClient { btn.style.color = 'white'; }); } + console.log('[addConsumer] Video-element-count', this.videoMediaContainer.childElementCount); + if (!this.isMobileDevice) { this.setTippy(pn.id, 'Toggle Pin', 'bottom'); this.setTippy(ha.id, 'Toggle Focus mode', 'bottom'); @@ -2391,6 +2393,7 @@ class RoomClient { this.setTippy(ban.id, 'Ban', 'bottom'); this.setTippy(ko.id, 'Eject', 'bottom'); } + this.setPeerAudio(remotePeerId, remotePeerAudio); handleAspectRatio(); this.sound('joined'); @@ -2405,13 +2408,16 @@ class RoomClient { let audioConsumerId = remotePeerId + '___pVolume'; this.audioConsumers.set(audioConsumerId, id); let inputPv = this.getId(audioConsumerId); + if (inputPv) { this.handlePV(id + '___' + audioConsumerId); this.setPeerAudio(remotePeerId, remotePeerAudio); } + if (sinkId && speakerSelect.value) { this.changeAudioDestination(elem); } + //elem.addEventListener('play', () => { elem.volume = 0.1 }); console.log('[Add audioConsumers]', this.audioConsumers); break; @@ -2434,6 +2440,8 @@ class RoomClient { if (consumer_kind === 'video') { const d = this.getId(consumer_id + '__video'); + const vb = this.getId(consumer_id + '__vb'); + if (d) { // Check if video is in focus-mode... if (d.hasAttribute('focus-mode')) { @@ -2443,6 +2451,8 @@ class RoomClient { } } d.parentNode.removeChild(d); + vb.parentNode.removeChild(vb); + //alert(this.pinnedVideoPlayerId + '==' + consumer_id); if (this.isVideoPinned && this.pinnedVideoPlayerId == consumer_id) { this.removeVideoPinMediaContainer(); @@ -2494,11 +2504,10 @@ class RoomClient { d.className = 'Camera'; d.id = peer_id + '__videoOff'; vb = document.createElement('div'); - vb.setAttribute('id', peer_id + 'vb'); - vb.className = 'videoMenuBar fadein'; - au = document.createElement('button'); - au.id = peer_id + '__audio'; - au.className = peer_audio ? html.audioOn : html.audioOff; + vb.id = peer_id + '__vb'; + vb.className = 'videoMenuBar hidden'; + au = this.createButton(peer_id + '__audio', peer_audio ? html.audioOn : html.audioOff); + if (remotePeer) { pv = document.createElement('input'); pv.id = peer_id + '___pVolume'; @@ -2506,25 +2515,14 @@ class RoomClient { pv.min = 0; pv.max = 100; pv.value = 100; - sf = document.createElement('button'); - sf.id = 'remotePeer___' + peer_id + '___sendFile'; - sf.className = html.sendFile; - sm = document.createElement('button'); - sm.id = 'remotePeer___' + peer_id + '___sendMsg'; - sm.className = html.sendMsg; - sv = document.createElement('button'); - sv.id = 'remotePeer___' + peer_id + '___sendVideo'; - sv.className = html.sendVideo; - gl = document.createElement('button'); - gl.id = 'remotePeer___' + peer_id + '___geoLocation'; - gl.className = html.geolocation; - ban = document.createElement('button'); - ban.id = 'remotePeer___' + peer_id + '___ban'; - ban.className = html.ban; - ko = document.createElement('button'); - ko.id = 'remotePeer___' + peer_id + '___kickOut'; - ko.className = html.kickOut; + sf = this.createButton('remotePeer___' + peer_id + '___sendFile', html.sendFile); + sm = this.createButton('remotePeer___' + peer_id + '___sendMsg', html.sendMsg); + sv = this.createButton('remotePeer___' + peer_id + '___sendVideo', html.sendVideo); + gl = this.createButton('remotePeer___' + peer_id + '___geoLocation', html.geolocation); + ban = this.createButton('remotePeer___' + peer_id + '___ban', html.ban); + ko = this.createButton('remotePeer___' + peer_id + '___kickOut', html.kickOut); } + i = document.createElement('img'); i.className = 'videoAvatarImage center'; // pulsate i.id = peer_id + '__img'; @@ -2543,6 +2541,7 @@ class RoomClient { pb.className = 'bar'; pb.style.height = '1%'; pm.appendChild(pb); + if (remotePeer) { BUTTONS.videoOff.ejectButton && vb.appendChild(ko); BUTTONS.videoOff.banButton && vb.appendChild(ban); @@ -2557,9 +2556,11 @@ class RoomClient { d.appendChild(p); d.appendChild(h); d.appendChild(pm); - d.appendChild(vb); + //d.appendChild(vb); + document.body.appendChild(vb); this.videoMediaContainer.appendChild(d); BUTTONS.videoOff.muteAudioButton && this.handleAU(au.id); + if (remotePeer) { this.handlePV('remotePeer___' + pv.id); this.handleSM(sm.id); @@ -2569,12 +2570,17 @@ class RoomClient { this.handleBAN(ban.id); this.handleKO(ko.id); } + + this.handleVB(d.id, vb.id); this.handleDD(d.id, peer_id, !remotePeer); this.popupPeerInfo(p.id, peer_info); this.setVideoAvatarImgName(i.id, peer_name); this.getId(i.id).style.display = 'block'; + handleAspectRatio(); + if (isParticipantsListOpen) getRoomParticipants(); + if (!this.isMobileDevice && remotePeer) { this.setTippy(sm.id, 'Send message', 'bottom'); this.setTippy(sf.id, 'Send file', 'bottom'); @@ -2585,10 +2591,11 @@ class RoomClient { this.setTippy(ban.id, 'Ban', 'bottom'); this.setTippy(ko.id, 'Eject', 'bottom'); } + remotePeer ? this.setPeerAudio(peer_id, peer_audio) : this.setIsAudio(peer_id, peer_audio); console.log('[setVideoOff] Video-element-count', this.videoMediaContainer.childElementCount); - // + wbUpdate(); this.editorUpdate(); @@ -2597,7 +2604,11 @@ class RoomClient { } removeVideoOff(peer_id) { - let pvOff = this.getId(peer_id + '__videoOff'); + const pvOff = this.getId(peer_id + '__videoOff'); + const vb = this.getId(peer_id + '__vb'); + + if (vb) vb.parentNode.removeChild(vb); + if (pvOff) { pvOff.parentNode.removeChild(pvOff); handleAspectRatio(); @@ -3302,7 +3313,7 @@ class RoomClient { handleFS(elemId, fsId) { let videoPlayer = this.getId(elemId); let btnFs = this.getId(fsId); - if (btnFs) { + if (videoPlayer && btnFs) { this.setTippy(fsId, 'Full screen', 'bottom'); btnFs.addEventListener('click', () => { if (videoPlayer.classList.contains('videoCircle')) { @@ -3311,19 +3322,6 @@ class RoomClient { videoPlayer.style.pointerEvents = this.isVideoOnFullScreen ? 'auto' : 'none'; this.toggleFullScreen(videoPlayer); }); - } - if (videoPlayer) { - videoPlayer.addEventListener('click', () => { - if (videoPlayer.classList.contains('videoCircle')) { - return this.userLog('info', 'Full Screen not allowed if video on privacy mode', 'top-end'); - } - if (!videoPlayer.hasAttribute('controls')) { - if ((this.isMobileDevice && this.isVideoOnFullScreen) || !this.isMobileDevice) { - videoPlayer.style.pointerEvents = this.isVideoOnFullScreen ? 'auto' : 'none'; - this.toggleFullScreen(videoPlayer); - } - } - }); videoPlayer.addEventListener('fullscreenchange', (e) => { if (!document.fullscreenElement) { videoPlayer.style.pointerEvents = 'auto'; @@ -3495,6 +3493,41 @@ class RoomClient { } } + // #################################################### + // HANDLE VIDEO AND MENU BAR + // #################################################### + + handleVB(videoId, videoBarId) { + const videoPlayer = this.getId(videoId); + const videoBar = this.getId(videoBarId); + if (videoPlayer && videoBar) { + videoPlayer.addEventListener('click', () => { + const videoMenuBar = rc.getEcN('videoMenuBar'); + for (let i = 0; i < videoMenuBar.length; i++) { + const menuBar = videoMenuBar[i]; + if (menuBar.id != videoBarId) { + hide(menuBar); + } + } + + const cameras = rc.getEcN('Camera'); + for (let i = 0; i < cameras.length; i++) { + cameras[i].style.border = 'none'; + } + + if (videoBar.classList.contains('hidden')) { + show(videoBar); + animateCSS(videoBar, 'fadeInDown'); + videoPlayer.style.border = '2px solid #2a7aef'; + } else { + animateCSS(videoBar, 'fadeOutUp').then((msg) => { + hide(videoBar); + }); + } + }); + } + } + // #################################################### // REMOVE VIDEO PIN MEDIA CONTAINER // #################################################### @@ -5982,13 +6015,9 @@ class RoomClient { d.id = '__shareVideo'; vb = document.createElement('div'); vb.setAttribute('id', '__videoBar'); - vb.className = 'videoMenuBar fadein'; - e = document.createElement('button'); - e.className = 'fas fa-times'; - e.id = '__videoExit'; - pn = document.createElement('button'); - pn.id = '__pinUnpin'; - pn.className = html.pin; + vb.className = 'videoMenuBarShare fadein'; + e = this.createButton('__videoExit', 'fas fa-times'); + pn = this.createButton('__pinUnpin', html.pin); if (is_youtube) { video = document.createElement('iframe'); video.setAttribute('title', peer_name); @@ -6711,10 +6740,16 @@ class RoomClient { if (inputPv && audioConsumerPlayer) { inputPv.style.display = 'inline'; inputPv.value = 100; - // Not work on Mobile? - inputPv.addEventListener('input', () => { - audioConsumerPlayer.volume = inputPv.value / 100; - }); + const updateVolume = () => { + const volume = inputPv.value / 100; + this.setAudioVolume(audioConsumerPlayer, volume); + }; + inputPv.addEventListener('input', updateVolume); + inputPv.addEventListener('change', updateVolume); + if (this.isMobileDevice) { + inputPv.addEventListener('touchstart', updateVolume); + inputPv.addEventListener('touchmove', updateVolume); + } } } @@ -8018,17 +8053,9 @@ class RoomClient { vb.setAttribute('id', 'avatar__vb'); vb.className = 'videoMenuBar fadein'; - const fs = document.createElement('button'); - fs.id = 'avatar__fs'; - fs.className = html.fullScreen; - - const pin = document.createElement('button'); - pin.id = 'avatar__pin'; - pin.className = html.pin; - - const ss = document.createElement('button'); - ss.id = 'avatar__stopSession'; - ss.className = html.kickOut; + const fs = this.createButton('avatar__fs', html.fullScreen); + const pin = this.createButton('avatar__pin', html.pin); + const ss = this.createButton('avatar__stopSession', html.kickOut); const avatarName = document.createElement('div'); const an = document.createElement('span'); diff --git a/public/views/Room.html b/public/views/Room.html index 7e3a3fe9..fe951808 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -182,7 +182,7 @@

    Loading

    -
    +
    + From e2c2a753fa6d11aab2c789f3e29ebe58eccafb33 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 10:28:39 +0100 Subject: [PATCH 064/119] [mirotalksfu] - #171 fix typo --- public/js/RoomClient.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 1272b718..368ddc1c 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -3518,11 +3518,12 @@ class RoomClient { if (videoBar.classList.contains('hidden')) { show(videoBar); animateCSS(videoBar, 'fadeInDown'); - videoPlayer.style.border = '2px solid #2a7aef'; + videoPlayer.style.border = '3px solid #2a7aef'; } else { animateCSS(videoBar, 'fadeOutUp').then((msg) => { hide(videoBar); }); + videoPlayer.style.border = 'none'; } }); } From 9d56c80e5a2012469e5768f46c05426ec1ca41b6 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 10:47:30 +0100 Subject: [PATCH 065/119] [mirotalksfu] - #171 fix --- public/css/VideoGrid.css | 2 +- public/js/Room.js | 8 ++++++++ public/js/RoomClient.js | 5 +---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/public/css/VideoGrid.css b/public/css/VideoGrid.css index 8e3b2c35..9b6aef47 100644 --- a/public/css/VideoGrid.css +++ b/public/css/VideoGrid.css @@ -279,6 +279,6 @@ input[type='range'] { .videoMenuBar input, .videoMenuBar button, .videoMenuBarShare button { - font-size: 0.9rem; + font-size: 0.8rem; } } diff --git a/public/js/Room.js b/public/js/Room.js index 2af69fc2..667583b8 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -3224,6 +3224,14 @@ function hideClassElements(className) { for (let i = 0; i < elements.length; i++) { hide(elements[i]); } + setCamerasBorderNone(); +} + +function setCamerasBorderNone() { + const cameras = rc.getEcN('Camera'); + for (let i = 0; i < cameras.length; i++) { + cameras[i].style.border = 'none'; + } } function toggleExtraButtons() { diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 368ddc1c..8813cc9d 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -3510,10 +3510,7 @@ class RoomClient { } } - const cameras = rc.getEcN('Camera'); - for (let i = 0; i < cameras.length; i++) { - cameras[i].style.border = 'none'; - } + setCamerasBorderNone(); if (videoBar.classList.contains('hidden')) { show(videoBar); From 04ae9fdf8504db487ae256c1f3267b862735fe69 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 11:05:06 +0100 Subject: [PATCH 066/119] [mirotalksfu] - #171 add missing --- public/js/RoomClient.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 8813cc9d..f41181e9 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -6751,6 +6751,22 @@ class RoomClient { } } + setAudioVolume(audioConsumerPlayer, volume) { + if (audioConsumerPlayer) { + if (this.isMobileDevice) { + // On mobile, we'll use a different approach + audioConsumerPlayer.muted = volume === 0; + if (!audioConsumerPlayer.muted) { + // We can only set volume to 1 on mobile, so we'll adjust playback rate instead + audioConsumerPlayer.playbackRate = Math.max(0.1, volume); + } + } else { + // On desktop, we can directly set the volume + audioConsumerPlayer.volume = volume; + } + } + } + // #################################################### // HANDLE DOMINANT SPEAKER // ################################################### From e6a6e81e9fdee96dc607160281f26d5d617040d0 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 20:06:34 +0100 Subject: [PATCH 067/119] [mirotalksfu] - #171 fix, improve UI/UX, update dep --- app/src/Server.js | 2 +- package.json | 6 +- public/css/VideoGrid.css | 126 ++++++++++++++++++++++++++++++++++----- public/js/Room.js | 4 +- public/js/RoomClient.js | 41 +++++++++++-- 5 files changed, 155 insertions(+), 24 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 4ad5f3fd..11fe2e19 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.11 + * @version 1.6.12 * */ diff --git a/package.json b/package.json index 55622cd5..370dd21f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.6.11", + "version": "1.6.12", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -58,10 +58,10 @@ }, "dependencies": { "@mattermost/client": "^10.0.0", - "@sentry/node": "^8.35.0", + "@sentry/node": "^8.36.0", "axios": "^1.7.7", "colors": "1.4.0", - "compression": "1.7.4", + "compression": "1.7.5", "cors": "2.8.5", "crypto-js": "4.2.0", "discord.js": "^14.16.3", diff --git a/public/css/VideoGrid.css b/public/css/VideoGrid.css index 9b6aef47..e3c1c8cd 100644 --- a/public/css/VideoGrid.css +++ b/public/css/VideoGrid.css @@ -132,6 +132,25 @@ overflow: hidden; } +.videoMenuBarClose { + position: absolute; + display: flex; + top: 30px; + right: 30px; + padding: 10px; + border-radius: 50%; + color: white; + align-items: center; + justify-content: center; + cursor: pointer; + user-select: none; + background: var(--body-bg); +} + +.videoMenuBarClose:hover { + background: var(--btns-bg-color); +} + .videoMenuBarShare { z-index: 2; position: absolute; @@ -166,15 +185,97 @@ transition: all 0.3s ease-in-out; } +.expand-video { + position: fixed; + left: 10px; +} + +.expand-video .dropdown-button { + cursor: pointer; +} + .expand-video-content { - position: relative; + z-index: 1; display: none; - float: right; - width: auto; + position: fixed; + min-width: 50%; + padding: 20px; + border-radius: 5px; + background: var(--body-bg); + box-shadow: var(--box-shadow); } .expand-video:hover .expand-video-content { - display: inline-flex; + z-index: 1; + display: grid !important; + grid-gap: 5px 5px; + grid-template-columns: 50%; + grid-template-areas: + 'header header' + 'controls controls'; + align-content: start; + justify-items: start; + overflow-y: auto; +} + +.peer-name-container { + display: row; + width: 100%; + height: 100%; + padding: 10px; + margin: 10px; +} + +.expand-video-content .peer-name-header { + grid-area: header; + width: 100%; + padding: 40px; + height: 120px; + background: var(--btns-bg-color); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + border-radius: 10px; + margin-bottom: 10px; + display: flex; + align-items: center; + justify-content: center; +} + +.expand-video-content .peer-name { + font-size: 18px; + font-weight: bold; + color: #fff; + text-shadow: 0 0 10px rgba(0, 0, 0, 0.5); + background-color: rgba(36, 36, 36, 0.8); + border-radius: 10px; + padding: 6px; + width: 100%; +} + +.expand-video-content input[type='range'] { + display: inline !important; + width: 100%; + margin: 16px 0; + background: rgba(255, 255, 255, 0.1); + height: 6px; +} + +.expand-video-content button { + display: flex !important; + font-size: 16px; + color: #fff; + background: var(--btns-bg-color); + width: 100%; + height: 45px; + justify-content: center; + align-items: center; + border-radius: 10px; +} + +.expand-video-content button:hover { + color: white; + background: var(--body-bg); } #videoMediaContainer video { @@ -262,23 +363,20 @@ input[type='range'] { } } -@media screen and (max-width: 600px) { +@media screen and (max-width: 500px) { .username { - font-size: 12px; + font-size: 10px; } .videoMenuBar input, .videoMenuBar button, .videoMenuBarShare button { font-size: 1rem; } -} -@media screen and (max-width: 500px) { - .username { - font-size: 10px; + .expand-video-content { + min-width: 100%; + left: 0px; } - .videoMenuBar input, - .videoMenuBar button, - .videoMenuBarShare button { - font-size: 0.8rem; + .expand-video-content .peer-name { + font-size: 10px; } } diff --git a/public/js/Room.js b/public/js/Room.js index 667583b8..dcf35fdf 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.11 + * @version 1.6.12 * */ @@ -4541,7 +4541,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.6.11', + title: 'WebRTC SFU v1.6.12', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index f41181e9..b3a2f0fe 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -43,9 +43,10 @@ const html = { bg: 'fas fa-circle-half-stroke', pin: 'fas fa-map-pin', videoPrivacy: 'far fa-circle', - expand: 'fas fa-ellipsis-vertical', + expand: 'fas fa-bars dropdown-button', hideALL: 'fas fa-eye', mirror: 'fas fa-arrow-right-arrow-left', + close: 'fas fa-times', }; const icons = { @@ -2307,17 +2308,38 @@ class RoomClient { pb.className = 'bar'; pb.style.height = '1%'; pm.appendChild(pb); + + const peerNameHeader = document.createElement('div'); + peerNameHeader.className = 'peer-name-header'; + + const peerNameContainer = document.createElement('div'); + peerNameContainer.className = 'peer-name-container'; + + const peerNameSpan = document.createElement('span'); + peerNameSpan.className = 'peer-name'; + peerNameSpan.textContent = peer_name; + + this.addCloseVBButton(peerNameHeader); + + peerNameContainer.appendChild(peerNameSpan); + + BUTTONS.consumerVideo.audioVolumeInput && peerNameContainer.appendChild(pv); + peerNameHeader.appendChild(peerNameContainer); + + vb.appendChild(peerNameHeader); + eVc.appendChild(peerNameHeader); + BUTTONS.consumerVideo.sendMessageButton && eVc.appendChild(sm); BUTTONS.consumerVideo.sendFileButton && eVc.appendChild(sf); BUTTONS.consumerVideo.sendVideoButton && eVc.appendChild(sv); BUTTONS.consumerVideo.geolocationButton && eVc.appendChild(gl); BUTTONS.consumerVideo.banButton && eVc.appendChild(ban); BUTTONS.consumerVideo.ejectButton && eVc.appendChild(ko); + eDiv.appendChild(eBtn); eDiv.appendChild(eVc); - vb.appendChild(eDiv); - BUTTONS.consumerVideo.audioVolumeInput && !this.isMobileDevice && vb.appendChild(pv); + vb.appendChild(au); vb.appendChild(cm); BUTTONS.consumerVideo.snapShotButton && vb.appendChild(ts); @@ -3513,9 +3535,10 @@ class RoomClient { setCamerasBorderNone(); if (videoBar.classList.contains('hidden')) { + rc.sound('open'); show(videoBar); animateCSS(videoBar, 'fadeInDown'); - videoPlayer.style.border = '3px solid #2a7aef'; + videoPlayer.style.border = '1px solid #2a7aef'; } else { animateCSS(videoBar, 'fadeOutUp').then((msg) => { hide(videoBar); @@ -3526,6 +3549,16 @@ class RoomClient { } } + addCloseVBButton(containerElement) { + const closeBtn = document.createElement('div'); + closeBtn.className = `${html.close} videoMenuBarClose`; + closeBtn.addEventListener('click', (e) => { + e.stopPropagation(); + hideClassElements('videoMenuBar'); + }); + containerElement.appendChild(closeBtn); + } + // #################################################### // REMOVE VIDEO PIN MEDIA CONTAINER // #################################################### From 320b0ced4cfc5638e3b93ac1f53b9f502399c9cb Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 20:49:50 +0100 Subject: [PATCH 068/119] [mirotalksfu] - #171 fix videoMenuBar width --- public/js/RoomClient.js | 25 +++++++++++++++++++++++++ public/js/Transcription.js | 2 ++ 2 files changed, 27 insertions(+) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index b3a2f0fe..9a5e85d4 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -3532,6 +3532,7 @@ class RoomClient { } } + rc.resizeVideoMenuBar(); setCamerasBorderNone(); if (videoBar.classList.contains('hidden')) { @@ -3549,6 +3550,22 @@ class RoomClient { } } + resizeVideoMenuBar() { + const somethingPinned = + this.isVideoPinned || + this.isChatPinned || + this.isEditorPinned || + this.isPollPinned || + transcription.isPin(); + const menuBarWidth = + this.isVideoPinned || this.isChatPinned || this.isPollPinned || transcription.isPin() ? '75%' : '70%'; + const videoMenuBar = rc.getEcN('videoMenuBar'); + for (let i = 0; i < videoMenuBar.length; i++) { + const menuBar = videoMenuBar[i]; + menuBar.style.width = somethingPinned ? menuBarWidth : '100%'; + } + } + addCloseVBButton(containerElement) { const closeBtn = document.createElement('div'); closeBtn.className = `${html.close} videoMenuBarClose`; @@ -3586,6 +3603,7 @@ class RoomClient { this.videoMediaContainer.style.top = 0; this.videoMediaContainer.style.width = '75%'; this.videoMediaContainer.style.height = '100%'; + this.resizeVideoMenuBar(); } videoMediaContainerUnpin() { @@ -3593,6 +3611,7 @@ class RoomClient { this.videoMediaContainer.style.right = null; this.videoMediaContainer.style.width = '100%'; this.videoMediaContainer.style.height = '100%'; + this.resizeVideoMenuBar(); } adaptVideoObjectFit(index) { @@ -3843,6 +3862,7 @@ class RoomClient { this.chatPinned(); this.isChatPinned = true; setColor(chatTogglePin, 'lime'); + this.resizeVideoMenuBar(); resizeVideoMedia(); chatRoom.style.resize = 'none'; if (!this.isMobileDevice) this.makeUnDraggable(chatRoom, chatHeader); @@ -3861,6 +3881,7 @@ class RoomClient { this.chatCenter(); this.isChatPinned = false; setColor(chatTogglePin, 'white'); + this.resizeVideoMenuBar(); resizeVideoMedia(); if (!this.isMobileDevice) this.makeDraggable(chatRoom, chatHeader); if (!this.isPlistOpen()) this.toggleShowParticipants(); @@ -4489,6 +4510,7 @@ class RoomClient { this.pollPinned(); this.isPollPinned = true; setColor(pollTogglePin, 'lime'); + this.resizeVideoMenuBar(); resizeVideoMedia(); pollRoom.style.resize = 'none'; if (!this.isMobileDevice) this.makeUnDraggable(pollRoom, pollHeader); @@ -4503,6 +4525,7 @@ class RoomClient { this.pollCenter(); this.isPollPinned = false; setColor(pollTogglePin, 'white'); + this.resizeVideoMenuBar(); resizeVideoMedia(); if (!this.isMobileDevice) this.makeDraggable(pollRoom, pollHeader); } @@ -4834,6 +4857,7 @@ class RoomClient { this.editorPinned(); this.isEditorPinned = true; setColor(editorTogglePin, 'lime'); + this.resizeVideoMenuBar(); resizeVideoMedia(); document.documentElement.style.setProperty('--editor-height', '80vh'); //if (!this.isMobileDevice) this.makeUnDraggable(editorRoom, editorHeader); @@ -4848,6 +4872,7 @@ class RoomClient { this.pollCenter(); this.isEditorPinned = false; setColor(editorTogglePin, 'white'); + this.resizeVideoMenuBar(); resizeVideoMedia(); document.documentElement.style.setProperty('--editor-height', '85vh'); //if (!this.isMobileDevice) this.makeDraggable(editorRoom, editorHeader); diff --git a/public/js/Transcription.js b/public/js/Transcription.js index a37bfce9..7cf1cd2b 100644 --- a/public/js/Transcription.js +++ b/public/js/Transcription.js @@ -318,6 +318,7 @@ class Transcription { transcriptionRoom.style.transform = null; document.documentElement.style.setProperty('--transcription-width', '25%'); document.documentElement.style.setProperty('--transcription-height', '100%'); + rc.resizeVideoMenuBar(); } unpinned() { @@ -334,6 +335,7 @@ class Transcription { this.center(); this.isPinned = false; setColor(transcriptionTogglePinBtn, 'white'); + rc.resizeVideoMenuBar(); resizeVideoMedia(); resizeTranscriptionRoom(); transcriptionRoom.style.resize = 'both'; From fe1bf786a26bec16fbb9751708a88bbe5691b13a Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 21:11:28 +0100 Subject: [PATCH 069/119] [mirotalksfu] - #171 improve username UI --- public/css/VideoGrid.css | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/public/css/VideoGrid.css b/public/css/VideoGrid.css index e3c1c8cd..032d6415 100644 --- a/public/css/VideoGrid.css +++ b/public/css/VideoGrid.css @@ -96,12 +96,12 @@ font-size: 10px; display: flex; align-items: center; - padding: 5px; - margin: 5px; + padding: 10px; + margin: 10px; width: auto; height: 25px; border-radius: 5px; - background: rgba(0, 0, 0, 0.1); + background: var(--body-bg); } .fscreen { @@ -246,8 +246,7 @@ font-size: 18px; font-weight: bold; color: #fff; - text-shadow: 0 0 10px rgba(0, 0, 0, 0.5); - background-color: rgba(36, 36, 36, 0.8); + background: var(--body-bg); border-radius: 10px; padding: 6px; width: 100%; From dc00ee4403cac86e1aedcb507c7bd4c89f94191e Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 31 Oct 2024 23:01:03 +0100 Subject: [PATCH 070/119] [mirotalksfu] - #171 improve VideoManuBar UI --- public/css/VideoGrid.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/css/VideoGrid.css b/public/css/VideoGrid.css index 032d6415..2bf71498 100644 --- a/public/css/VideoGrid.css +++ b/public/css/VideoGrid.css @@ -122,12 +122,13 @@ display: inline; top: 0; left: 0; - padding: 20px; - background: rgba(0, 0, 0, 0.9); + padding: 15px; + width: 100%; font-size: small; font-weight: bold; text-align: center; - width: 100%; + background: var(--body-bg); + box-shadow: var(--box-shadow); cursor: default; overflow: hidden; } @@ -376,6 +377,6 @@ input[type='range'] { left: 0px; } .expand-video-content .peer-name { - font-size: 10px; + font-size: 12px; } } From cfd4342ad5d2b51156cd048443dbd94f85c893fc Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 1 Nov 2024 09:12:59 +0100 Subject: [PATCH 071/119] [mirotalksfu] - improve toggleExtraButton --- public/js/Room.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/js/Room.js b/public/js/Room.js index dcf35fdf..dd04f342 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -1812,6 +1812,9 @@ function handleButtons() { toggleExtraButton.onclick = async () => { toggleExtraButtons(); }; + toggleExtraButton.onmouseover = () => { + show(control); + }; startAudioButton.onclick = async () => { const moderator = rc.getModerator(); if (moderator.audio_cant_unmute) { From 6dd3f4ef44371d6c3fac4e077306d2a103daa0f2 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 1 Nov 2024 09:47:13 +0100 Subject: [PATCH 072/119] [mirotalksfu] - remove boxShadow to videoMenuBar --- public/css/VideoGrid.css | 1 - 1 file changed, 1 deletion(-) diff --git a/public/css/VideoGrid.css b/public/css/VideoGrid.css index 2bf71498..887e2445 100644 --- a/public/css/VideoGrid.css +++ b/public/css/VideoGrid.css @@ -128,7 +128,6 @@ font-weight: bold; text-align: center; background: var(--body-bg); - box-shadow: var(--box-shadow); cursor: default; overflow: hidden; } From c380d29111ad7f0fe9ced07306fd53b39ddbd198 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 1 Nov 2024 10:30:56 +0100 Subject: [PATCH 073/119] [mirotalksfu] - add missing --- public/js/Room.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/Room.js b/public/js/Room.js index dd04f342..9c774fdb 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -1814,6 +1814,7 @@ function handleButtons() { }; toggleExtraButton.onmouseover = () => { show(control); + hideClassElements('videoMenuBar'); }; startAudioButton.onclick = async () => { const moderator = rc.getModerator(); From 1a967292bf145d003ec68fe34975029737c371e1 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 1 Nov 2024 18:35:48 +0100 Subject: [PATCH 074/119] [mirotalksfu] - improvements --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index 11fe2e19..a621a6ab 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.12 + * @version 1.6.13 * */ diff --git a/package.json b/package.json index 370dd21f..d09f2c1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.6.12", + "version": "1.6.13", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index 9c774fdb..6a204aa6 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.12 + * @version 1.6.13 * */ @@ -4545,7 +4545,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.6.12', + title: 'WebRTC SFU v1.6.13', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 9a5e85d4..c96dbfb8 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -3539,7 +3539,7 @@ class RoomClient { rc.sound('open'); show(videoBar); animateCSS(videoBar, 'fadeInDown'); - videoPlayer.style.border = '1px solid #2a7aef'; + if (participantsCount > 1) videoPlayer.style.border = '0.1px solid #2a7aef'; } else { animateCSS(videoBar, 'fadeOutUp').then((msg) => { hide(videoBar); From 72ec1b6de62c394b14e69c6e0bbd6d2fddf19326 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 1 Nov 2024 19:18:50 +0100 Subject: [PATCH 075/119] [mirotalksfu] - add missing --- public/js/RoomClient.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index c96dbfb8..fa7ab502 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -3413,6 +3413,7 @@ class RoomClient { this.removeVideoPinMediaContainer(); setColor(btnPn, 'white'); } + this.resizeVideoMenuBar(); handleAspectRatio(); }); From cc96da060c69f76a5ff71b55de960576a6f4684c Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 1 Nov 2024 23:42:56 +0100 Subject: [PATCH 076/119] [mirotalksfu] - fix toggleExtraButtons --- public/css/Room.css | 2 +- public/js/Room.js | 23 +++++++++++++---------- public/views/Room.html | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/public/css/Room.css b/public/css/Room.css index 56622bda..621c0a62 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -163,7 +163,7 @@ body { #control { z-index: 3; position: absolute; - display: flex; + display: none; padding: 5px; top: var(--btns-top); diff --git a/public/js/Room.js b/public/js/Room.js index 6a204aa6..4ba827ef 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -1809,12 +1809,14 @@ function handleButtons() { lowerHandButton.onclick = () => { rc.updatePeerInfo(peer_name, socket.id, 'hand', false); }; - toggleExtraButton.onclick = async () => { + toggleExtraButton.onclick = () => { toggleExtraButtons(); }; toggleExtraButton.onmouseover = () => { - show(control); - hideClassElements('videoMenuBar'); + if (DetectRTC.isMobileDevice) return; + if (control.style.display === 'none') { + toggleExtraButtons(); + } }; startAudioButton.onclick = async () => { const moderator = rc.getModerator(); @@ -3213,8 +3215,7 @@ function showButtons() { function checkButtonsBar() { if (!isButtonsBarOver) { - // hideClassElements('videoMenuBar'); - hide(control); + control.style.display = 'none'; bottomButtons.style.display = 'none'; isButtonsVisible = false; } @@ -3223,6 +3224,13 @@ function checkButtonsBar() { }, 10000); } +function toggleExtraButtons() { + control.style.display === 'none' || control.style.display === '' + ? elemDisplay('control', true, 'flex') + : elemDisplay('control', false); + hideClassElements('videoMenuBar'); +} + function hideClassElements(className) { const elements = rc.getEcN(className); for (let i = 0; i < elements.length; i++) { @@ -3238,11 +3246,6 @@ function setCamerasBorderNone() { } } -function toggleExtraButtons() { - control.classList.contains('hidden') ? show(control) : hide(control); - hideClassElements('videoMenuBar'); -} - // https://animate.style function animateCSS(element, animation, prefix = 'animate__') { diff --git a/public/views/Room.html b/public/views/Room.html index fe951808..b9810b8f 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -182,7 +182,7 @@

    Loading

    -
  • @@ -700,7 +700,7 @@

    Moderator options

    @@ -713,7 +713,7 @@

    Moderator options

    @@ -736,7 +736,7 @@

    Moderator options

    @@ -754,7 +754,7 @@

    Moderator options

    @@ -772,7 +772,7 @@

    Moderator options

    @@ -790,7 +790,7 @@

    Moderator options

    @@ -808,7 +808,7 @@

    Moderator options

    @@ -826,7 +826,7 @@

    Moderator options

    From 1322e8194f46e2eff17027e923b3d0d4380dc26e Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 7 Nov 2024 14:52:39 +0100 Subject: [PATCH 102/119] [mirotalksfu] - fix typo --- public/css/Room.css | 5 +++-- public/views/Room.html | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/public/css/Room.css b/public/css/Room.css index edc3e15e..870dd6df 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -720,9 +720,10 @@ th { display: block; } +/* moderator title */ .mod-title { - margin-top: 5px; - color: grey; + font-size: 1.1rem; + color: #c2c2c2; } /*-------------------------------------------------------------- diff --git a/public/views/Room.html b/public/views/Room.html index c19eb142..6fc0efe2 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -675,7 +675,7 @@

    Loading

    -

    Moderator options for Everyone

    + Moderator options for Everyone
    From 5676cfbd2c0fdc0e9f379067c0ea9aaa06b4cf5a Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 7 Nov 2024 20:12:13 +0100 Subject: [PATCH 103/119] [mirotalksfu] - #180 start shared media on join room --- app/src/Room.js | 12 ++++++++++++ app/src/Server.js | 4 +++- package.json | 2 +- public/js/Room.js | 4 ++-- public/js/RoomClient.js | 19 ++++++++++++++----- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/app/src/Room.js b/app/src/Room.js index acf53b2b..402dda3f 100644 --- a/app/src/Room.js +++ b/app/src/Room.js @@ -67,6 +67,9 @@ module.exports = class Room { this.polls = []; this.isHostProtected = config.host.protected; + + // Share Media + this.shareMediaData = {}; } // #################################################### @@ -95,10 +98,19 @@ module.exports = class Room { redirect: this.redirect, videoAIEnabled: this.videoAIEnabled, thereIsPolls: this.thereIsPolls(), + shareMediaData: this.shareMediaData, peers: JSON.stringify([...this.peers]), }; } + // ############################################## + // SHARE MEDIA + // ############################################## + + updateShareMedia(data) { + this.shareMediaData = data; + } + // ############################################## // POLLS // ############################################## diff --git a/app/src/Server.js b/app/src/Server.js index e0765430..da96ed4f 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.25 + * @version 1.6.26 * */ @@ -2086,6 +2086,8 @@ function startServer() { const room = getRoom(socket); + room.updateShareMedia(data); + data.peer_id == 'all' ? room.broadCast(socket.id, 'shareVideoAction', data) : room.sendTo(data.peer_id, 'shareVideoAction', data); diff --git a/package.json b/package.json index 2b9a4e7e..b9efe816 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.6.25", + "version": "1.6.26", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index dd7dcae6..bc643e3c 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.25 + * @version 1.6.26 * */ @@ -4564,7 +4564,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.6.25', + title: 'WebRTC SFU v1.6.26', html: `
    diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index cd9c151d..05009975 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -601,6 +601,15 @@ class RoomClient { if (room.hostProtected) { RoomURL = window.location.origin + '/join/?room=' + room_id; } + + // Share Media Data on Join + if ( + room.shareMediaData && + Object.keys(room.shareMediaData).length !== 0 && + room.shareMediaData.action === 'open' + ) { + this.shareVideoAction(room.shareMediaData); + } } // PARTICIPANTS @@ -6093,9 +6102,9 @@ class RoomClient { }).then((result) => { if (result.value) { result.value = filterXSS(result.value); - if (!this.thereAreParticipants()) { - return userLog('info', 'No participants detected', 'top-end'); - } + // if (!this.thereAreParticipants()) { + // return userLog('info', 'No participants detected', 'top-end'); + // } if (!this.isVideoTypeSupported(result.value)) { return userLog('warning', 'Something wrong, try with another Video or audio URL'); } @@ -6169,8 +6178,8 @@ class RoomClient { } shareVideoAction(data) { - let peer_name = data.peer_name; - let action = data.action; + const { peer_name, action } = data; + switch (action) { case 'open': this.userLog('info', `${peer_name} opened the video`, 'top-end'); From f9827dac79fd70ef9f0f373125c08aaec4a38a9d Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Thu, 7 Nov 2024 20:41:13 +0100 Subject: [PATCH 104/119] [mirotalksfu] - improvements --- app/src/Server.js | 2 +- package.json | 2 +- public/js/Room.js | 4 ++-- public/views/Room.html | 12 ++---------- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index da96ed4f..19706be6 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -55,7 +55,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.26 + * @version 1.6.27 * */ diff --git a/package.json b/package.json index b9efe816..d3e6761f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.6.26", + "version": "1.6.27", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/js/Room.js b/public/js/Room.js index bc643e3c..d4efd278 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.6.26 + * @version 1.6.27 * */ @@ -4564,7 +4564,7 @@ function showAbout() { imageUrl: image.about, customClass: { image: 'img-about' }, position: 'center', - title: 'WebRTC SFU v1.6.26', + title: 'WebRTC SFU v1.6.27', html: `
    diff --git a/public/views/Room.html b/public/views/Room.html index 6fc0efe2..164e1924 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -860,11 +860,7 @@

    Loading

    -
    -
    - -