From 07a86a95d3d068202627ee9b981ea8f484191ce0 Mon Sep 17 00:00:00 2001 From: drlight17 <37434652+drlight17@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:31:14 +0300 Subject: [PATCH] v 0.2.9-alpha --- main.js | 326 ++++++++++++++++++++++++++++++++++++++----- nextcloud_check.js | 3 + package.json | 6 +- package.json.linux | 8 +- settings.html | 4 + settings.js | 6 + translations/en.json | 2 + translations/ru.json | 2 + unread_observer.js | 6 + 9 files changed, 323 insertions(+), 40 deletions(-) diff --git a/main.js b/main.js index 17f26c4..ddde3bd 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,4 @@ -// Modules to control application life and create native browser window + // Modules to control application life and create native browser window const prompt = require('electron-prompt'); @@ -21,6 +21,11 @@ if (isWindows) { var { BrowserWindow } = require('electron-acrylic-window') // return BrowserWindows to electron in case of not using electron-acrylic-window }*/ const { app, clipboard, BrowserWindow, Menu, Tray, nativeImage, Notification, dialog, session, shell, powerMonitor, nativeTheme } = require('electron') +const { exec } = require('child_process'); + +//const SystemIdleTime = require('@paulcbetts/system-idle-time'); +const SystemIdleTime = require('desktop-idle'); + const fs = require("fs"); const { join } = require('path'); @@ -47,31 +52,43 @@ try { main(); async function main() { + + const store = new Store(); + // TODO check allow_multiple in newer version + let allow_multiple = false/*store.get('allow_multiple') ? JSON.parse(store.get('allow_multiple')) : false;*/ // prevent multiple instances, focus on the existed app instead if (!gotTheLock) { - app.exit(0); + if (!allow_multiple) { + app.exit(0); + } } else { + if (!allow_multiple) { app.on('second-instance', (event) => { - if (win) { - //if (win.isMinimized()) win.restore(); - win.show(); - win.focus(); - } - }) + if (win) { + //if (win.isMinimized()) win.restore(); + win.show(); + win.focus(); + if (isMac) app.dock.show(); + } + }) + } try { - const store = new Store(); // to check prompted status for dialogs let prompted = false let auto_login_error = false + let idleTime_non_active = 0; // to check gui_blocked status //let gui_blocked = false //let is_notification = false; // for storing unread counter let unread = false; + let unread_prev = false; // to store settings menu opened status let settings_opened = false; + setTimeout(function() {checkNewVersion(app.getVersion())},3000); + let url = ""; const url_example = 'https://cloud.example.com'; @@ -86,6 +103,7 @@ try { let iconPath = path.join(__dirname,store.get('app_icon_name')||'iconTemplate.png'); let icon = nativeImage.createFromPath(iconPath); // template with center transparency let trayIcon = icon + let dockIcon = icon if (isMac) { var icon_bw = await bw_icon_process(icon); @@ -94,7 +112,7 @@ try { } //icon = icon_bw - const icon_notification = nativeImage.createFromPath(path.join(__dirname,store.get('notification_icon_name')||'notification.png')); + //const icon_notification = nativeImage.createFromPath(path.join(__dirname,store.get('notification_icon_name')||'notification.png')); //const icon_red_dot = nativeImage.createFromPath(path.join(__dirname,'red_dot.png')); @@ -167,6 +185,8 @@ Icon=talk-electron`; accelerator: isMac ? 'Cmd+Q' : 'Alt+X', click: () => { store.set('bounds', win.getBounds()); + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); }, } @@ -189,7 +209,7 @@ Icon=talk-electron`; { label: i18n.__('hide'), click: () => { if (isMac) app.dock.hide(); - win.hide() + /*if (!isMac)*/ win.hide(); }, accelerator: isMac ? 'Cmd+H' : 'Ctrl+H', role : "hide" @@ -240,14 +260,17 @@ Icon=talk-electron`; win_loading.show(); }*/ win.show() - if (isMac) { /*app.dock.setIcon(icon);*/ app.dock.show();}; + + if (isMac) { //app.dock.setIcon(dockIcon); + app.dock.show(); addBadgeMac(); + }; }, }, { label: i18n.__('hide'), click: () => { if (isMac) app.dock.hide(); - win.hide() + /*if (!isMac)*/ win.hide(); //win_loading.hide(); }, role : "hide" @@ -265,16 +288,61 @@ Icon=talk-electron`; openSettings(); }, }, + { + label : i18n.__('about'), + // for linux compatibility + click: () => { + app.showAboutPanel(); + } + }, { type: 'separator' }, { label: i18n.__('exit'), click: () => { store.set('bounds', win.getBounds()); + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); }, } ]; + /*function checkInactivity() { + const idleTime = SystemIdleTime.getIdleTime(); + console.log('Idle time is:'+idleTime+' s'); + //const idleTime = Date.now() - lastActivityTime; + if (idleTime > 4 * 60 ) { + console.log("User is not active for 4 minutes..."); + } else { + //simulateActivity(); + if (!win.isVisible() || !win.isFocused()) { + console.log("User is active for the last 4 minutes so reloading window to simulate activity..."); + win.reload(); + } + } + }*/ + + function checkInactivity(activity_check_interval) { + let idleTime = SystemIdleTime.getIdleTime(); + + if (!win.isVisible() || !win.isFocused()) { + idleTime_non_active = idleTime_non_active + activity_check_interval; + } else { + idleTime_non_active = 0; + } + + //console.log('Current idle time is:'+idleTime+' s'); + //console.log('Current hidden or unfocused time is:'+idleTime_non_active+' s'); + + if (idleTime_non_active > 4 * 60) { + if (idleTime <= 4 * 60) { + console.log("Window is hidden or unfocused for more than 4 minutes, but user was active - reloading the page..."); + idleTime_non_active = 0; + win.reload(); + } + } + } + function checkMaximize(click) { if (win.isMaximized()) { if (click) { @@ -294,6 +362,7 @@ Icon=talk-electron`; MainMenu = Menu.buildFromTemplate(mainMenuTemplate); Menu.setApplicationMenu(MainMenu); + checkNewVersion(app.getVersion()); } function isInternalLink(url) { @@ -410,6 +479,104 @@ Icon=talk-electron`; win.webContents.executeJavaScript(`loadSettings(`+JSON.stringify(store.store)+`,`+lang_files+`);`); } + function addNewVersionLink(releaseUrl,latestVersion) { + + const separator = { type: 'separator' }; + + const menu = Menu.getApplicationMenu(); + const newVersionLabel = i18n.__('new_version')+latestVersion; + + const newVersionMenuItem = { + label: newVersionLabel, + click: () => { + shell.openExternal(releaseUrl); + } + }; + + const menuItems = menu.items.map(item => item); + const exists = menuItems.some(item => item.label === newVersionLabel); + + if (!exists) { + + menuItems.push(separator); + menuItems.push(newVersionMenuItem); + + + const updatedMenu = Menu.buildFromTemplate(menuItems); + Menu.setApplicationMenu(updatedMenu); + } + } + + async function checkNewVersion(currentVersion) { + const cachedVersion = store.get('latestVersion'); + const cachedUrl = store.get('releaseUrl'); + + const apiUrl = `https://api.github.com/repos/drlight17/talk-electron/releases/latest`; + + try { + let latestVersion; + let releaseUrl; + if (!cachedVersion && !cachedUrl) { + //console.log("Fetch new version info from github.") + const response = await fetch(apiUrl); + const data = await response.json(); + + // Извлекаем версию последнего релиза (tag name) + latestVersion = data.tag_name; + releaseUrl = data.html_url; + + store.set('latestVersion', latestVersion); + store.set('releaseUrl', releaseUrl); + + //console.log(`Current version: ${currentVersion}`); + //console.log(`Latest version: ${latestVersion}`); + + + } else { + //console.log("Using version info from cache.") + latestVersion = cachedVersion; + releaseUrl = cachedUrl; + } + + const comparison = compareVersions(currentVersion, latestVersion); + if (comparison === 0) { + //console.log("You are using the latest version."); + } else if (comparison < 0) { + //console.log("A new version is available: " + latestVersion); + + addNewVersionLink(releaseUrl,latestVersion); + } else { + //console.log("You are using a newer version."); + } + + } catch (error) { + console.error('Error fetching the latest release:', error); + } + } + function compareVersions(version1, version2) { + + const cleanVersion1 = version1.replace(/^v/, ''); + const cleanVersion2 = version2.replace(/^v/, ''); + + + const parts1 = cleanVersion1.split('.'); + const parts2 = cleanVersion2.split('.'); + + + for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { + const part1 = parts1[i] || '0'; + const part2 = parts2[i] || '0'; + + + const comparison = part1.localeCompare(part2, undefined, { numeric: true }); + + if (comparison !== 0) { + return comparison; + } + } + return 0; + } + function localizeSettings(win) { //win.webContents.toggleDevTools(); win.webContents.executeJavaScript(`get_all_ids();`); @@ -437,6 +604,21 @@ Icon=talk-electron`; }); } + // dirty function to apply unread badge to dock icon on Mac with 1s timeout + function addBadgeMac () { + //console.log(app.dock.getBadge()); + //setTimeout (function() { + // force dockIcon! + app.dock.setIcon(dockIcon); + if (unread!=0) { + app.dock.setBadge(''); + app.dock.setBadge(unread.toString()); + } else { + app.dock.setBadge(''); + } + //}, 1000); + } + function setSettings(message,win) { try { if (JSON.parse(message).action == 'save_settings') { @@ -523,7 +705,7 @@ Icon=talk-electron`; icon:icon, title:i18n.__('preferences'), width: 500, - height: 350, + height: 400, resizable:false, parent: win }) @@ -531,6 +713,14 @@ Icon=talk-electron`; win_settings.loadFile('settings.html'); win_settings.setMenu(null); + // override fonts to Arial to fix any app startup errors + win_settings.webContents.on('did-finish-load', () => { + win_settings.webContents.insertCSS(` + * { + font-family: 'Arial', sans-serif !important; + } + `); + }); // save app name title win_settings.on('page-title-updated', function(e) { @@ -586,6 +776,15 @@ Icon=talk-electron`; win_popup.loadURL(theUrl); win_popup.setMenu(null); + // override fonts to Arial to fix any app startup errors + win_popup.webContents.on('did-finish-load', () => { + win_popup.webContents.insertCSS(` + * { + font-family: 'Arial', sans-serif !important; + } + `); + }); + //block_gui_loading(false); // save app name title @@ -680,6 +879,7 @@ Icon=talk-electron`; var linear = 0 // for black color } var newImage = await sharp(icon.toPNG()).greyscale().linear(linear, 0).png({colors:2}).toBuffer(); + return nativeImage.createFromBuffer(newImage); } @@ -690,8 +890,8 @@ Icon=talk-electron`; // process icon for macos to black and white colors if (isMac) { icon = await bw_icon_process(icon) - } - + } + // var newImage = await sharp(Buffer.from(badge)).toBuffer(); @@ -760,7 +960,7 @@ Icon=talk-electron`; // set mac dock icon if (isMac) { //app.dock.setIcon(icon); - app.dock.setBadge(''); + addBadgeMac(); icon_bw = await bw_icon_process(icon); trayIcon = icon_bw.resize({width:16}); } else { @@ -780,18 +980,22 @@ Icon=talk-electron`; // set mac dock icon if (isMac) { //app.dock.setIcon(icon_notification); - app.dock.setBadge(unread.toString()); + addBadgeMac(); } //is_notification = true; if (store.get('show_on_new_message')) { - // check if win is in not hidden - if (!win.isVisible()) { - win.show(); - if (isMac) app.dock.show(); + if (unread_prev != unread) { + // check if win is in not hidden + if (!win.isVisible()) { + win.show(); + if (isMac) app.dock.show(); + } } } if ((!removed)&&(!win.isFocused())) { - win.flashFrame(true); + if (unread_prev != unread) { + win.flashFrame(true); + } } } } @@ -873,15 +1077,17 @@ Icon=talk-electron`; center: true, show: store.get('start_hidden') ? !JSON.parse(store.get('start_hidden')) : true, resizable: true, + minimizable: (isMac) ? false : true, minWidth: 512, // temporary restrict min window width by 512px, // see issues https://github.com/nextcloud/spreed/issues/12236 // https://github.com/nextcloud/spreed/issues/11454 - icon:icon, + //icon:icon, useContentSize: true, webPreferences: { enableRemoteModule: true, backgroundThrottling: false, //preload: path.join(__dirname, 'preload.js'), + contextIsolation: true, nodeIntegration: true, } }); @@ -988,20 +1194,17 @@ Icon=talk-electron`; win.on('show', function () { win.setBounds(store.get('bounds')); - if (isMac) app.dock.setIcon(icon); + //if (isMac) app.dock.setIcon(dockIcon); //if (is_notification) { if (unread != 0) { createBadge(unread,"taskbar"); //win.setOverlayIcon(icon_notification, 'Есть непрочитанные уведомления'); if (isMac) { - // remove badge prior to set new badge! - app.dock.setBadge(''); - //console.log(unread) - app.dock.setBadge(unread.toString()); + addBadgeMac(); } } else { win.setOverlayIcon(null, ''); - if (isMac) app.dock.setBadge(''); + if (isMac) addBadgeMac(); } }) @@ -1018,6 +1221,7 @@ Icon=talk-electron`; const buffer = await response.arrayBuffer(); const nodebuffer = Buffer.from(buffer); icon = nativeImage.createFromBuffer(nodebuffer) + dockIcon = icon // apply theme to the tray icon - don't apply @@ -1026,7 +1230,8 @@ Icon=talk-electron`; if (isMac) { icon_bw = await bw_icon_process(icon); trayIcon = icon_bw.resize({width:16}); - app.dock.setIcon(icon); + //app.dock.setIcon(dockIcon); + addBadgeMac(); } else { trayIcon = icon/*.resize({width:16});*/ } @@ -1046,6 +1251,9 @@ Icon=talk-electron`; //block_gui_loading(true); win.loadURL(url); + let activity_check_interval = 5; + + setInterval(function () { checkInactivity(activity_check_interval) }, activity_check_interval*1000); preventUnsupportedBrowser(win); @@ -1070,6 +1278,13 @@ Icon=talk-electron`; // check cloud win.webContents.on('did-finish-load', function(e) { + // override fonts to Arial to fix any app startup errors + win.webContents.insertCSS(` + * { + font-family: 'Arial', sans-serif !important; + } + `); + /*if (!store.get('start_hidden')) { win.show() }*/ @@ -1119,6 +1334,7 @@ Icon=talk-electron`; })*/ win.webContents.on('console-message', (event, level, message, line, sourceId) => { + try { //console.log(JSON.parse(message)) // get current nextcloud lang @@ -1131,9 +1347,19 @@ Icon=talk-electron`; if (JSON.parse(message).action.unread || (JSON.parse(message).action.unread === 0)) { //console.log(JSON.parse(message).action.unread) - unread = JSON.parse(message).action.unread + + if (unread_prev == unread) { + unread = JSON.parse(message).action.unread + } else { + if (unread!==false){ + unread_prev = unread; + } + //unread = JSON.parse(message).action.unread + } + removed = JSON.parse(message).action.removed UnreadTray(unread,removed); + unread_prev = unread // update title with unread on load if (unread != 0) { // set linux taskbar image same as tray @@ -1150,6 +1376,7 @@ Icon=talk-electron`; } //block_gui_loading(false); } + if (JSON.parse(message).action == 'not_alive') { /*if (!gui_blocked) { block_gui_loading(true);*/ @@ -1185,6 +1412,8 @@ Icon=talk-electron`; // dirty but it works if (!win.isVisible()) { win.show(); + if (isMac) app.dock.show(); + } //win.webContents.executeJavaScript('window.location.replace("/apps/spreed")') } @@ -1281,12 +1510,15 @@ Icon=talk-electron`; mainMenuTemplate[2].submenu[1].label = i18n.__("open_devtools"); MainMenu = Menu.buildFromTemplate(mainMenuTemplate); Menu.setApplicationMenu(MainMenu); + checkNewVersion(app.getVersion()); }) win.webContents.on('devtools-opened', () => { + checkNewVersion(app.getVersion()); mainMenuTemplate[2].submenu[1].label = i18n.__("close_devtools"); MainMenu = Menu.buildFromTemplate(mainMenuTemplate); Menu.setApplicationMenu(MainMenu); + checkNewVersion(app.getVersion()); }) // Open the DevTools. @@ -1321,7 +1553,7 @@ Icon=talk-electron`; //trayIcon.setTemplateImage(true); // set mac dock icon if (isMac) { - app.dock.setIcon(icon); + app.dock.setIcon(dockIcon); appIcon = new Tray(icon_bw) } else { appIcon = new Tray(trayIcon) @@ -1355,7 +1587,10 @@ Icon=talk-electron`; app.on('activate', function () { - if (isMac) app.dock.setIcon(icon); + if (isMac) { + //app.dock.setIcon(dockIcon); + addBadgeMac(); + } // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. //if (win.getAllWindows().length === 0) createWindow() @@ -1425,6 +1660,8 @@ Icon=talk-electron`; .catch((err) => { console.log(err) dialog.showErrorBox(i18n.__('error'), i18n.__("more")+JSON.stringify(err)); + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); }); } @@ -1432,6 +1669,16 @@ Icon=talk-electron`; } + function openNotificationsSettings() { + exec('open x-apple.systempreferences:com.apple.preference.notifications', (error) => { + if (error) { + console.error('Error while opeing notification settings:', error); + } else { + console.log('Notification settings are opened for macOS.'); + } + }); + } + // set server_url prompt function setServerUrl (server_url) { prompted = true; @@ -1451,6 +1698,8 @@ Icon=talk-electron`; }, win) .then((input) => { if(input === null) { + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); } else { let address = input @@ -1466,6 +1715,8 @@ Icon=talk-electron`; .catch((err) => { console.log(err) dialog.showErrorBox(i18n.__('error'), i18n.__("more")+JSON.stringify(err)); + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); }); } @@ -1484,7 +1735,7 @@ Icon=talk-electron`; } app.whenReady().then((event) => { - + //app.on('ready', async () => { console.log('PID =', process.pid); if (url == "") { @@ -1503,6 +1754,8 @@ Icon=talk-electron`; ShutdownHandler.on('shutdown', () => { console.log('Shutdown/logout is detected! Exiting app!'); ShutdownHandler.releaseShutdown(); + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); }) } @@ -1515,6 +1768,7 @@ Icon=talk-electron`; // for applications and their menu bar to stay active until the user quits // explicitly with Cmd + Q. app.on('window-all-closed', function () { + // 08.06.2024 due to bug in case of new config recreation //if (!isMac) app.quit() }) @@ -1535,6 +1789,8 @@ Icon=talk-electron`; } catch (err) { console.log(err); + store.delete('latestVersion'); + store.delete('releaseUrl'); app.exit(0); } diff --git a/nextcloud_check.js b/nextcloud_check.js index 6c3a69d..ae6e743 100644 --- a/nextcloud_check.js +++ b/nextcloud_check.js @@ -84,6 +84,7 @@ function checkURL(auto_login){ //window.location.replace("/apps/spreed") } } else { + // to force show app window if not logged in // 5s timeout to pass SSO procedure if (!(auto_login)) { @@ -92,6 +93,8 @@ function checkURL(auto_login){ $("#alternative-logins > a").hide(); } setTimeout(function() { + // check localStorage to drop unread counter + recalc_counters_summary(true); console.log(JSON.stringify({action: "force_show_app_win"})); }, 5000); } else { diff --git a/package.json b/package.json index 1b8b54d..c0233b9 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ ], "icon": "icon.png", "main": "./main.js", - "version": "0.2.8-alpha", + "version": "0.2.9-alpha", "author": "drlight17", "build": { "appId": "com.electron.talk-electron", @@ -80,6 +80,7 @@ "dependencies": { "@electron/packager": "latest", "@paymoapp/electron-shutdown-handler": "latest", + "desktop-idle": "^1.3.0", "electron-fetch": "^1.9.1", "electron-prompt": "latest", "electron-store": "^8.2.0", @@ -88,6 +89,7 @@ "devDependencies": { "@paymoapp/electron-shutdown-handler": "latest", "electron": "^22.3.27", - "electron-builder": "^24.13.3" + "electron-builder": "^24.13.3", + "electron-rebuild": "^3.2.9" } } diff --git a/package.json.linux b/package.json.linux index 05404f3..00fafab 100644 --- a/package.json.linux +++ b/package.json.linux @@ -11,7 +11,7 @@ ], "icon": "icon.png", "main": "./main.js", - "version": "0.2.8-alpha", + "version": "0.2.9-alpha", "author": "Yuri Samoilov ", "homepage": "https://github.com/drlight17/talk-electron", "build": { @@ -65,14 +65,16 @@ "dependencies": { "@electron/packager": "latest", "@paymoapp/electron-shutdown-handler": "latest", - "electron-prompt": "latest", + "desktop-idle": "^1.3.0", "electron-fetch": "^1.9.1", + "electron-prompt": "latest", "electron-store": "^8.2.0", "sharp": "^0.32" }, "devDependencies": { "@paymoapp/electron-shutdown-handler": "latest", "electron": "^22.3.27", - "electron-builder": "^24.13.3" + "electron-builder": "^24.13.3", + "electron-rebuild": "^3.2.9" } } diff --git a/settings.html b/settings.html index 421d983..c0d3ff2 100644 --- a/settings.html +++ b/settings.html @@ -41,6 +41,10 @@ +
+

