diff --git a/app/src/Server.js b/app/src/Server.js index 73cf5e87..cbd08627 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -58,7 +58,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.7.37 + * @version 1.7.38 * */ diff --git a/package.json b/package.json index b834d4e1..cd9a2bd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.7.37", + "version": "1.7.38", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { diff --git a/public/css/Room.css b/public/css/Room.css index ca6a9d5c..b815a614 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -269,6 +269,54 @@ body { color: white; } +/*-------------------------------------------------------------- +# Custom modal to paste image URL +--------------------------------------------------------------*/ + +.imageUrlModal { + display: none; + position: fixed; + z-index: 9999; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: var(--body-bg); + width: 80%; + max-width: 400px; + padding: 20px; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); +} + +.imageUrlModal-content { + background: var(--body-bg); + padding: 20px; + border-radius: 8px; + text-align: center; +} + +.imageUrlModal input { + width: 80%; + padding: 10px; + margin: 10px 0; + border: var(--border); + border-radius: 4px; +} + +.imageUrlModal button { + padding: 10px 20px; + border: none; + background: var(--btns-bg-color); + border-radius: 10px; + border-radius: 4px; + cursor: pointer; + margin: 5px; +} + +.imageUrlModal button:hover { + background: var(--body-bg) !important; +} + /*-------------------------------------------------------------- # Buttons bar --------------------------------------------------------------*/ diff --git a/public/images/link.png b/public/images/link.png new file mode 100644 index 00000000..ad402cef Binary files /dev/null and b/public/images/link.png differ diff --git a/public/js/Brand.js b/public/js/Brand.js index 6c3cf73e..8468b69f 100644 --- a/public/js/Brand.js +++ b/public/js/Brand.js @@ -64,7 +64,7 @@ let BRAND = { }, about: { imageUrl: '../images/mirotalk-logo.gif', - title: 'WebRTC SFU v1.7.37', + title: 'WebRTC SFU v1.7.38', html: ` { + elemDisplay(imageUrlModal.id, false); + if (isValidURL(imageUrlInput.value)) { + await fetchAndStoreImage(imageUrlInput.value); + imageUrlInput.value = ''; + } + }); + + cancelImageUrlBtn.addEventListener('click', () => { + elemDisplay(imageUrlModal.id, false); + imageUrlInput.value = ''; + }); + + function askForImageURL() { + elemDisplay(imageUrlModal.id, true); + + // Take URL from clipboard ex: + navigator.clipboard + .readText() + .then((clipboardText) => { + if (!clipboardText) return false; + const sanitizedText = filterXSS(clipboardText); + if (isValidURL(sanitizedText) && imageUrlInput) { + imageUrlInput.value = sanitizedText; + } + return false; + }) + .catch(() => { + return false; + }); + } + + // Function to validate URL format + function isValidURL(url) { + return ( + url.match(/\.(jpeg|jpg|png|gif|webp|bmp|svg|apng|avif|heif|heic|tiff?|ico|cur|jfif|pjpeg|pjp|raw)$/i) !== + null + ); + } + + // Create link to upload image + const linkImg = document.createElement('img'); + linkImg.id = 'linkImage'; + linkImg.src = image.link; + linkImg.alt = 'Link image'; + linkImg.addEventListener('click', askForImageURL); + imageGrid.appendChild(linkImg); + setTippy(linkImg.id, 'Upload Image from Url', 'top'); + // Loop through virtual background images dynamically virtualBackgrounds.forEach((imageUrl, index) => { const img = document.createElement('img'); diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 5a912ec0..158685de 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -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.7.37 + * @version 1.7.38 * */ @@ -114,6 +114,7 @@ const image = { transcription: '../images/transcription.png', back: '../images/back.png', blur: '../images/blur.png', + link: '../images/link.png', upload: '../images/upload.png', virtualBackground: { one: '../images/virtual-background/background-1.jpg', @@ -1837,6 +1838,75 @@ class RoomClient { imageGridVideo.appendChild(uploadImg); setTippy(uploadImg.id, 'Upload your custom background', 'top'); + // Function to fetch image from URL and store it in IndexedDB + async function fetchAndStoreImage(url) { + try { + const response = await fetch(url); + const blob = await response.blob(); + const reader = new FileReader(); + + reader.onload = function (e) { + const imgData = e.target.result; + saveImageToIndexedDB(imgData); + addImageToUI(imgData); + }; + + reader.readAsDataURL(blob); + } catch (error) { + console.error('Error fetching image:', error); + } + } + + saveImageUrlBtn.addEventListener('click', async () => { + elemDisplay(imageUrlModal.id, false); + if (isValidURL(imageUrlInput.value)) { + await fetchAndStoreImage(imageUrlInput.value); + imageUrlInput.value = ''; + } + }); + + cancelImageUrlBtn.addEventListener('click', () => { + elemDisplay(imageUrlModal.id, false); + imageUrlInput.value = ''; + }); + + function askForImageURL() { + elemDisplay(imageUrlModal.id, true); + + // Take URL from clipboard ex: + navigator.clipboard + .readText() + .then((clipboardText) => { + if (!clipboardText) return false; + const sanitizedText = filterXSS(clipboardText); + if (isValidURL(sanitizedText) && imageUrlInput) { + imageUrlInput.value = sanitizedText; + } + return false; + }) + .catch(() => { + return false; + }); + } + + // Function to validate URL format + function isValidURL(url) { + return ( + url.match( + /\.(jpeg|jpg|png|gif|webp|bmp|svg|apng|avif|heif|heic|tiff?|ico|cur|jfif|pjpeg|pjp|raw)$/i, + ) !== null + ); + } + + // Create link to upload image + const linkImg = document.createElement('img'); + linkImg.id = 'linkImage'; + linkImg.src = image.link; + linkImg.alt = 'Link image'; + linkImg.addEventListener('click', askForImageURL); + imageGridVideo.appendChild(linkImg); + setTippy(linkImg.id, 'Upload Image from Url', 'top'); + // Loop through virtual background images dynamically virtualBackgrounds.forEach((imageUrl, index) => { const img = document.createElement('img'); diff --git a/public/views/Room.html b/public/views/Room.html index b9e8705a..9bec24c0 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -175,6 +175,14 @@ Loading + + + Paste Image URL + + Save + Cancel + +