[call-me] - fix chat, improve popups, update dep

This commit is contained in:
Miroslav Pejic
2025-12-03 16:55:05 +01:00
parent 703d20ab8d
commit 114af0da2c
4 changed files with 94 additions and 66 deletions
+10 -1
View File
@@ -9,7 +9,16 @@
<body>
<iframe
id="callmeIframe"
allow="camera; microphone; display-capture; fullscreen; clipboard-read; clipboard-write; web-share; autoplay"
allow="
camera;
microphone;
display-capture;
fullscreen;
clipboard-read;
clipboard-write;
web-share;
autoplay;
"
src="https://cme.mirotalk.com"
style="height: 100vh; width: 100vw; border: 0px"
></iframe>
+64 -47
View File
@@ -1,12 +1,12 @@
{
"name": "call-me",
"version": "1.2.75",
"version": "1.2.76",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "call-me",
"version": "1.2.75",
"version": "1.2.76",
"license": "AGPLv3",
"dependencies": {
"@ngrok/ngrok": "1.6.0",
@@ -14,7 +14,7 @@
"colors": "^1.4.0",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"express": "^5.2.1",
"helmet": "^8.1.0",
"httpolyglot": "0.1.2",
"js-yaml": "4.1.1",
@@ -23,7 +23,7 @@
},
"devDependencies": {
"nodemon": "^3.1.11",
"prettier": "3.6.2"
"prettier": "3.7.4"
}
},
"node_modules/@ngrok/ngrok": {
@@ -359,29 +359,33 @@
}
},
"node_modules/body-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
"license": "MIT",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"debug": "^4.4.0",
"debug": "^4.4.3",
"http-errors": "^2.0.0",
"iconv-lite": "^0.6.3",
"iconv-lite": "^0.7.0",
"on-finished": "^2.4.1",
"qs": "^6.14.0",
"raw-body": "^3.0.0",
"type-is": "^2.0.0"
"raw-body": "^3.0.1",
"type-is": "^2.0.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/body-parser/node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -741,18 +745,19 @@
}
},
"node_modules/express": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT",
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.0",
"body-parser": "^2.2.1",
"content-disposition": "^1.0.0",
"content-type": "^1.0.5",
"cookie": "^0.7.1",
"cookie-signature": "^1.2.1",
"debug": "^4.4.0",
"depd": "^2.0.0",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
@@ -1095,19 +1100,23 @@
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
"depd": "~2.0.0",
"inherits": "~2.0.4",
"setprototypeof": "~1.2.0",
"statuses": "~2.0.2",
"toidentifier": "~1.0.1"
},
"engines": {
"node": ">= 0.8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/httpolyglot": {
@@ -1119,15 +1128,19 @@
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/ignore-by-default": {
@@ -1396,9 +1409,9 @@
}
},
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
"bin": {
@@ -1460,18 +1473,18 @@
}
},
"node_modules/raw-body": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.6.3",
"unpipe": "1.0.0"
"bytes": "~3.1.2",
"http-errors": "~2.0.1",
"iconv-lite": "~0.7.0",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
"node": ">= 0.10"
}
},
"node_modules/readdirp": {
@@ -1758,9 +1771,9 @@
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -1851,15 +1864,19 @@
}
},
"node_modules/type-is/node_modules/mime-types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
},
"engines": {
"node": ">= 0.6"
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/undefsafe": {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "call-me",
"version": "1.2.75",
"version": "1.2.76",
"description": "Your Go-To for Instant Video Calls",
"author": "Miroslav Pejic - miroslav.pejic.85@gmail.com",
"license": "AGPLv3",
@@ -24,7 +24,7 @@
"colors": "^1.4.0",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"express": "^5.2.1",
"helmet": "^8.1.0",
"httpolyglot": "0.1.2",
"js-yaml": "4.1.1",
@@ -33,6 +33,6 @@
},
"devDependencies": {
"nodemon": "^3.1.11",
"prettier": "3.6.2"
"prettier": "3.7.4"
}
}
+17 -15
View File
@@ -767,7 +767,7 @@ async function startScreenSharing() {
stopScreenSharing();
};
toast('Screen sharing started', 'success', 'top-end', 2000);
toast('Screen sharing started', 'success', 'top', 2000);
console.log('Screen sharing started');
} catch (error) {
if (error.name === 'NotAllowedError') {
@@ -848,7 +848,7 @@ async function stopScreenSharing() {
// Ensure UI button state matches actual video state
checkVideoAudioStatus();
toast('Screen sharing stopped', 'success', 'top-end', 2000);
toast('Screen sharing stopped', 'success', 'top', 2000);
console.log('Screen sharing stopped');
} catch (error) {
handleError('Failed to stop screen sharing', error.message);
@@ -1805,10 +1805,12 @@ if (chatForm && chatInput) {
chatForm.addEventListener('submit', (e) => {
e.preventDefault();
const text = chatInput.value.trim();
if (text.length > 0) {
if (text.length > 0 && allConnectedUsers.length > 0) {
socket.emit('message', { type: 'chat', text });
addChatMessage({ from: userName || 'Me', text, timestamp: Date.now() }, true);
chatInput.value = '';
} else {
toast('Cannot send empty message or no user connected', 'warning', 'top', 2000);
}
});
}
@@ -1845,7 +1847,7 @@ function addChatMessage(msg, isSelf = false) {
// Show toast notification for new messages only if sidebar is not opened
if (!userSidebar.classList.contains('active')) {
toast(`New message from ${msg.from}`, 'info', 'top-end', 2000);
toast(`New message from ${msg.from}`, 'info', 'top', 2000);
}
}
}
@@ -1971,7 +1973,7 @@ function handleSaveChatClick() {
const chatText = generateChatExportText();
if (!chatText) {
toast('No chat messages to save', 'info', 'top-end', 2000);
toast('No chat messages to save', 'info', 'top', 2000);
return;
}
@@ -1980,13 +1982,13 @@ function handleSaveChatClick() {
downloadTextAsFile(chatText, fileName);
toast(`Chat messages saved as ${fileName}`, 'success', 'top-end', 3000);
toast(`Chat messages saved as ${fileName}`, 'success', 'top', 3000);
}
// Handle clear chat button click
function handleClearChatClick() {
if (!thereAreChatMessages()) {
toast('No chat messages to clear', 'info', 'top-end', 2000);
toast('No chat messages to clear', 'info', 'top', 2000);
return;
}
@@ -2010,7 +2012,7 @@ function handleClearChatClick() {
updateChatNotification();
// Show success message
toast('Chat messages cleared successfully', 'success', 'top-end', 2000);
toast('Chat messages cleared successfully', 'success', 'top', 2000);
}
});
}
@@ -2201,7 +2203,7 @@ async function refreshDevices(showToast = true) {
await enumerateDevices();
updateUIForAvailableDevices();
if (showToast) {
toast('Devices refreshed successfully', 'success', 'top-end', 2000);
toast('Devices refreshed successfully', 'success', 'top', 2000);
}
} catch (error) {
console.error('Error refreshing devices:', error);
@@ -2220,7 +2222,7 @@ async function handleVideoDeviceChange() {
selectedDevices.videoInput = newDeviceId;
await updateVideoStream();
updateUIForAvailableDevices();
toast('Camera changed successfully', 'success', 'top-end', 2000);
toast('Camera changed successfully', 'success', 'top', 2000);
}
}
@@ -2230,7 +2232,7 @@ async function handleAudioDeviceChange() {
selectedDevices.audioInput = newDeviceId;
await updateAudioStream();
updateUIForAvailableDevices();
toast('Microphone changed successfully', 'success', 'top-end', 2000);
toast('Microphone changed successfully', 'success', 'top', 2000);
}
}
@@ -2239,7 +2241,7 @@ async function handleAudioOutputDeviceChange() {
if (newDeviceId && newDeviceId !== selectedDevices.audioOutput) {
selectedDevices.audioOutput = newDeviceId;
await setAudioOutputDevice(newDeviceId);
toast('Speaker changed successfully', 'success', 'top-end', 2000);
toast('Speaker changed successfully', 'success', 'top', 2000);
}
}
@@ -2364,7 +2366,7 @@ async function setAudioOutputDevice(deviceId) {
selectedDevices.audioOutput = deviceId;
} else {
console.warn('Browser does not support audio output device selection');
toast('Audio output selection not supported in this browser', 'warning', 'top-end', 3000);
toast('Audio output selection not supported in this browser', 'warning', 'top', 3000);
}
} catch (error) {
console.error('Error setting audio output device:', error);
@@ -2384,7 +2386,7 @@ async function testDevices() {
const hasMic = availableDevices.audioInputs.length > 0;
if (!hasCamera && !hasMic) {
toast('No devices available to test', 'warning', 'top-end', 2000);
toast('No devices available to test', 'warning', 'top', 2000);
return;
}
@@ -2414,7 +2416,7 @@ async function testDevices() {
// Test for 2 seconds then stop
setTimeout(() => {
testStream.getTracks().forEach((track) => track.stop());
toast('Device test completed successfully', 'success', 'top-end', 2000);
toast('Device test completed successfully', 'success', 'top', 2000);
}, 2000);
} catch (error) {
console.error('Error testing devices:', error);