diff --git a/settings.js b/settings.js index 4b5c0a0..09548eb 100644 --- a/settings.js +++ b/settings.js @@ -81,6 +81,12 @@ function loadSettings(settings,locales) { } else { document.getElementById('start_hidden').checked = false; } + + /*if (settings.allow_multiple !== undefined) { + document.getElementById('allow_multiple').checked = settings.allow_multiple; + } else { + document.getElementById('allow_multiple').checked = false; + }*/ } function saveSettings() { diff --git a/translations/en.json b/translations/en.json index 241a5cb..5f4e522 100644 --- a/translations/en.json +++ b/translations/en.json @@ -22,6 +22,7 @@ "allow_domain": "Allow SSO from domains (* for any):", "auto_login": "Try to login automatically (if SSO is configured)", "run_at_startup": "Autorun app during system startup", + "allow_multiple": "Allow multiple app instances with own confirations", "use_server_icon": "Use server logo icon", "show_on_new_message": "Show app on new message receive", "always_on_top": "App always on top", @@ -49,6 +50,7 @@ "copy": "Copy", "cut": "Cut", "select_all": "Select all", + "new_version": "New version available: ", "paste": "Paste", "about": "About", "user_settings_link": "User settings", diff --git a/translations/ru.json b/translations/ru.json index ac17cd2..6773be0 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -21,6 +21,7 @@ "allow_domain_title": "Несколько значений через запятую, * - wildcard (может обозначать любой поддомен)", "allow_domain": "Разрешить SSO с доменов (* для всех):", "auto_login": "Попробовать войти автоматически (для настроенного SSO)", + "allow_multiple": "Разрешить запуск нескольких процессов приложения с различной конфигурацией", "run_at_startup": "Автозапуск при входе пользователя", "use_server_icon": "Использовать логотип сервера", "show_on_new_message": "Показывать окно чата при получении сообщения", @@ -49,6 +50,7 @@ "copy": "Скопировать", "cut": "Вырезать", "select_all": "Выбрать всё", + "new_version": "Доступна новая версия: ", "paste": "Вставить", "about": "О программе", "user_settings_link": "Настройки пользователя", diff --git a/unread_observer.js b/unread_observer.js index 3c73b70..90e53c7 100644 --- a/unread_observer.js +++ b/unread_observer.js @@ -18,6 +18,7 @@ function getItemsByPartialKey(partialKey) { } function recalc_counters_summary (removed) { + let totalUnreadMessages = 0; try { // Шаг 1: Извлечение данных из localStorage @@ -59,14 +60,19 @@ function recalc_counters_summary (removed) { // Шаг 5: Вывод результата //console.log(`Общее количество непрочитанных сообщений: ${totalUnreadMessages}`); + if (removed) { + localStorage.removeItem(found_key); + } console.log(JSON.stringify({'action': {'unread': totalUnreadMessages, 'removed': removed}})); return found_key; } catch (error) { + console.log(JSON.stringify({'action': {'unread': 0, 'removed': removed}})); //console.error('Произошла ошибка при обработке "_cachedConversations":', error); } } + // Сохраняем оригинальные методы localStorage const originalSetItem = localStorage.setItem; const originalRemoveItem = localStorage.removeItem;