[mirotalksfu] - Add Support for Custom Avatar via Options Object

هذا الالتزام موجود في:
Miroslav Pejic
2025-04-08 03:30:10 +02:00
الأصل ff493e278c
التزام f69b201ecc
16 ملفات معدلة مع 233 إضافات و77 حذوفات

عرض الملف

@@ -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

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 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&notify=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&notify=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&notify=false&duration=unlimited',
'https://example.com/join?room=room1&roomPassword=false&name=User-123456&avatar=false&audio=false&video=false&screen=false&hide=false&notify=false&duration=unlimited',
);
});
});