[mirotalksfu] - #194 Keep uploaded virtual background images in IndexedDB
هذا الالتزام موجود في:
@@ -64,7 +64,7 @@ let BRAND = {
|
||||
},
|
||||
about: {
|
||||
imageUrl: '../images/mirotalk-logo.gif',
|
||||
title: '<strong>WebRTC SFU v1.7.36</strong>',
|
||||
title: '<strong>WebRTC SFU v1.7.37</strong>',
|
||||
html: `
|
||||
<button
|
||||
id="support-button"
|
||||
|
||||
@@ -5011,20 +5011,107 @@ function showImageSelector() {
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const customImg = document.createElement('img');
|
||||
customImg.id = `customImage${imageCounter}`; // Assign a unique id
|
||||
customImg.src = e.target.result;
|
||||
customImg.alt = 'Custom Background';
|
||||
customImg.addEventListener('click', async function () {
|
||||
await applyVirtualBackground(initVideo, initStream, false, e.target.result);
|
||||
});
|
||||
imageGrid.appendChild(customImg);
|
||||
setTippy(customImg.id, 'Custom background', 'top');
|
||||
const imgData = e.target.result;
|
||||
saveImageToIndexedDB(imgData);
|
||||
addImageToUI(imgData);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
|
||||
// Load images from IndexedDB
|
||||
async function loadStoredImages() {
|
||||
const storedImages = await getImagesFromIndexedDB();
|
||||
storedImages.forEach((imgData) => addImageToUI(imgData));
|
||||
}
|
||||
|
||||
// Save image to IndexedDB
|
||||
async function saveImageToIndexedDB(imgData) {
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction('images', 'readwrite');
|
||||
const store = transaction.objectStore('images');
|
||||
store.add({ imgData });
|
||||
}
|
||||
|
||||
// Open IndexedDB
|
||||
function openDB() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open('customImageDB', 1);
|
||||
request.onupgradeneeded = function (event) {
|
||||
const db = event.target.result;
|
||||
if (!db.objectStoreNames.contains('images')) {
|
||||
db.createObjectStore('images', { keyPath: 'id', autoIncrement: true });
|
||||
}
|
||||
};
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
// Get images from IndexedDB
|
||||
function getImagesFromIndexedDB() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const dbRequest = openDB();
|
||||
dbRequest.then((db) => {
|
||||
const transaction = db.transaction('images', 'readonly');
|
||||
const store = transaction.objectStore('images');
|
||||
const request = store.getAll();
|
||||
|
||||
request.onsuccess = () => resolve(request.result.map((item) => item.imgData));
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Add image to UI
|
||||
function addImageToUI(imgData) {
|
||||
const imageContainer = document.createElement('div');
|
||||
imageContainer.className = 'image-wrapper';
|
||||
const customImg = document.createElement('img');
|
||||
|
||||
customImg.id = `customImageGrid${imageCounter}`;
|
||||
customImg.src = imgData;
|
||||
customImg.alt = 'Custom Background';
|
||||
customImg.addEventListener('click', async function () {
|
||||
await applyVirtualBackground(initVideo, initStream, false, imgData);
|
||||
});
|
||||
|
||||
// Create delete button
|
||||
const deleteBtn = createDeleteIcon(imgData, imageContainer);
|
||||
imageContainer.appendChild(customImg);
|
||||
imageContainer.appendChild(deleteBtn);
|
||||
imageGrid.appendChild(imageContainer);
|
||||
setTippy(customImg.id, 'Custom background', 'top');
|
||||
|
||||
imageCounter++;
|
||||
}
|
||||
|
||||
// Create delete icon
|
||||
function createDeleteIcon(imgData, container) {
|
||||
const deleteIcon = document.createElement('span');
|
||||
deleteIcon.className = 'delete-icon fas fa-times';
|
||||
deleteIcon.addEventListener('click', function (event) {
|
||||
event.stopPropagation(); // Prevent triggering background change
|
||||
removeImageFromIndexedDB(imgData);
|
||||
container.remove();
|
||||
});
|
||||
return deleteIcon;
|
||||
}
|
||||
|
||||
// Remove image from IndexedDB
|
||||
async function removeImageFromIndexedDB(imgData) {
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction('images', 'readwrite');
|
||||
const store = transaction.objectStore('images');
|
||||
|
||||
const request = store.getAll();
|
||||
request.onsuccess = () => {
|
||||
const items = request.result;
|
||||
const itemToDelete = items.find((item) => item.imgData === imgData);
|
||||
if (itemToDelete) store.delete(itemToDelete.id);
|
||||
};
|
||||
}
|
||||
|
||||
// Append the button to the imageGrid
|
||||
imageGrid.appendChild(uploadImg);
|
||||
setTippy(uploadImg.id, 'Upload your custom background', 'top');
|
||||
@@ -5040,6 +5127,9 @@ function showImageSelector() {
|
||||
});
|
||||
imageGrid.appendChild(img);
|
||||
});
|
||||
|
||||
// Load images from IndexedDB on page load
|
||||
loadStoredImages();
|
||||
}
|
||||
|
||||
async function applyVirtualBackground(videoElement, stream, blurLevel, backgroundImage) {
|
||||
|
||||
@@ -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.36
|
||||
* @version 1.7.37
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1685,7 +1685,7 @@ class RoomClient {
|
||||
const cleanVbImg = document.createElement('img');
|
||||
cleanVbImg.id = 'cleanVbImg';
|
||||
cleanVbImg.src = image.user;
|
||||
cleanVbImg.alt = 'Clean virtual bacgroundk';
|
||||
cleanVbImg.alt = 'Clean virtual background';
|
||||
cleanVbImg.dataset.index = 'cleanVb';
|
||||
cleanVbImg.addEventListener('click', async function () {
|
||||
if (!virtualBackgroundBlurLevel && !virtualBackgroundSelectedImage) {
|
||||
@@ -1726,26 +1726,113 @@ class RoomClient {
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
// Load images from IndexedDB
|
||||
async function loadStoredImages() {
|
||||
const storedImages = await getImagesFromIndexedDB();
|
||||
storedImages.forEach((imgData) => addImageToUI(imgData));
|
||||
}
|
||||
|
||||
// Handle image selection
|
||||
fileInput.addEventListener('change', function () {
|
||||
const file = this.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const customImg = document.createElement('img');
|
||||
customImg.id = `customImage${imageCounter}`; // Assign a unique id
|
||||
customImg.src = e.target.result;
|
||||
customImg.alt = 'Custom Background';
|
||||
customImg.addEventListener('click', async function () {
|
||||
await rc.applyVirtualBackground(false, e.target.result);
|
||||
});
|
||||
imageGridVideo.appendChild(customImg);
|
||||
setTippy(customImg.id, 'Custom background', 'top');
|
||||
const imgData = e.target.result;
|
||||
saveImageToIndexedDB(imgData);
|
||||
addImageToUI(imgData);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
|
||||
// Add image with delete button to UI
|
||||
function addImageToUI(imgData) {
|
||||
const imageContainer = document.createElement('div');
|
||||
imageContainer.className = 'image-wrapper';
|
||||
const customImg = document.createElement('img');
|
||||
|
||||
customImg.id = `customImageGrid${imageCounter}`;
|
||||
customImg.src = imgData;
|
||||
customImg.alt = 'Custom Background';
|
||||
customImg.addEventListener('click', async function () {
|
||||
await rc.applyVirtualBackground(false, imgData);
|
||||
});
|
||||
|
||||
// Create delete button
|
||||
const deleteBtn = createDeleteIcon(imgData, imageContainer);
|
||||
imageContainer.appendChild(customImg);
|
||||
imageContainer.appendChild(deleteBtn);
|
||||
imageGridVideo.appendChild(imageContainer);
|
||||
setTippy(customImg.id, 'Custom background', 'top');
|
||||
|
||||
imageCounter++;
|
||||
}
|
||||
|
||||
// Create delete icon
|
||||
function createDeleteIcon(imgData, container) {
|
||||
const deleteIcon = document.createElement('span');
|
||||
deleteIcon.className = 'delete-icon fas fa-times';
|
||||
deleteIcon.addEventListener('click', function (event) {
|
||||
event.stopPropagation(); // Prevent triggering background change
|
||||
removeImageFromIndexedDB(imgData);
|
||||
container.remove();
|
||||
});
|
||||
return deleteIcon;
|
||||
}
|
||||
|
||||
// Save image to IndexedDB
|
||||
async function saveImageToIndexedDB(imgData) {
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction('images', 'readwrite');
|
||||
const store = transaction.objectStore('images');
|
||||
store.add({ imgData });
|
||||
}
|
||||
|
||||
// Open IndexedDB
|
||||
function openDB() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open('customImageDB', 1);
|
||||
request.onupgradeneeded = function (event) {
|
||||
const db = event.target.result;
|
||||
if (!db.objectStoreNames.contains('images')) {
|
||||
db.createObjectStore('images', { keyPath: 'id', autoIncrement: true });
|
||||
}
|
||||
};
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
// Get images from IndexedDB
|
||||
function getImagesFromIndexedDB() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const dbRequest = openDB();
|
||||
dbRequest.then((db) => {
|
||||
const transaction = db.transaction('images', 'readonly');
|
||||
const store = transaction.objectStore('images');
|
||||
const request = store.getAll();
|
||||
|
||||
request.onsuccess = () => resolve(request.result.map((item) => item.imgData));
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Remove image from IndexedDB
|
||||
async function removeImageFromIndexedDB(imgData) {
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction('images', 'readwrite');
|
||||
const store = transaction.objectStore('images');
|
||||
|
||||
const request = store.getAll();
|
||||
request.onsuccess = () => {
|
||||
const items = request.result;
|
||||
const itemToDelete = items.find((item) => item.imgData === imgData);
|
||||
if (itemToDelete) store.delete(itemToDelete.id);
|
||||
};
|
||||
}
|
||||
|
||||
// Append the button to the imageGrid
|
||||
imageGridVideo.appendChild(uploadImg);
|
||||
setTippy(uploadImg.id, 'Upload your custom background', 'top');
|
||||
@@ -1761,6 +1848,9 @@ class RoomClient {
|
||||
});
|
||||
imageGridVideo.appendChild(img);
|
||||
});
|
||||
|
||||
// Load images from IndexedDB on page load
|
||||
loadStoredImages();
|
||||
}
|
||||
|
||||
async applyVirtualBackground(blurLevel, backgroundImage) {
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم