[mirotalksfu] - Add Support for Custom Avatar via Options Object
هذا الالتزام موجود في:
93
README.md
93
README.md
@@ -287,25 +287,82 @@ To embed a meeting within `your service or app` using an iframe, you can use the
|
||||
|
||||
- `Rest API:` The [API documentation](https://docs.mirotalk.com/mirotalk-sfu/api/) uses [swagger](https://swagger.io/) at https://localhost:3010/api/v1/docs or check it on live [here](https://sfu.mirotalk.com/api/v1/docs).
|
||||
|
||||
### 1. Get Server Statistics
|
||||
|
||||
```bash
|
||||
# The response will give you the total of rooms and users.
|
||||
$ curl -X GET "http://localhost:3010/api/v1/stats" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json"
|
||||
$ curl -X GET "https://sfu.mirotalk.com/api/v1/stats" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json"
|
||||
# The response will give you the active meetings (default disabled).
|
||||
$ curl -X GET "http://localhost:3010/api/v1/meetings" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json"
|
||||
$ curl -X GET "https://sfu.mirotalk.com/api/v1/meetings" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json"
|
||||
# The response will give you a entrypoint / Room URL for your meeting.
|
||||
$ curl -X POST "http://localhost:3010/api/v1/meeting" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json"
|
||||
$ curl -X POST "https://sfu.mirotalk.com/api/v1/meeting" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json"
|
||||
# The response will give you a entrypoint / URL for the direct join to the meeting.
|
||||
$ curl -X POST "http://localhost:3010/api/v1/join" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json" --data '{"room":"test","roomPassword":"false","name":"mirotalksfu","audio":"false","video":"false","screen":"false","notify":"false","duration":"unlimited"}'
|
||||
$ curl -X POST "https://sfu.mirotalk.com/api/v1/join" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json" --data '{"room":"test","roomPassword":"false","name":"mirotalksfu","audio":"false","video":"false","screen":"false","notify":"false","duration":"unlimited"}'
|
||||
# The response will give you a entrypoint / URL for the direct join to the meeting with a token.
|
||||
$ curl -X POST "http://localhost:3010/api/v1/join" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json" --data '{"room":"test","roomPassword":"false","name":"mirotalksfu","audio":"false","video":"false","screen":"false","notify":"false","duration":"unlimited","token":{"username":"username","password":"password","presenter":"true", "expire":"1h"}}'
|
||||
$ curl -X POST "https://sfu.mirotalk.com/api/v1/join" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json" --data '{"room":"test","roomPassword":"false","name":"mirotalksfu","audio":"false","video":"false","screen":"false","notify":"false","duration":"unlimited","token":{"username":"username","password":"password","presenter":"true", "expire":"1h"}}'
|
||||
# The response will give you a valid token for a meeting (default diabled)
|
||||
$ curl -X POST "http://localhost:3010/api/v1/token" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json" --data '{"username":"username","password":"password","presenter":"true", "expire":"1h"}'
|
||||
$ curl -X POST "https://sfu.mirotalk.com/api/v1/token" -H "authorization: mirotalksfu_default_secret" -H "Content-Type: application/json" --data '{"username":"username","password":"password","presenter":"true", "expire":"1h"}'
|
||||
curl -X GET "http://localhost:3010/api/v1/stats" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
curl -X GET "https://sfu.mirotalk.com/api/v1/stats" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
### 2. Get Active Meetings
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:3010/api/v1/meetings" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
curl -X GET "https://sfu.mirotalk.com/api/v1/meetings" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
### 3. Create Meeting
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:3010/api/v1/meeting" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
curl -X POST "https://sfu.mirotalk.com/api/v1/meeting" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
### 4. Join Meeting (Basic)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:3010/api/v1/join" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"room":"test","roomPassword":false,"avatar":false,"name":"mirotalksfu","audio":false,"video":false,"screen":false,"notify":false,"duration":"unlimited"}'
|
||||
|
||||
curl -X POST "https://sfu.mirotalk.com/api/v1/join" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"room":"test","roomPassword":false,"name":"mirotalksfu","avatar":false,"audio":false,"video":false,"screen":false,"notify":false,"duration":"unlimited"}'
|
||||
```
|
||||
|
||||
### 5. Join Meeting with Token
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:3010/api/v1/join" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"room":"test","roomPassword":false,"name":"mirotalksfu","audio":false,"video":false,"screen":false,"notify":false,"duration":"unlimited","token":{"username":"username","password":"password","presenter":true,"expire":"1h"}}'
|
||||
|
||||
curl -X POST "https://sfu.mirotalk.com/api/v1/join" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"room":"test","roomPassword":false,"name":"mirotalksfu","audio":false,"video":false,"screen":false,"notify":false,"duration":"unlimited","token":{"username":"username","password":"password","presenter":true,"expire":"1h"}}'
|
||||
```
|
||||
|
||||
### 6. Generate Token
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:3010/api/v1/token" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"username":"username","password":"password","presenter":true,"expire":"1h"}'
|
||||
|
||||
curl -X POST "https://sfu.mirotalk.com/api/v1/token" \
|
||||
-H "authorization: mirotalksfu_default_secret" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"username":"username","password":"password","presenter":true,"expire":"1h"}'
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
@@ -19,9 +19,10 @@ async function getJoin() {
|
||||
room: 'test',
|
||||
roomPassword: false,
|
||||
name: 'mirotalksfu',
|
||||
audio: true,
|
||||
video: true,
|
||||
screen: true,
|
||||
avatar: false,
|
||||
audio: false,
|
||||
video: false,
|
||||
screen: false,
|
||||
hide: false,
|
||||
notify: true,
|
||||
duration: 'unlimited',
|
||||
|
||||
@@ -20,9 +20,10 @@ $data = array(
|
||||
"room" => "test",
|
||||
"roomPassword" => false,
|
||||
"name" => "mirotalksfu",
|
||||
"audio" => true,
|
||||
"video" => true,
|
||||
"screen" => true,
|
||||
"avatar" => false,
|
||||
"audio" => false,
|
||||
"video" => false,
|
||||
"screen" => false,
|
||||
"hide" => false,
|
||||
"notify" => true,
|
||||
"duration" => "unlimited",
|
||||
|
||||
@@ -15,9 +15,10 @@ data = {
|
||||
"room": "test",
|
||||
"roomPassword": "false",
|
||||
"name": "mirotalksfu",
|
||||
"audio": "true",
|
||||
"video": "true",
|
||||
"screen": "true",
|
||||
"avatar": "false",
|
||||
"audio": "false",
|
||||
"video": "false",
|
||||
"screen": "false",
|
||||
"hide": "false",
|
||||
"notify": "true",
|
||||
"duration": "unlimited",
|
||||
|
||||
@@ -1,11 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration
|
||||
API_KEY_SECRET="mirotalksfu_default_secret"
|
||||
MIROTALK_URL="https://sfu.mirotalk.com/api/v1/join"
|
||||
# Alternative URL for local testing:
|
||||
# MIROTALK_URL="http://localhost:3010/api/v1/join"
|
||||
|
||||
curl $MIROTALK_URL \
|
||||
--header "authorization: $API_KEY_SECRET" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data '{"room":"test","roomPassword":"false","name":"mirotalksfu","audio":"true","video":"true","screen":"false","hide":"false","notify":"true","duration":"unlimited","token":{"username":"username","password":"password","presenter":"true", "expire":"1h"}}' \
|
||||
--request POST
|
||||
# Request data with proper JSON formatting
|
||||
REQUEST_DATA='{
|
||||
"room": "test",
|
||||
"roomPassword": false,
|
||||
"name": "mirotalksfu",
|
||||
"avatar": false,
|
||||
"audio": false,
|
||||
"video": false,
|
||||
"screen": false,
|
||||
"hide": false,
|
||||
"notify": true,
|
||||
"duration": "unlimited",
|
||||
"token": {
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
"presenter": true,
|
||||
"expire": "1h"
|
||||
}
|
||||
}'
|
||||
|
||||
# Make the API request
|
||||
curl -X POST "$MIROTALK_URL" \
|
||||
-H "Authorization: $API_KEY_SECRET" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$REQUEST_DATA"
|
||||
@@ -162,6 +162,9 @@ definitions:
|
||||
name:
|
||||
type: string
|
||||
default: 'mirotalksfu'
|
||||
avatar:
|
||||
type: ['boolean', 'string'] # Allow boolean or string type
|
||||
default: false
|
||||
audio:
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -212,6 +215,8 @@ definitions:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
avatar:
|
||||
type: string
|
||||
presenter:
|
||||
type: boolean
|
||||
video:
|
||||
|
||||
@@ -10,6 +10,7 @@ module.exports = class Peer {
|
||||
const {
|
||||
peer_uuid,
|
||||
peer_name,
|
||||
peer_avatar,
|
||||
peer_presenter,
|
||||
peer_audio,
|
||||
peer_audio_volume,
|
||||
@@ -23,6 +24,7 @@ module.exports = class Peer {
|
||||
this.peer_info = peer_info;
|
||||
this.peer_uuid = peer_uuid;
|
||||
this.peer_name = peer_name;
|
||||
this.peer_avatar = peer_avatar;
|
||||
this.peer_presenter = peer_presenter;
|
||||
this.peer_audio = peer_audio;
|
||||
this.peer_video = peer_video;
|
||||
|
||||
@@ -64,7 +64,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.8.12
|
||||
* @version 1.8.13
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -68,11 +68,12 @@ module.exports = class ServerApi {
|
||||
|
||||
getJoinURL(data) {
|
||||
// Get data
|
||||
const { room, roomPassword, name, audio, video, screen, hide, notify, duration, token } = data;
|
||||
const { room, roomPassword, name, avatar, audio, video, screen, hide, notify, duration, token } = data;
|
||||
|
||||
const roomValue = room || uuidV4();
|
||||
const nameValue = name || 'User-' + this.getRandomNumber();
|
||||
const roomPasswordValue = roomPassword || false;
|
||||
const nameValue = name || 'User-' + this.getRandomNumber();
|
||||
const avatarValue = avatar || false;
|
||||
const audioValue = audio || false;
|
||||
const videoValue = video || false;
|
||||
const screenValue = screen || false;
|
||||
@@ -88,6 +89,7 @@ module.exports = class ServerApi {
|
||||
`room=${roomValue}` +
|
||||
`&roomPassword=${roomPasswordValue}` +
|
||||
`&name=${encodeURIComponent(nameValue)}` +
|
||||
`&avatar=${encodeURIComponent(avatarValue)}` +
|
||||
`&audio=${audioValue}` +
|
||||
`&video=${videoValue}` +
|
||||
`&screen=${screenValue}` +
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalksfu",
|
||||
"version": "1.8.12",
|
||||
"version": "1.8.13",
|
||||
"description": "WebRTC SFU browser-based video calls",
|
||||
"main": "Server.js",
|
||||
"scripts": {
|
||||
@@ -81,7 +81,7 @@
|
||||
"mediasoup": "3.15.7",
|
||||
"mediasoup-client": "3.9.5",
|
||||
"nodemailer": "^6.10.0",
|
||||
"openai": "^4.91.1",
|
||||
"openai": "^4.92.1",
|
||||
"qs": "6.14.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"socket.io": "4.8.1",
|
||||
@@ -99,7 +99,7 @@
|
||||
"proxyquire": "^2.1.3",
|
||||
"should": "^13.2.3",
|
||||
"sinon": "^20.0.0",
|
||||
"webpack": "^5.98.0",
|
||||
"webpack": "^5.99.1",
|
||||
"webpack-cli": "^6.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
ثنائية
public/images/admin.png
Normal file
ثنائية
public/images/admin.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 36 KiB |
@@ -64,7 +64,7 @@ let BRAND = {
|
||||
},
|
||||
about: {
|
||||
imageUrl: '../images/mirotalk-logo.gif',
|
||||
title: '<strong>WebRTC SFU v1.8.12</strong>',
|
||||
title: '<strong>WebRTC SFU v1.8.13</strong>',
|
||||
html: `
|
||||
<button
|
||||
id="support-button"
|
||||
|
||||
@@ -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.8.12
|
||||
* @version 1.8.13
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -218,6 +218,7 @@ let room_id = getRoomId();
|
||||
let room_password = getRoomPassword();
|
||||
let room_duration = getRoomDuration();
|
||||
let peer_name = getPeerName();
|
||||
let peer_avatar = getPeerAvatar();
|
||||
let peer_uuid = getPeerUUID();
|
||||
let peer_token = getPeerToken();
|
||||
let isScreenAllowed = getScreen();
|
||||
@@ -850,6 +851,16 @@ function getPeerName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
function getPeerAvatar() {
|
||||
const avatar = getQueryParam('avatar');
|
||||
const avatarDisabled = avatar === '0' || avatar === 'false';
|
||||
console.log('Direct join', { avatar: avatar });
|
||||
if (avatarDisabled || !isImageURL(avatar)) {
|
||||
return false;
|
||||
}
|
||||
return avatar;
|
||||
}
|
||||
|
||||
function getPeerUUID() {
|
||||
if (lS.getItemLocalStorage('peer_uuid')) {
|
||||
return lS.getItemLocalStorage('peer_uuid');
|
||||
@@ -966,6 +977,7 @@ function getPeerInfo() {
|
||||
peer_uuid: peer_uuid,
|
||||
peer_id: socket.id,
|
||||
peer_name: peer_name,
|
||||
peer_avatar: peer_avatar,
|
||||
peer_token: peer_token,
|
||||
peer_presenter: isPresenter,
|
||||
peer_audio: isAudioAllowed,
|
||||
@@ -1473,12 +1485,15 @@ function joinRoom(peer_name, room_id) {
|
||||
function roomIsReady() {
|
||||
makeRoomPopupQR();
|
||||
|
||||
if (rc.isValidEmail(peer_name)) {
|
||||
if (peer_avatar && isImageURL(peer_avatar)) {
|
||||
myProfileAvatar.setAttribute('src', peer_avatar);
|
||||
} else if (rc.isValidEmail(peer_name)) {
|
||||
myProfileAvatar.style.borderRadius = `50px`;
|
||||
myProfileAvatar.setAttribute('src', rc.genGravatar(peer_name));
|
||||
} else {
|
||||
myProfileAvatar.setAttribute('src', rc.genAvatarSvg(peer_name, 64));
|
||||
}
|
||||
|
||||
show(toggleExtraButton); //*
|
||||
BUTTONS.main.exitButton && show(exitButton);
|
||||
BUTTONS.main.shareButton && show(shareButton);
|
||||
@@ -3721,8 +3736,15 @@ async function sound(name, force = false) {
|
||||
}
|
||||
}
|
||||
|
||||
function isImageURL(url) {
|
||||
return url.match(/\.(jpeg|jpg|gif|png|tiff|bmp)$/) != null;
|
||||
async function isImageURL(url) {
|
||||
if (!url) return false;
|
||||
try {
|
||||
const response = await fetch(url, { method: 'HEAD' });
|
||||
const contentType = response.headers.get('content-type');
|
||||
return contentType && contentType.startsWith('image/');
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isMobile(userAgent) {
|
||||
@@ -4430,7 +4452,7 @@ function getParticipantsList(peers) {
|
||||
data-to-id="ChatGPT"
|
||||
data-to-name="ChatGPT"
|
||||
class="clearfix${chatgpt_active}"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, 'ChatGPT', event)"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, 'ChatGPT', '', event)"
|
||||
>
|
||||
<img
|
||||
src="${image.chatgpt}"
|
||||
@@ -4451,7 +4473,7 @@ function getParticipantsList(peers) {
|
||||
data-to-id="all"
|
||||
data-to-name="all"
|
||||
class="clearfix${public_chat_active}"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, 'all', event)"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, 'all', '', event)"
|
||||
>
|
||||
<img
|
||||
src="${image.all}"
|
||||
@@ -4512,7 +4534,9 @@ function getParticipantsList(peers) {
|
||||
// PEERS IN THE CURRENT ROOM
|
||||
for (const peer of Array.from(peers.keys())) {
|
||||
const peer_info = peers.get(peer).peer_info;
|
||||
console.log('PEER-INFO------->', peer_info);
|
||||
const peer_name = peer_info.peer_name;
|
||||
const peer_avatar = peer_info.peer_avatar;
|
||||
const peer_name_limited = peer_name.length > 15 ? peer_name.substring(0, 10) + '*****' : peer_name;
|
||||
//const peer_presenter = peer_info.peer_presenter ? _PEER.presenter : _PEER.guest;
|
||||
const peer_audio = peer_info.peer_audio ? _PEER.audioOn : _PEER.audioOff;
|
||||
@@ -4524,7 +4548,7 @@ function getParticipantsList(peers) {
|
||||
const peer_geoLocation = _PEER.geoLocation;
|
||||
const peer_sendFile = _PEER.sendFile;
|
||||
const peer_id = peer_info.peer_id;
|
||||
const avatarImg = getParticipantAvatar(peer_name);
|
||||
const avatarImg = getParticipantAvatar(peer_name, peer_avatar);
|
||||
|
||||
const peer_chat_active = rc.chatPeerId === peer_id ? ' active' : '';
|
||||
|
||||
@@ -4538,7 +4562,7 @@ function getParticipantsList(peers) {
|
||||
data-to-id="${peer_id}"
|
||||
data-to-name="${peer_name}"
|
||||
class="clearfix${peer_chat_active}"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, '${peer_name}', event)"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, '${peer_name}', '${peer_avatar}', event)"
|
||||
>
|
||||
<img
|
||||
src="${avatarImg}"
|
||||
@@ -4614,7 +4638,7 @@ function getParticipantsList(peers) {
|
||||
data-to-id="${peer_id}"
|
||||
data-to-name="${peer_name}"
|
||||
class="clearfix${peer_chat_active}"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, '${peer_name}', event)"
|
||||
onclick="rc.showPeerAboutAndMessages(this.id, '${peer_name}', '${peer_avatar}', event)"
|
||||
>
|
||||
<img
|
||||
src="${avatarImg}"
|
||||
@@ -4706,7 +4730,10 @@ function refreshParticipantsCount(count, adapt = true) {
|
||||
if (adapt) adaptAspectRatio(count);
|
||||
}
|
||||
|
||||
function getParticipantAvatar(peerName) {
|
||||
function getParticipantAvatar(peerName, peerAvatar = false) {
|
||||
if (peerAvatar && rc.isImageURL(peerAvatar)) {
|
||||
return peerAvatar;
|
||||
}
|
||||
if (rc.isValidEmail(peerName)) {
|
||||
return rc.genGravatar(peerName);
|
||||
}
|
||||
@@ -5324,7 +5351,7 @@ function showAbout() {
|
||||
position: 'center',
|
||||
imageUrl: BRAND.about?.imageUrl && BRAND.about.imageUrl.trim() !== '' ? BRAND.about.imageUrl : image.about,
|
||||
customClass: { image: 'img-about' },
|
||||
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.8.12',
|
||||
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.8.13',
|
||||
html: `
|
||||
<br />
|
||||
<div id="about">
|
||||
|
||||
@@ -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.8.12
|
||||
* @version 1.8.13
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -245,6 +245,7 @@ class RoomClient {
|
||||
this.room_id = room_id;
|
||||
this.peer_id = socket.id;
|
||||
this.peer_name = peer_name;
|
||||
this.peer_avatar = peer_info.peer_avatar;
|
||||
this.peer_uuid = peer_uuid;
|
||||
this.peer_info = peer_info;
|
||||
|
||||
@@ -279,6 +280,7 @@ class RoomClient {
|
||||
this.chatMessageSpamCountToBan = 10;
|
||||
this.chatPeerId = 'all';
|
||||
this.chatPeerName = 'all';
|
||||
this.chatPeerAvatar = '';
|
||||
|
||||
// HeyGen Video AI
|
||||
this.videoAIContainer = null;
|
||||
@@ -639,7 +641,7 @@ class RoomClient {
|
||||
let peer_info = this.peers.get(peer).peer_info;
|
||||
// console.log('07.1 ----> Remote Peer info', peer_info);
|
||||
|
||||
const { peer_id, peer_name, peer_presenter, peer_video, peer_recording } = peer_info;
|
||||
const { peer_id, peer_name, peer_avatar, peer_presenter, peer_video, peer_recording } = peer_info;
|
||||
|
||||
const canSetVideoOff = !isBroadcastingEnabled || (isBroadcastingEnabled && peer_presenter);
|
||||
|
||||
@@ -652,6 +654,7 @@ class RoomClient {
|
||||
this.handleRecordingAction({
|
||||
peer_id: peer_id,
|
||||
peer_name: peer_name,
|
||||
peer_avatar: peer_avatar,
|
||||
action: enums.recording.started,
|
||||
});
|
||||
}
|
||||
@@ -3080,7 +3083,7 @@ class RoomClient {
|
||||
//console.log('setVideoOff', peer_info);
|
||||
let d, vb, i, h, au, sf, sm, sv, gl, ban, ko, p, pm, pb, pv;
|
||||
|
||||
const { peer_id, peer_name, peer_audio, peer_presenter } = peer_info;
|
||||
const { peer_id, peer_name, peer_avatar, peer_audio, peer_presenter } = peer_info;
|
||||
|
||||
this.removeVideoOff(peer_id);
|
||||
|
||||
@@ -3169,7 +3172,7 @@ class RoomClient {
|
||||
this.handleDD(d.id, peer_id, !remotePeer);
|
||||
this.popupPeerInfo(p.id, peer_info);
|
||||
this.checkPeerInfoStatus(peer_info);
|
||||
this.setVideoAvatarImgName(i.id, peer_name);
|
||||
this.setVideoAvatarImgName(i.id, peer_name, peer_avatar);
|
||||
this.getId(i.id).style.display = 'block';
|
||||
|
||||
if (isParticipantsListOpen) getRoomParticipants();
|
||||
@@ -3391,9 +3394,11 @@ class RoomClient {
|
||||
}
|
||||
}
|
||||
|
||||
setVideoAvatarImgName(elemId, peer_name) {
|
||||
setVideoAvatarImgName(elemId, peer_name, peer_avatar = false) {
|
||||
let elem = this.getId(elemId);
|
||||
if (cfg.useAvatarSvg) {
|
||||
if (peer_avatar && rc.isImageURL(peer_avatar)) {
|
||||
elem.setAttribute('src', peer_avatar);
|
||||
} else if (cfg.useAvatarSvg) {
|
||||
rc.isValidEmail(peer_name)
|
||||
? elem.setAttribute('src', this.genGravatar(peer_name))
|
||||
: elem.setAttribute('src', this.genAvatarSvg(peer_name, 250));
|
||||
@@ -4528,7 +4533,7 @@ class RoomClient {
|
||||
}
|
||||
this.chatCenter();
|
||||
this.sound('open');
|
||||
this.showPeerAboutAndMessages(this.chatPeerId, this.chatPeerName);
|
||||
this.showPeerAboutAndMessages(this.chatPeerId, this.chatPeerName, this.chatPeerAvatar);
|
||||
}
|
||||
isParticipantsListOpen = !isParticipantsListOpen;
|
||||
this.isChatOpen = !this.isChatOpen;
|
||||
@@ -4737,6 +4742,7 @@ class RoomClient {
|
||||
const data = {
|
||||
room_id: this.room_id,
|
||||
peer_name: this.peer_name,
|
||||
peer_avatar: this.peer_avatar,
|
||||
peer_id: this.peer_id,
|
||||
to_peer_id: 'ChatGPT',
|
||||
to_peer_name: 'ChatGPT',
|
||||
@@ -4746,7 +4752,7 @@ class RoomClient {
|
||||
if (isChatGPTOn) {
|
||||
console.log('Send message:', data);
|
||||
this.socket.emit('message', data);
|
||||
this.setMsgAvatar('left', this.peer_name);
|
||||
this.setMsgAvatar('left', this.peer_name, this.peer_avatar);
|
||||
this.appendMessage(
|
||||
'left',
|
||||
this.leftMsgAvatar,
|
||||
@@ -4792,7 +4798,7 @@ class RoomClient {
|
||||
data.to_peer_name = li.getAttribute('data-to-name');
|
||||
console.log('Send message:', data);
|
||||
this.socket.emit('message', data);
|
||||
this.setMsgAvatar('left', this.peer_name);
|
||||
this.setMsgAvatar('left', this.peer_name, this.peer_avatar);
|
||||
this.appendMessage(
|
||||
'left',
|
||||
this.leftMsgAvatar,
|
||||
@@ -4835,6 +4841,7 @@ class RoomClient {
|
||||
const toPeerName = filterXSS(to_peer_name);
|
||||
let data = {
|
||||
peer_name: this.peer_name,
|
||||
peer_avatar: this.peer_avatar,
|
||||
peer_id: this.peer_id,
|
||||
to_peer_id: to_peer_id,
|
||||
to_peer_name: toPeerName,
|
||||
@@ -4842,7 +4849,7 @@ class RoomClient {
|
||||
};
|
||||
console.log('Send message:', data);
|
||||
this.socket.emit('message', data);
|
||||
this.setMsgAvatar('left', this.peer_name);
|
||||
this.setMsgAvatar('left', this.peer_name, this.peer_avatar);
|
||||
this.appendMessage(
|
||||
'left',
|
||||
this.leftMsgAvatar,
|
||||
@@ -4859,7 +4866,7 @@ class RoomClient {
|
||||
|
||||
async showMessage(data) {
|
||||
if (!this.isChatOpen && this.showChatOnMessage) await this.toggleChat();
|
||||
this.setMsgAvatar('right', data.peer_name);
|
||||
this.setMsgAvatar('right', data.peer_name, data.peer_avatar);
|
||||
this.appendMessage(
|
||||
'right',
|
||||
this.rightMsgAvatar,
|
||||
@@ -4895,8 +4902,13 @@ class RoomClient {
|
||||
}
|
||||
}
|
||||
|
||||
setMsgAvatar(avatar, peerName) {
|
||||
let avatarImg = rc.isValidEmail(peerName) ? this.genGravatar(peerName) : this.genAvatarSvg(peerName, 32);
|
||||
setMsgAvatar(avatar, peerName, peerAvatar = false) {
|
||||
const avatarImg =
|
||||
peerAvatar && this.isImageURL(peerAvatar)
|
||||
? peerAvatar
|
||||
: this.isValidEmail(peerName)
|
||||
? this.genGravatar(peerName)
|
||||
: this.genAvatarSvg(peerName, 32);
|
||||
avatar === 'left' ? (this.leftMsgAvatar = avatarImg) : (this.rightMsgAvatar = avatarImg);
|
||||
}
|
||||
|
||||
@@ -5137,8 +5149,15 @@ class RoomClient {
|
||||
}
|
||||
}
|
||||
|
||||
isImageURL(input) {
|
||||
return input.match(/\.(jpeg|jpg|gif|png|tiff|bmp)$/) != null;
|
||||
async isImageURL(input) {
|
||||
if (!input) return false;
|
||||
try {
|
||||
const response = await fetch(input, { method: 'HEAD' });
|
||||
const contentType = response.headers.get('content-type');
|
||||
return contentType && contentType.startsWith('image/');
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getImage(input) {
|
||||
@@ -6325,12 +6344,13 @@ class RoomClient {
|
||||
handleRecordingAction(data) {
|
||||
console.log('Handle recording action', data);
|
||||
|
||||
const { peer_name, peer_id, action } = data;
|
||||
const { peer_name, peer_avatar, peer_id, action } = data;
|
||||
|
||||
const recAction = {
|
||||
side: 'left',
|
||||
img: this.leftMsgAvatar,
|
||||
peer_name: peer_name,
|
||||
peer_avatar: peer_avatar,
|
||||
peer_id: peer_id,
|
||||
peer_msg: `🔴 ${action}`,
|
||||
to_peer_id: 'all',
|
||||
@@ -6514,11 +6534,12 @@ class RoomClient {
|
||||
peer_id: peer_id,
|
||||
broadcast: broadcast,
|
||||
peer_name: this.peer_name,
|
||||
peer_avatar: this.peer_avatar,
|
||||
fileName: this.fileToSend.name,
|
||||
fileSize: this.fileToSend.size,
|
||||
fileType: this.fileToSend.type,
|
||||
};
|
||||
this.setMsgAvatar('left', this.peer_name);
|
||||
this.setMsgAvatar('left', this.peer_name, this.peer_avatar);
|
||||
this.appendMessage(
|
||||
'left',
|
||||
this.leftMsgAvatar,
|
||||
@@ -6560,7 +6581,7 @@ class RoomClient {
|
||||
html.newline +
|
||||
' File size: ' +
|
||||
this.bytesToSize(this.incomingFileInfo.fileSize);
|
||||
this.setMsgAvatar('right', this.incomingFileInfo.peer_name);
|
||||
this.setMsgAvatar('right', this.incomingFileInfo.peer_name, this.incomingFileInfo.peer_avatar);
|
||||
this.appendMessage(
|
||||
'right',
|
||||
this.rightMsgAvatar,
|
||||
@@ -7308,9 +7329,15 @@ class RoomClient {
|
||||
let lobbyTr = '';
|
||||
let peer_id = data.peer_id;
|
||||
let peer_name = data.peer_name;
|
||||
let avatarImg = rc.isValidEmail(peer_name)
|
||||
let peer_avatar = data.peer_avatar;
|
||||
|
||||
const avatarImg =
|
||||
peer_avatar && this.isImageURL(peer_avatar)
|
||||
? peer_avatar
|
||||
: this.isValidEmail(peer_name)
|
||||
? this.genGravatar(peer_name)
|
||||
: this.genAvatarSvg(peer_name, 32);
|
||||
|
||||
let lobbyTb = this.getId('lobbyTb');
|
||||
let lobbyAccept = _PEER.acceptPeer;
|
||||
let lobbyReject = _PEER.ejectPeer;
|
||||
@@ -8621,11 +8648,12 @@ class RoomClient {
|
||||
// SHOW PEER ABOUT AND MESSAGES
|
||||
// ####################################################
|
||||
|
||||
showPeerAboutAndMessages(peer_id, peer_name, event = null) {
|
||||
showPeerAboutAndMessages(peer_id, peer_name, peer_avatar = false, event = null) {
|
||||
this.hidePeerMessages();
|
||||
|
||||
this.chatPeerId = peer_id;
|
||||
this.chatPeerName = peer_name;
|
||||
this.chatPeerAvatar = peer_avatar;
|
||||
|
||||
const chatAbout = this.getId('chatAbout');
|
||||
const participant = this.getId(peer_id);
|
||||
@@ -8633,7 +8661,7 @@ class RoomClient {
|
||||
const chatPrivateMessages = this.getId('chatPrivateMessages');
|
||||
const messagePrivateListItems = chatPrivateMessages.getElementsByTagName('li');
|
||||
const participantsListItems = participantsList.getElementsByTagName('li');
|
||||
const avatarImg = getParticipantAvatar(peer_name);
|
||||
const avatarImg = getParticipantAvatar(peer_name, peer_avatar);
|
||||
|
||||
const generateChatAboutHTML = (imgSrc, title, status = 'online', participants = '') => {
|
||||
const isSensitiveChat = !['all', 'ChatGPT'].includes(peer_id) && title.length > 15;
|
||||
|
||||
@@ -120,6 +120,7 @@ class Transcription {
|
||||
type: 'transcript',
|
||||
room_id: room_id,
|
||||
peer_name: peer_name,
|
||||
peer_avatar: peer_avatar,
|
||||
text_data: transcript,
|
||||
time_stamp: new Date(),
|
||||
broadcast: true,
|
||||
@@ -185,10 +186,17 @@ class Transcription {
|
||||
|
||||
transcriptionData.text_data = filterXSS(transcriptionData.text_data);
|
||||
transcriptionData.peer_name = filterXSS(transcriptionData.peer_name);
|
||||
transcriptionData.peer_avatar = filterXSS(transcriptionData.peer_avatar);
|
||||
|
||||
const { peer_name, text_data } = transcriptionData;
|
||||
const { peer_name, peer_avatar, text_data } = transcriptionData;
|
||||
const time_stamp = rc.getTimeNow();
|
||||
const avatar_image = rc.isValidEmail(peer_name) ? rc.genGravatar(peer_name) : rc.genAvatarSvg(peer_name, 32);
|
||||
|
||||
const avatar_image =
|
||||
peer_avatar && rc.isImageURL(peer_avatar)
|
||||
? peer_avatar
|
||||
: rc.isValidEmail(peer_name)
|
||||
? rc.genGravatar(peer_name)
|
||||
: rc.genAvatarSvg(peer_name, 32);
|
||||
|
||||
if (this.isHidden) {
|
||||
if (this.showOnMessage) {
|
||||
@@ -468,6 +476,7 @@ class Transcription {
|
||||
data: {
|
||||
peer_id: rc.peer_id,
|
||||
peer_name: rc.peer_name,
|
||||
peer_avatar: rc.peer_avatar,
|
||||
transcriptionLanguageIndex: transcriptionLanguage.selectedIndex,
|
||||
transcriptionDialectIndex: transcriptionDialect.selectedIndex,
|
||||
},
|
||||
|
||||
@@ -172,6 +172,7 @@ describe('test-ServerAPI', () => {
|
||||
room: 'room1',
|
||||
roomPassword: 'password123',
|
||||
name: 'John Doe',
|
||||
avatar: 'test.jpg',
|
||||
audio: true,
|
||||
video: false,
|
||||
screen: false,
|
||||
@@ -185,7 +186,7 @@ describe('test-ServerAPI', () => {
|
||||
|
||||
const result = serverApi.getJoinURL(data);
|
||||
result.should.equal(
|
||||
'https://example.com/join?room=room1&roomPassword=password123&name=John%20Doe&audio=true&video=false&screen=false&hide=false¬ify=false&duration=00:30:00&token=testToken',
|
||||
'https://example.com/join?room=room1&roomPassword=password123&name=John%20Doe&avatar=test.jpg&audio=true&video=false&screen=false&hide=false¬ify=false&duration=00:30:00&token=testToken',
|
||||
);
|
||||
|
||||
tokenStub.restore();
|
||||
@@ -203,7 +204,7 @@ describe('test-ServerAPI', () => {
|
||||
|
||||
const result = serverApi.getJoinURL({});
|
||||
result.should.equal(
|
||||
'https://example.com/join?room=room1&roomPassword=false&name=User-123456&audio=false&video=false&screen=false&hide=false¬ify=false&duration=unlimited',
|
||||
'https://example.com/join?room=room1&roomPassword=false&name=User-123456&avatar=false&audio=false&video=false&screen=false&hide=false¬ify=false&duration=unlimited',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم