[call-me] - improve UI & logs
This commit is contained in:
+1
-4
@@ -9,6 +9,7 @@ PORT=8000
|
||||
|
||||
# Logging
|
||||
|
||||
LOGS_DEBUG=true # true or false
|
||||
LOGS_JSON=false # Enable JSON formatted logs (true/false)
|
||||
LOGS_JSON_PRETTY=false # Enable pretty JSON formatted logs (true/false)
|
||||
|
||||
@@ -50,10 +51,6 @@ NGROK_AUTH_TOKEN=YourNgrokAuthToken
|
||||
|
||||
TZ=UTC
|
||||
|
||||
# Logs
|
||||
|
||||
DEBUG=true # true or false
|
||||
|
||||
# API
|
||||
|
||||
API_KEY_SECRET=call_me_api_key_secret # change me
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ const util = require('util');
|
||||
const colors = require('colors');
|
||||
colors.enable(); // colors.disable();
|
||||
|
||||
const LOGS_DEBUG = process.env.LOGS_DEBUG !== undefined ? process.env.LOGS_DEBUG === 'true' : true;
|
||||
const LOGS_JSON = process.env.LOGS_JSON ? process.env.LOGS_JSON === 'true' : false;
|
||||
const LOGS_JSON_PRETTY = process.env.LOGS_JSON_PRETTY ? process.env.LOGS_JSON_PRETTY === 'true' : false;
|
||||
|
||||
@@ -15,7 +16,7 @@ const options = {
|
||||
module.exports = class Logs {
|
||||
constructor(appName = 'call-me') {
|
||||
this.appName = colors.yellow(appName);
|
||||
this.debugOn = process.env.DEBUG !== undefined ? process.env.DEBUG === 'true' : true;
|
||||
this.debugOn = LOGS_DEBUG;
|
||||
this.timeStart = Date.now();
|
||||
this.timeEnd = null;
|
||||
this.timeElapsedMs = null;
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "call-me",
|
||||
"version": "1.2.89",
|
||||
"version": "1.2.90",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "call-me",
|
||||
"version": "1.2.89",
|
||||
"version": "1.2.90",
|
||||
"license": "AGPLv3",
|
||||
"dependencies": {
|
||||
"@ngrok/ngrok": "1.7.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "call-me",
|
||||
"version": "1.2.89",
|
||||
"version": "1.2.90",
|
||||
"description": "Your Go-To for Instant Video Calls",
|
||||
"author": "Miroslav Pejic - miroslav.pejic.85@gmail.com",
|
||||
"license": "AGPLv3",
|
||||
|
||||
+51
-17
@@ -182,6 +182,8 @@ async function checkHostPassword(maxRetries = 3, attempts = 0) {
|
||||
if (config.isPasswordRequired) {
|
||||
// Show prompt for the password
|
||||
const { value: password } = await Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
title: 'Host Protected',
|
||||
text: 'Please enter the host password:',
|
||||
input: 'password',
|
||||
@@ -216,6 +218,8 @@ async function checkHostPassword(maxRetries = 3, attempts = 0) {
|
||||
|
||||
if (validationResult.success) {
|
||||
await Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'top',
|
||||
icon: 'success',
|
||||
title: 'Access Granted',
|
||||
@@ -228,6 +232,8 @@ async function checkHostPassword(maxRetries = 3, attempts = 0) {
|
||||
attempts++;
|
||||
if (attempts < maxRetries) {
|
||||
await Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'top',
|
||||
icon: 'error',
|
||||
title: 'Invalid Password',
|
||||
@@ -237,6 +243,8 @@ async function checkHostPassword(maxRetries = 3, attempts = 0) {
|
||||
await checkHostPassword(maxRetries, attempts);
|
||||
} else {
|
||||
await Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'top',
|
||||
icon: 'warning',
|
||||
title: 'Too Many Attempts',
|
||||
@@ -251,6 +259,8 @@ async function checkHostPassword(maxRetries = 3, attempts = 0) {
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'top',
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
@@ -460,12 +470,12 @@ async function handleEnumerateDevices() {
|
||||
const videoInputs = devices.filter((device) => device.kind === 'videoinput');
|
||||
if (videoInputs.length > 1 && userInfo.device.isMobile) {
|
||||
swapCameraBtn.addEventListener('click', swapCamera);
|
||||
elemDisplay(swapCameraBtn, true, 'inline');
|
||||
elemDisplay(swapCameraBtn, true, 'inline-flex');
|
||||
}
|
||||
|
||||
// Check if screen sharing is supported
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
|
||||
elemDisplay(screenShareBtn, true, 'inline');
|
||||
elemDisplay(screenShareBtn, true, 'inline-flex');
|
||||
} else {
|
||||
elemDisplay(screenShareBtn, false);
|
||||
console.log('Screen sharing not supported in this browser');
|
||||
@@ -1217,6 +1227,8 @@ function handleMediaStreamError(error) {
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'top',
|
||||
icon: 'warning',
|
||||
html: errorMessage,
|
||||
@@ -1343,6 +1355,8 @@ function offerAccept(data) {
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'top',
|
||||
imageUrl: 'assets/ring.png',
|
||||
imageWidth: 284,
|
||||
@@ -1617,17 +1631,15 @@ function handleLeave(disconnect = true) {
|
||||
|
||||
// Display toast messages
|
||||
function toast(message, icon = 'info', position = 'top', timer = 3000) {
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
position: position,
|
||||
icon: icon,
|
||||
showConfirmButton: false,
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position,
|
||||
icon,
|
||||
html: message,
|
||||
timer,
|
||||
timerProgressBar: true,
|
||||
timer: timer,
|
||||
});
|
||||
Toast.fire({
|
||||
icon: icon,
|
||||
title: message,
|
||||
showConfirmButton: false,
|
||||
showClass: { popup: 'animate__animated animate__fadeInDown' },
|
||||
hideClass: { popup: 'animate__animated animate__fadeOutUp' },
|
||||
});
|
||||
@@ -1638,6 +1650,8 @@ function handleError(message, error = false, position = 'top', timer = 6000) {
|
||||
if (error) console.error(error);
|
||||
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position,
|
||||
icon: 'warning',
|
||||
html: message,
|
||||
@@ -1653,6 +1667,8 @@ function handleError(message, error = false, position = 'top', timer = 6000) {
|
||||
// Display Message to user
|
||||
function popupMsg(message, position = 'top', timer = 4000) {
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position,
|
||||
html: message,
|
||||
timerProgressBar: true,
|
||||
@@ -1767,8 +1783,21 @@ function setupDataChannel(channel) {
|
||||
console.log('Data channel closed');
|
||||
};
|
||||
|
||||
dataChannel.onerror = (error) => {
|
||||
console.error('Data channel error:', error);
|
||||
dataChannel.onerror = (event) => {
|
||||
// Some browsers emit an error event during/after close (e.g. "User-Initiated Abort, reason=Close called").
|
||||
// That's expected during hang-up/teardown and shouldn't be shown to the user.
|
||||
const rtcError = event?.error;
|
||||
const message = (rtcError && (rtcError.message || rtcError.reason)) || '';
|
||||
const isClosingOrClosed = dataChannel?.readyState && dataChannel.readyState !== 'open';
|
||||
const isBenignCloseError =
|
||||
rtcError?.name === 'OperationError' && /close called|user-initiated abort|abort/i.test(String(message));
|
||||
|
||||
if (isClosingOrClosed || isBenignCloseError) {
|
||||
console.debug('Ignoring data channel close-related error:', event);
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('Data channel error:', event);
|
||||
toast('Data channel error occurred', 'warning', 'top', 3000);
|
||||
};
|
||||
|
||||
@@ -1985,7 +2014,8 @@ function renderUserList() {
|
||||
|
||||
if (isInActiveCall) {
|
||||
// Show hang-up button only if in active call (user has answered)
|
||||
actionBtnEl.className = 'btn btn-custom btn-danger btn-s hangup-user-btn fas fa-phone-slash';
|
||||
actionBtnEl.className = 'btn btn-custom btn-danger btn-s hangup-user-btn';
|
||||
actionBtnEl.innerHTML = '<i class="fas fa-phone-slash"></i>';
|
||||
actionBtnEl.title = `Hang up call with ${user}`;
|
||||
actionBtnEl.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -1998,7 +2028,8 @@ function renderUserList() {
|
||||
});
|
||||
} else {
|
||||
// Show call button if not in active call
|
||||
actionBtnEl.className = 'btn btn-custom btn-warning btn-s call-user-btn fas fa-phone';
|
||||
actionBtnEl.className = 'btn btn-custom btn-warning btn-s call-user-btn';
|
||||
actionBtnEl.innerHTML = '<i class="fas fa-phone"></i>';
|
||||
actionBtnEl.title = `Call ${user}`;
|
||||
actionBtnEl.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -2013,7 +2044,8 @@ function renderUserList() {
|
||||
|
||||
// Send file button
|
||||
const sendFileBtn = document.createElement('button');
|
||||
sendFileBtn.className = 'btn btn-custom btn-secondary btn-s fas fa-paperclip';
|
||||
sendFileBtn.className = 'btn btn-custom btn-secondary btn-s';
|
||||
sendFileBtn.innerHTML = '<i class="fas fa-paperclip"></i>';
|
||||
sendFileBtn.style.marginRight = '10px';
|
||||
sendFileBtn.style.cursor = 'pointer';
|
||||
sendFileBtn.setAttribute('data-toggle', 'tooltip');
|
||||
@@ -2538,6 +2570,8 @@ function handleClearChatClick() {
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
position: 'center',
|
||||
icon: 'question',
|
||||
title: 'Clear Chat Messages',
|
||||
|
||||
@@ -249,6 +249,8 @@ function updateCustomTranslations() {
|
||||
function showTranslatedAlert(titleKey, textKey, icon = 'info') {
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
heightAuto: false,
|
||||
scrollbarPadding: false,
|
||||
title: t(titleKey),
|
||||
text: t(textKey),
|
||||
icon: icon,
|
||||
|
||||
+104
-110
@@ -61,29 +61,25 @@
|
||||
</div>
|
||||
|
||||
<!-- Sign-in Page -->
|
||||
<div id="signInPage" class="container text-center center">
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header"><h1 id="appName" data-i18n="appName">Call-me</h1></div>
|
||||
<div class="card-body">
|
||||
<!-- Sign-in Form -->
|
||||
<div class="mb-3">
|
||||
<!-- Input field for entering the username -->
|
||||
<input
|
||||
id="usernameIn"
|
||||
type="text"
|
||||
placeholder="Enter username"
|
||||
data-i18n-placeholder="signIn.username"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- Sign-in button -->
|
||||
<button id="signInBtn" class="btn btn-primary" data-i18n="signIn.button">
|
||||
Sign In
|
||||
</button>
|
||||
<div id="signInPage" class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header"><h1 id="appName" data-i18n="appName">Call-me</h1></div>
|
||||
<div class="card-body">
|
||||
<!-- Sign-in Form -->
|
||||
<div class="mb-3">
|
||||
<!-- Input field for entering the username -->
|
||||
<input
|
||||
id="usernameIn"
|
||||
type="text"
|
||||
placeholder="Enter username"
|
||||
data-i18n-placeholder="signIn.username"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- Sign-in button -->
|
||||
<button id="signInBtn" class="btn btn-primary" data-i18n="signIn.button">Sign In</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,7 +87,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Room Page -->
|
||||
<div id="roomPage" class="container text-center center">
|
||||
<div id="roomPage" class="container">
|
||||
<!-- Session time -->
|
||||
<span id="sessionTime">0s</span>
|
||||
|
||||
@@ -111,89 +107,87 @@
|
||||
<span id="remoteUsername" class="hide"></span>
|
||||
</div>
|
||||
|
||||
<div class="row text-center">
|
||||
<div class="col-md-12">
|
||||
<!-- Button share Room -->
|
||||
<button
|
||||
id="shareRoomBtn"
|
||||
class="btn btn-custom btn-primary btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Share room"
|
||||
>
|
||||
<i class="fas fa-share-nodes"></i>
|
||||
</button>
|
||||
<!-- Button to hide/show the local video -->
|
||||
<button
|
||||
id="hideBtn"
|
||||
class="btn btn-custom btn-primary btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle hide me"
|
||||
>
|
||||
<i class="fas fa-eye-slash"></i>
|
||||
</button>
|
||||
<!-- Button to toggle audio stream -->
|
||||
<button
|
||||
id="audioBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle audio"
|
||||
>
|
||||
<i class="fas fa-microphone"></i>
|
||||
</button>
|
||||
<!-- Button to swap camera -->
|
||||
<button
|
||||
id="swapCameraBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Swap camera"
|
||||
>
|
||||
<i class="fas fa-camera-rotate"></i>
|
||||
</button>
|
||||
<!-- Button to toggle video stream -->
|
||||
<button
|
||||
id="videoBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle video"
|
||||
>
|
||||
<i class="fas fa-video"></i>
|
||||
</button>
|
||||
<!-- Button to share screen -->
|
||||
<button
|
||||
id="screenShareBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle screen"
|
||||
>
|
||||
<i class="fas fa-desktop"></i>
|
||||
</button>
|
||||
<!-- Toggle user sidebar button -->
|
||||
<button
|
||||
id="sidebarBtn"
|
||||
class="btn btn-custom btn-primary btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle users"
|
||||
>
|
||||
<i class="fas fa-users"></i>
|
||||
</button>
|
||||
<!-- Button to leave the call -->
|
||||
<button
|
||||
id="leaveBtn"
|
||||
class="btn btn-custom btn-danger btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Leave"
|
||||
>
|
||||
<i class="fas fa-door-open"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<!-- Button share Room -->
|
||||
<button
|
||||
id="shareRoomBtn"
|
||||
class="btn btn-custom btn-primary btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Share room"
|
||||
>
|
||||
<i class="fas fa-share-nodes"></i>
|
||||
</button>
|
||||
<!-- Button to hide/show the local video -->
|
||||
<button
|
||||
id="hideBtn"
|
||||
class="btn btn-custom btn-primary btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle hide me"
|
||||
>
|
||||
<i class="fas fa-eye-slash"></i>
|
||||
</button>
|
||||
<!-- Button to toggle audio stream -->
|
||||
<button
|
||||
id="audioBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle audio"
|
||||
>
|
||||
<i class="fas fa-microphone"></i>
|
||||
</button>
|
||||
<!-- Button to toggle video stream -->
|
||||
<button
|
||||
id="videoBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle video"
|
||||
>
|
||||
<i class="fas fa-video"></i>
|
||||
</button>
|
||||
<!-- Button to swap camera -->
|
||||
<button
|
||||
id="swapCameraBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Swap camera"
|
||||
>
|
||||
<i class="fas fa-camera-rotate"></i>
|
||||
</button>
|
||||
<!-- Button to share screen -->
|
||||
<button
|
||||
id="screenShareBtn"
|
||||
class="btn btn-custom btn-success btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle screen"
|
||||
>
|
||||
<i class="fas fa-desktop"></i>
|
||||
</button>
|
||||
<!-- Toggle user sidebar button -->
|
||||
<button
|
||||
id="sidebarBtn"
|
||||
class="btn btn-custom btn-primary btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Toggle users"
|
||||
>
|
||||
<i class="fas fa-users"></i>
|
||||
</button>
|
||||
<!-- Button to leave the call -->
|
||||
<button
|
||||
id="leaveBtn"
|
||||
class="btn btn-custom btn-danger btn-m"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title="Leave"
|
||||
>
|
||||
<i class="fas fa-phone-slash red"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -233,7 +227,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Chat Tab Content -->
|
||||
<div id="chatContent" class="tab-content mt-5">
|
||||
<div id="chatContent" class="tab-content">
|
||||
<div id="chatMessages" class="chat-messages"></div>
|
||||
<form id="chatForm" class="chat-form" autocomplete="off">
|
||||
<button
|
||||
@@ -335,13 +329,13 @@
|
||||
<!-- Include SweetAlert JS file -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.8/dist/sweetalert2.all.min.js"></script>
|
||||
|
||||
<!-- Include Bootstrap JavaScript file -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Include GitHub buttons -->
|
||||
<script src="https://buttons.github.io/buttons.js"></script>
|
||||
|
||||
<!-- Include Emoji Mart for emoji picker -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/emoji-mart@latest/dist/browser.js"></script>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1231
-374
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user