diff --git a/app/src/server.js b/app/src/server.js
index eb224eab..9da266ab 100755
--- a/app/src/server.js
+++ b/app/src/server.js
@@ -39,7 +39,7 @@ dependencies: {
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.3.68
+ * @version 1.3.70
*
*/
diff --git a/package.json b/package.json
index f3a3f29d..37fb4f8a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mirotalk",
- "version": "1.3.68",
+ "version": "1.3.70",
"description": "A free WebRTC browser-based video call",
"main": "server.js",
"scripts": {
@@ -55,7 +55,7 @@
"js-yaml": "^4.1.0",
"ngrok": "^5.0.0-beta.2",
"nodemailer": "^6.9.14",
- "openai": "^4.55.7",
+ "openai": "^4.56.0",
"qs": "^6.13.0",
"socket.io": "^4.7.5",
"swagger-ui-express": "^5.0.1",
diff --git a/public/css/client.css b/public/css/client.css
index 435e5196..e5cb2fd7 100755
--- a/public/css/client.css
+++ b/public/css/client.css
@@ -16,6 +16,8 @@
--msger-width: 420px;
--msger-bubble-width: 85%;
+ --caption-top: 50%;
+ --caption-left: 50%;
--caption-height: 680px;
--caption-width: 420px;
@@ -345,10 +347,6 @@ body {
z-index: 14;
display: none;
position: fixed;
- /* center screen */
- top: var(--caption-top);
- left: var(--caption-left);
- transform: translate(-50%, -50%);
/* end center screen */
height: var(--caption-height);
width: var(--caption-width);
@@ -361,6 +359,7 @@ body {
overflow: hidden;
border-radius: 10px;
box-shadow: var(--box-shadow);
+ transition: width 0.5s ease-in-out;
}
.caption {
@@ -386,7 +385,7 @@ body {
padding: 5px;
/* border: var(--border); */
border: none;
- font-size: 1.1rem;
+ font-size: 1rem;
background: transparent;
color: #fff;
border-radius: 5px;
@@ -467,10 +466,6 @@ body {
z-index: 14;
display: none;
position: fixed;
- /* center screen */
- top: var(--msger-top);
- left: var(--msger-left);
- transform: translate(-50%, -50%);
/* end center screen */
height: var(--msger-height);
width: var(--msger-width);
@@ -483,6 +478,7 @@ body {
overflow: hidden;
border-radius: 10px;
box-shadow: var(--box-shadow);
+ transition: width 0.5s ease-in-out;
}
.msger {
@@ -520,7 +516,7 @@ body {
padding: 5px;
/* border: var(--border); */
border: none;
- font-size: 1.1rem;
+ font-size: 1rem;
background: transparent;
color: #fff;
border-radius: 5px;
@@ -860,10 +856,11 @@ button:hover {
position: absolute;
bottom: 105px;
left: 10px;
+ background: var(--body-bg);
border: var(--border);
border-radius: 5px;
- --rgb-background: var(--body-bg);
- --color-border-over: var(--body-bg);
+ --rgb-background: var(--body-bg) !important;
+ --color-border-over: var(--body-bg) !important;
--font-family: 'Comfortaa';
}
@@ -1875,11 +1872,11 @@ hr {
/* Styles for the dropdown button */
.dropdown-toggle {
- background-color: var(--body-bg);
+ /* padding: 10px 20px; */
color: #fff;
border: none;
border-radius: 5px;
- /* padding: 10px 20px; */
+ background-color: var(--body-bg);
cursor: pointer;
}
@@ -1894,6 +1891,59 @@ hr {
box-shadow: var(--box-shadow);
}
+/*--------------------------------------------------------------
+# Dropdown menu custom
+--------------------------------------------------------------*/
+
+/* General container for the dropdown */
+.dropdown-custom {
+ position: relative;
+ display: inline-block;
+}
+
+/* Style the button that triggers the dropdown */
+.dropdown-toggle-custom {
+ color: #fff;
+ border: var(--border);
+ background: var(--body-bg);
+ cursor: pointer;
+}
+
+/* Dropdown menu */
+.dropdown-menu-custom {
+ z-index: 1;
+ display: none;
+ position: absolute;
+ right: 0;
+ padding: 10px 0;
+ min-width: 240px;
+ border-radius: 5px;
+ border: var(--border);
+ background: var(--body-bg);
+ box-shadow: var(--box-shadow);
+}
+
+/* Style for dropdown items */
+.dropdown-menu-custom li {
+ padding: 8px 16px;
+ list-style-type: none;
+}
+
+.dropdown-menu-custom li button {
+ border: none;
+ background: none;
+ width: 100%;
+ text-align: left;
+ padding: 8px 16px;
+ font-size: 0.8em;
+ cursor: pointer;
+ color: #fff;
+}
+
+.dropdown-menu-custom li button:hover {
+ background-color: var(--hover-bg); /* Use a default hover color if --hover-bg is not defined */
+}
+
/* Styles for table cell with title (td) */
.microphone-table-width {
width: 50%;
diff --git a/public/js/client.js b/public/js/client.js
index 55d65ca8..d5bd7fbc 100644
--- a/public/js/client.js
+++ b/public/js/client.js
@@ -15,7 +15,7 @@
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.3.68
+ * @version 1.3.70
*
*/
@@ -166,6 +166,7 @@ const buttons = {
showAboutBtn: true, // Please keep me always true, Thank you!
},
chat: {
+ showTogglePinBtn: true,
showMaxBtn: true,
showSaveMessageBtn: true,
showMarkDownBtn: true,
@@ -175,6 +176,7 @@ const buttons = {
showParticipantsBtn: true,
},
caption: {
+ showTogglePinBtn: true,
showMaxBtn: true,
},
settings: {
@@ -265,8 +267,11 @@ const userEmoji = getId(`userEmoji`);
// Chat room
const msgerDraggable = getId('msgerDraggable');
const msgerHeader = getId('msgerHeader');
+const msgerTogglePin = getId('msgerTogglePin');
const msgerTheme = getId('msgerTheme');
const msgerCPBtn = getId('msgerCPBtn');
+const msgerDropDownMenuBtn = getId('msgerDropDownMenuBtn');
+const msgerDropDownContent = getId('msgerDropDownContent');
const msgerClean = getId('msgerClean');
const msgerSaveBtn = getId('msgerSaveBtn');
const msgerClose = getId('msgerClose');
@@ -349,6 +354,7 @@ const searchPeerBarName = getId('searchPeerBarName');
// Caption section
const captionDraggable = getId('captionDraggable');
const captionHeader = getId('captionHeader');
+const captionTogglePin = getId('captionTogglePin');
const captionTheme = getId('captionTheme');
const captionMaxBtn = getId('captionMaxBtn');
const captionMinBtn = getId('captionMinBtn');
@@ -652,6 +658,8 @@ let leftChatAvatar;
let rightChatAvatar;
let chatMessagesId = 0;
let showChatOnMessage = true;
+let isChatPinned = false;
+let isCaptionPinned = false;
let isChatRoomVisible = false;
let isCaptionBoxVisible = false;
let isChatEmojiVisible = false;
@@ -764,9 +772,8 @@ function setButtonsToolTip() {
setTippy(msgerClose, 'Close', 'bottom');
setTippy(msgerShowChatOnMsgDiv, 'Show chat when you receive a new message', 'bottom');
setTippy(msgerSpeechMsgDiv, 'Speech the incoming messages', 'bottom');
+ setTippy(msgerTogglePin, 'Toggle chat pin', 'bottom');
setTippy(msgerTheme, 'Ghost theme', 'bottom');
- setTippy(msgerClean, 'Clean the messages', 'bottom');
- setTippy(msgerSaveBtn, 'Save the messages', 'bottom');
setTippy(msgerMaxBtn, 'Maximize', 'bottom');
setTippy(msgerMinBtn, 'Minimize', 'bottom');
setTippy(msgerEmojiBtn, 'Emoji', 'top');
@@ -783,6 +790,7 @@ function setButtonsToolTip() {
setTippy(captionClose, 'Close', 'bottom');
setTippy(captionMaxBtn, 'Maximize', 'bottom');
setTippy(captionMinBtn, 'Minimize', 'bottom');
+ setTippy(captionTogglePin, 'Toggle caption pin', 'bottom');
setTippy(captionTheme, 'Ghost theme', 'bottom');
setTippy(captionClean, 'Clean the messages', 'bottom');
setTippy(captionSaveBtn, 'Save the messages', 'bottom');
@@ -1405,6 +1413,7 @@ function handleButtonsRule() {
elemDisplay(mySettingsBtn, buttons.main.showMySettingsBtn);
elemDisplay(aboutBtn, buttons.main.showAboutBtn);
// chat
+ elemDisplay(msgerTogglePin, !isMobileDevice && buttons.chat.showTogglePinBtn);
elemDisplay(msgerMaxBtn, !isMobileDevice && buttons.chat.showMaxBtn);
elemDisplay(msgerSaveBtn, buttons.chat.showSaveMessageBtn);
elemDisplay(msgerMarkdownBtn, buttons.chat.showMarkDownBtn);
@@ -1413,6 +1422,7 @@ function handleButtonsRule() {
elemDisplay(msgerVideoUrlBtn, buttons.chat.showShareVideoAudioBtn);
elemDisplay(msgerCPBtn, buttons.chat.showParticipantsBtn);
// caption
+ elemDisplay(captionTogglePin, !isMobileDevice && buttons.caption.showTogglePinBtn);
elemDisplay(captionMaxBtn, !isMobileDevice && buttons.caption.showMaxBtn);
// Settings
elemDisplay(dropDownMicOptions, buttons.settings.showMicOptionsBtn && isPresenter); // auto-detected
@@ -4260,13 +4270,39 @@ function removeVideoPinMediaContainer(peer_id, force_remove = false) {
force_remove
) {
elemDisplay(videoPinMediaContainer, false);
+ isVideoPinned = false;
+ pinnedVideoPlayerId = null;
+ videoMediaContainerUnpin();
+ if (isChatPinned) {
+ chatPin();
+ }
+ if (isCaptionPinned) {
+ captionPin();
+ }
+ resizeVideoMedia();
+ }
+}
+
+/**
+ * Pin videoMediaContainer
+ */
+function videoMediaContainerPin() {
+ if (!isVideoPinned) {
+ videoMediaContainer.style.top = 0;
+ videoMediaContainer.style.width = '75%';
+ videoMediaContainer.style.height = '100%';
+ }
+}
+
+/**
+ * Unpin videoMediaContainer
+ */
+function videoMediaContainerUnpin() {
+ if (!isVideoPinned) {
videoMediaContainer.style.top = 0;
videoMediaContainer.style.right = null;
videoMediaContainer.style.width = '100%';
videoMediaContainer.style.height = '100%';
- pinnedVideoPlayerId = null;
- isVideoPinned = false;
- resizeVideoMedia();
}
}
@@ -4542,6 +4578,11 @@ function setChatRoomBtn() {
}
});
+ // pin/unpin
+ msgerTogglePin.addEventListener('click', () => {
+ toggleChatPin();
+ });
+
// ghost theme + undo
msgerTheme.addEventListener('click', (e) => {
if (e.target.className == className.ghost) {
@@ -4553,6 +4594,11 @@ function setChatRoomBtn() {
}
});
+ // dropdown chat menu
+ msgerDropDownMenuBtn.addEventListener('click', () => {
+ toggleChatDropDownMenu();
+ });
+
// show msger participants section
msgerCPBtn.addEventListener('click', (e) => {
if (!thereArePeerConnections()) {
@@ -4714,6 +4760,11 @@ function setCaptionRoomBtn() {
captionMinimize();
});
+ // toggle caption pin
+ captionTogglePin.addEventListener('click', () => {
+ toggleCaptionPin();
+ });
+
// ghost theme + undo
captionTheme.addEventListener('click', (e) => {
if (e.target.className == className.ghost) {
@@ -7068,9 +7119,7 @@ function showChatRoomDraggable() {
isButtonsVisible = false;
}
chatRoomBtn.className = className.chatOff;
- msgerDraggable.style.top = '50%';
- msgerDraggable.style.left = isMobileDevice ? '50%' : '25%';
- msgerDraggable.style.display = 'flex';
+ chatLeftCenter();
isChatRoomVisible = true;
setTippy(chatRoomBtn, 'Close the chat', placement);
}
@@ -7086,13 +7135,20 @@ function showCaptionDraggable() {
isButtonsVisible = false;
}
captionBtn.className = 'far fa-closed-captioning';
- captionDraggable.style.top = '50%';
- captionDraggable.style.left = isMobileDevice ? '50%' : '75%';
- captionDraggable.style.display = 'flex';
+ captionRightCenter();
isCaptionBoxVisible = true;
setTippy(captionBtn, 'Close the caption', placement);
}
+/**
+ * Toggle Chat dropdown menu
+ */
+function toggleChatDropDownMenu() {
+ msgerDropDownContent.style.display === 'block'
+ ? (msgerDropDownContent.style.display = 'none')
+ : (msgerDropDownContent.style.display = 'block');
+}
+
/**
* Chat maximize
*/
@@ -7111,16 +7167,87 @@ function chatMinimize() {
elemDisplay(msgerMinBtn, false);
elemDisplay(msgerMaxBtn, true);
chatCenter();
- setSP('--msger-width', '420px');
- setSP('--msger-height', '680px');
+ if (!isChatPinned) {
+ setSP('--msger-width', '420px');
+ setSP('--msger-height', '680px');
+ } else {
+ setSP('--msger-width', '25%');
+ setSP('--msger-height', '100%');
+ }
}
/**
* Set chat position
*/
function chatCenter() {
+ if (!isChatPinned) {
+ msgerDraggable.style.top = '50%';
+ msgerDraggable.style.left = '50%';
+ }
+}
+
+/**
+ * Toggle Chat Pin
+ */
+function toggleChatPin() {
+ if (isCaptionPinned) {
+ return userLog('toast', 'Please unpin the Caption that appears to be currently pinned');
+ }
+ isChatPinned ? chatUnpin() : chatPin();
+ playSound('click');
+}
+
+/**
+ * Handle chat pin
+ */
+function chatPin() {
+ videoMediaContainerPin();
+ chatPinned();
+ isChatPinned = true;
+ setColor(msgerTogglePin, 'lime');
+ resizeVideoMedia();
+ msgerDraggable.style.resize = 'none';
+ if (!isMobileDevice) undragElement(msgerDraggable, msgerHeader);
+}
+
+/**
+ * Handle chat unpin
+ */
+function chatUnpin() {
+ videoMediaContainerUnpin();
+ setSP('--msger-width', '420px');
+ setSP('--msger-height', '680px');
+ elemDisplay(msgerMinBtn, false);
+ buttons.chat.showMaxBtn && elemDisplay(msgerMaxBtn, true);
+ chatLeftCenter();
+ isChatPinned = false;
+ setColor(msgerTogglePin, 'white');
+ resizeVideoMedia();
+ if (!isMobileDevice) dragElement(msgerDraggable, msgerHeader);
+}
+
+/**
+ * Move Chat center left
+ */
+function chatLeftCenter() {
+ msgerDraggable.style.position = 'fixed';
+ msgerDraggable.style.display = 'flex';
msgerDraggable.style.top = '50%';
- msgerDraggable.style.left = '50%';
+ msgerDraggable.style.left = isMobileDevice ? '50%' : '25%';
+ msgerDraggable.style.transform = 'translate(-50%, -50%)';
+}
+
+/**
+ * Chat is pinned
+ */
+function chatPinned() {
+ msgerDraggable.style.position = 'absolute';
+ msgerDraggable.style.top = 0;
+ msgerDraggable.style.right = 0;
+ msgerDraggable.style.left = null;
+ msgerDraggable.style.transform = null;
+ setSP('--msger-width', '25%');
+ setSP('--msger-height', '100%');
}
/**
@@ -7141,16 +7268,87 @@ function captionMinimize() {
elemDisplay(captionMinBtn, false);
elemDisplay(captionMaxBtn, true);
captionCenter();
- setSP('--caption-width', '420px');
- setSP('--caption-height', '680px');
+ if (!isCaptionPinned) {
+ setSP('--caption-width', '420px');
+ setSP('--caption-height', '680px');
+ } else {
+ setSP('--caption-width', '25%');
+ setSP('--caption-height', '100%');
+ }
}
/**
- * Set caption position
+ * Set chat position
*/
function captionCenter() {
+ if (!isCaptionPinned) {
+ captionDraggable.style.top = '50%';
+ captionDraggable.style.left = '50%';
+ }
+}
+
+/**
+ * Toggle Caption Pin
+ */
+function toggleCaptionPin() {
+ if (isChatPinned) {
+ return userLog('toast', 'Please unpin the Chat that appears to be currently pinned');
+ }
+ isCaptionPinned ? captionUnpin() : captionPin();
+ playSound('click');
+}
+
+/**
+ * Handle caption pin
+ */
+function captionPin() {
+ videoMediaContainerPin();
+ captionPinned();
+ isCaptionPinned = true;
+ setColor(captionTogglePin, 'lime');
+ resizeVideoMedia();
+ captionDraggable.style.resize = 'none';
+ if (!isMobileDevice) undragElement(captionDraggable, captionHeader);
+}
+
+/**
+ * Handle caption unpin
+ */
+function captionUnpin() {
+ videoMediaContainerUnpin();
+ setSP('--caption-width', '420px');
+ setSP('--caption-height', '680px');
+ elemDisplay(captionMinBtn, false);
+ buttons.caption.showMaxBtn && elemDisplay(captionMaxBtn, true);
+ captionRightCenter();
+ isCaptionPinned = false;
+ setColor(captionTogglePin, 'white');
+ resizeVideoMedia();
+ if (!isMobileDevice) dragElement(captionDraggable, captionHeader);
+}
+
+/**
+ * Move Caption center right
+ */
+function captionRightCenter() {
+ captionDraggable.style.position = 'fixed';
+ captionDraggable.style.display = 'flex';
captionDraggable.style.top = '50%';
- captionDraggable.style.left = '50%';
+ captionDraggable.style.left = isMobileDevice ? '50%' : '75%';
+ captionDraggable.style.transform = 'translate(-50%, -50%)';
+}
+
+/**
+ * Caption is pinned
+ */
+function captionPinned() {
+ captionDraggable.style.position = 'absolute';
+ captionDraggable.style.top = 0;
+ captionDraggable.style.right = 0;
+ captionDraggable.style.left = null;
+ captionDraggable.style.transform = null;
+ setSP('--caption-width', '25%');
+ setSP('--caption-height', '100%');
}
/**
@@ -7219,6 +7417,9 @@ function cleanCaptions() {
* Hide chat room and emoji picker
*/
function hideChatRoomAndEmojiPicker() {
+ if (isChatPinned) {
+ chatUnpin();
+ }
elemDisplay(msgerDraggable, false);
elemDisplay(msgerEmojiPicker, false);
setColor(msgerEmojiBtn, '#FFFFFF');
@@ -7232,6 +7433,9 @@ function hideChatRoomAndEmojiPicker() {
* Hide chat room and emoji picker
*/
function hideCaptionBox() {
+ if (isCaptionPinned) {
+ captionUnpin();
+ }
elemDisplay(captionDraggable, false);
captionBtn.className = className.captionOn;
isCaptionBoxVisible = false;
@@ -10291,7 +10495,7 @@ function showAbout() {
Swal.fire({
background: swBg,
position: 'center',
- title: 'WebRTC P2P v1.3.68',
+ title: 'WebRTC P2P v1.3.70',
imageAlt: 'mirotalk-about',
imageUrl: images.about,
customClass: { image: 'img-about' },
@@ -10419,6 +10623,21 @@ function dragElement(elmnt, dragObj) {
}
}
+/**
+ * Make Obj Undraggable
+ * @param {object} elmnt father element
+ * @param {object} dragObj children element to make father undraggable
+ */
+function undragElement(elmnt, dragObj) {
+ if (dragObj) {
+ dragObj.onmousedown = null;
+ } else {
+ elmnt.onmousedown = null;
+ }
+ elmnt.style.top = '';
+ elmnt.style.left = '';
+}
+
/**
* Date Format: https://convertio.co/it/
* @returns {string} date string format: DD-MM-YYYY-H_M_S
diff --git a/public/views/client.html b/public/views/client.html
index 20093e9f..7b940e90 100755
--- a/public/views/client.html
+++ b/public/views/client.html
@@ -160,28 +160,53 @@ access to use this app.
@@ -257,6 +282,7 @@ access to use this app.