您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Manage Deepseek chats using folders. 使用文件夹管理Deepseek会话。
// ==UserScript== // @name Deepseek会话文件夹 // @namespace http://tampermonkey.net/ // @version 1.2 // @description Manage Deepseek chats using folders. 使用文件夹管理Deepseek会话。 // @author paradox661 // @match https://chat.deepseek.com/* // @icon https://www.deepseek.com/favicon.ico // @grant GM_setValue // @grant GM_getValue // @grant GM_listValues // @license MIT // ==/UserScript== (function() { 'use strict'; console.log('Start DSChatFolders.'); const FOLDERS = JSON.parse(GM_getValue('folders', '{}')); const CHATS = JSON.parse(GM_getValue('chats', '{}')); const FOLDER_STATE = JSON.parse(GM_getValue('folder_state', '{}')); let FOLDER_SEQ = JSON.parse(GM_getValue('folder_seq', '[]')); // 等待cond()为true时运行func() function waitFor(cond, func, timeout=2000) { const observer = new MutationObserver(function() { if (cond()) { observer.disconnect(); func(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => observer.disconnect(), timeout); } // 添加需要的CSS类 function addCSSClass() { const iconLink = document.createElement('link'); iconLink.rel = 'stylesheet'; iconLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css'; document.head.appendChild(iconLink); const style = document.createElement('style'); style.textContent = ` .no-after-content::after { content: "" !important; } .no-scrollbar::-webkit-scrollbar { display: none; } .folder-btn { border-radius: 12px; margin: 2px; } .folder { display: flex; align-items: center; justify-content: flex-start; border-radius: 12px; } .folder::before { content: "\\f07b"; font-family: "Font Awesome 6 Free"; font-weight: 900; color: #6770FE; display: inline-block; margin-right: 5px; } .folder::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0); pointer-events: none; transition: background-color 0.2s; border-radius: 12px; } .folder.active::after { background-color: rgba(0,0,0,0.08); } .chat { display: none; align-items: center; justify-content: flex-start; } .chat::before { content: ""; display: inline-block; margin-right: 10px; } .drop-top { position: relative; } .drop-top::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: blue; } .drop-bottom { position: relative; } .drop-bottom::after { content: ""; position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background: blue; } `; document.head.appendChild(style); } // 工具函数 let currentDragId = null; function existChatAnchors() { // 在某个会话页面刷新可能先加载一个,再加载其他。 // 如果length > 0,可能后续逻辑下其他会话还没有加载。 return getOriginalAnchors().length > 1; } function getChatId(chatAnchor) { const href = chatAnchor.getAttribute('href'); if (href) { const match = href.match(/^\/a\/chat\/s\/([a-f0-9-]+)$/); return match[1]; } } function outputChatAnchors() { const chatAnchors = getOriginalAnchors(); console.log(`总共找到 ${chatAnchors.length} 个会话`); if (chatAnchors.length > 0) { console.group('DeepSeek 会话'); chatAnchors.forEach(chatAnchor => { console.log(chatAnchor); console.log(getChatId(chatAnchor)); }); console.groupEnd(); } } function genRandomId() { // 生成16位定长id return (Date.now().toString(36).padStart(10, "0") + Math.random().toString(36).substring(2, 8)).slice(0, 16); } function isChatId(id) { return id.length == 36 || id.length == 58; } function isFolderId(id) { return id.length == 16; } function insertAfter(newNode, referenceNode) { const parent = referenceNode.parentNode; if (referenceNode.nextSibling) { parent.insertBefore(newNode, referenceNode.nextSibling); } else { parent.appendChild(newNode); } } function extractIdFromUrl(url) { try { const u = new URL(url); const match = u.pathname.match(/\/a\/chat\/s\/([a-f0-9-]+)/i); return match ? match[1] : null; } catch (e) { console.error("Invalid URL:", e); return null; } } // 获取DOM元素 function getScrollArea() { return document.querySelector('.ds-scroll-area'); } function getOriginalAnchors() { return getScrollArea().querySelectorAll('a[href^="/a/chat/s/"]'); } function getMenuBtn() { return getScrollArea().querySelector('a[href^="/a/chat/s/"]').children[1]; } // 获取魔法数字Class function getBtnClass() { return getScrollArea().parentNode.children[1].classList[0]; } function getAnchorClass() { return getOriginalAnchors()[0].classList[0]; } function getAnchorSelectedClass() { return 'b64fb9ae'; } // 添加DOM元素 function addBtnArea() { if (document.getElementById('btn-area')) { return; } const btnArea = document.createElement('div'); btnArea.id = 'btn-area'; btnArea.style.cssText = ` display: flex; margin-top: 6px; margin-bottom: 6px; `; return btnArea; } function addNewFolderBtn() { if (document.getElementById('new-folder-btn')) { return; } const newFolderBtn = document.createElement('button'); newFolderBtn.id = 'new-folder-btn'; newFolderBtn.textContent = 'New Folder'; newFolderBtn.classList.add(getBtnClass(), 'folder-btn', 'no-after-content'); newFolderBtn.style.flex = 4; newFolderBtn.addEventListener('click', () => { const folderArea = document.getElementById('folder-area'); const folderName = prompt('文件夹名称:', ''); if (folderName !== null) { const folderId = genRandomId(); FOLDERS[folderId] = folderName; FOLDER_STATE[folderId] = false; FOLDER_SEQ.push(folderId); GM_setValue('folders', JSON.stringify(FOLDERS)); GM_setValue('folder_state', JSON.stringify(FOLDER_STATE)); GM_setValue('folder_seq', JSON.stringify(FOLDER_SEQ)); const newFolder = addNewFolder(folderName, folderId); folderArea.appendChild(newFolder); } }); return newFolderBtn; } function addImportFoldersBtn() { if (document.getElementById('import-folders-btn')) { return; } const importFoldersBtn = document.createElement('button'); importFoldersBtn.id = 'import-folders-btn'; const icon = document.createElement('i'); icon.className = "fa-solid fa-arrow-turn-down"; importFoldersBtn.appendChild(icon); importFoldersBtn.classList.add(getBtnClass(), 'folder-btn', 'no-after-content'); importFoldersBtn.style.flex = 1; importFoldersBtn.style.color = '#6770FE'; //importFoldersBtn.addEventListener('click', () => { // GM_setValue('folders', '{}'); // GM_setValue('chats', '{}'); // GM_setValue('folder_state', '{}'); // GM_setValue('folder_seq', '[]'); //}); importFoldersBtn.addEventListener('click', () => { const input = document.createElement('input'); input.type = 'file'; input.accept = '.txt,.json'; input.onchange = async () => { const file = input.files && input.files[0]; if (!file) return; const text = await file.text(); const obj = JSON.parse(text); for (const k of Object.keys(obj)) { GM_setValue(k, obj[k]); } alert('导入完成。'); location.reload(); }; input.click(); }); return importFoldersBtn; } function addExportFoldersBtn() { if (document.getElementById('export-folders-btn')) { return; } const exportFoldersBtn = document.createElement('button'); exportFoldersBtn.id = 'export-folders-btn'; const icon = document.createElement('i'); icon.className = "fa-solid fa-arrow-turn-up"; exportFoldersBtn.appendChild(icon); exportFoldersBtn.classList.add(getBtnClass(), 'folder-btn', 'no-after-content'); exportFoldersBtn.style.flex = 1; exportFoldersBtn.style.color = '#6770FE'; //exportFoldersBtn.addEventListener('click', () => { // console.log(JSON.parse(GM_getValue('folders', '{}'))); // console.log(JSON.parse(GM_getValue('chats', '{}'))); // console.log(JSON.parse(GM_getValue('folder_state', '{}'))); // console.log(JSON.parse(GM_getValue('folder_seq', '[]'))); //}); exportFoldersBtn.addEventListener('click', () => { const keys = GM_listValues(); const data = {}; for (const k of keys){ data[k] = GM_getValue(k); } const text = JSON.stringify(data, null, 2); const blob = new Blob([text], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `deepseek-folder_${new Date().toISOString().replace(/[:.]/g, '-')}.txt`; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); }); return exportFoldersBtn; } function addFolderArea() { if (document.getElementById('folder-area')) { return; } const folderArea = document.createElement('div'); folderArea.id = 'folder-area'; folderArea.classList.add('no-scrollbar'); folderArea.style.cssText = ` height: 50%; overflow-y: auto; overflow-x: hidden; `; return folderArea; } function addNewFolder(folderName, folderId) { const newFolder = document.createElement('div'); newFolder.id = folderId; const folderHeader = document.createElement('div'); folderHeader.classList.add(getAnchorClass(), 'folder'); const folderHeaderText = document.createElement('div'); folderHeaderText.style.cssText = ` white-space: nowrap; text-overflow: ellipsis; overflow: hidden; `; folderHeaderText.textContent = folderName; folderHeader.appendChild(folderHeaderText); const folderMenuBtn = getMenuBtn().cloneNode(true); folderMenuBtn.addEventListener('click', (e) => { e.stopPropagation(); addMenu(folderMenuBtn); }); folderHeader.appendChild(folderMenuBtn); folderHeader.addEventListener('click', () => { folderHeader.classList.toggle('active'); FOLDER_STATE[folderId] = folderHeader.classList.contains('active'); GM_setValue('folder_state', JSON.stringify(FOLDER_STATE)); Array.from(newFolder.children).forEach(child => { if (child !== folderHeader) { child.style.display = (child.style.display === 'none' || child.style.display === '') ? 'flex' : 'none'; } }); }); folderHeader.draggable = true; folderHeader.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', e.currentTarget.parentNode.id); currentDragId = e.currentTarget.parentNode.id; }); folderHeader.addEventListener('dragover', (e) => { e.preventDefault(); if (isFolderId(currentDragId) && currentDragId != e.currentTarget.parentNode.id) { const rect = e.currentTarget.getBoundingClientRect(); const isBottom = (e.clientY - rect.top) > (rect.height / 2); e.currentTarget.parentNode.classList.remove('drop-top', 'drop-bottom'); e.currentTarget.parentNode.classList.add(isBottom ? 'drop-bottom' : 'drop-top'); } }); folderHeader.addEventListener('dragleave', (e) => { e.preventDefault(); if (isFolderId(currentDragId) && currentDragId != e.currentTarget.parentNode.id) { e.currentTarget.parentNode.classList.remove('drop-top', 'drop-bottom'); } }); folderHeader.addEventListener('drop', (e) => { e.preventDefault(); if (isFolderId(currentDragId) && currentDragId != e.currentTarget.parentNode.id) { const rect = e.currentTarget.getBoundingClientRect(); const isBottom = (e.clientY - rect.top) > (rect.height / 2); e.currentTarget.parentNode.classList.remove('drop-top', 'drop-bottom'); const originalFolderId = e.dataTransfer.getData('text/plain'); const targetFolderId = e.currentTarget.parentNode.id; const newFolderSeq = []; FOLDER_SEQ.forEach(folderId => { if (folderId == originalFolderId) { } else if (folderId == targetFolderId) { if (isBottom) { newFolderSeq.push(targetFolderId); newFolderSeq.push(originalFolderId); } else { newFolderSeq.push(originalFolderId); newFolderSeq.push(targetFolderId); } } else { newFolderSeq.push(folderId); } }); FOLDER_SEQ = newFolderSeq; GM_setValue('folder_seq', JSON.stringify(FOLDER_SEQ)); const originalFolder = document.getElementById(originalFolderId); const targetFolder = document.getElementById(targetFolderId); originalFolder.remove(); if (isBottom) { insertAfter(originalFolder, targetFolder); } else { targetFolder.parentNode.insertBefore(originalFolder, targetFolder); } } }); newFolder.appendChild(folderHeader); newFolder.addEventListener('dragover', (e) => { e.preventDefault(); if (isChatId(currentDragId)) { if (!currentDragId.endsWith('-copy') || currentDragId.slice(-21, -5) != folderId) { newFolder.style.border = '1.5px solid blue'; } } }); newFolder.addEventListener('dragleave', (e) => { e.preventDefault(); if (isChatId(currentDragId)) { if (!currentDragId.endsWith('-copy') || currentDragId.slice(-21, -5) != folderId) { newFolder.style.border = ''; } } }); newFolder.addEventListener('drop', (e) => { e.preventDefault(); if (isChatId(currentDragId)) { newFolder.style.border = ''; let chatId = e.dataTransfer.getData('text/plain'); if (chatId.endsWith('-copy')) { chatId = chatId.slice(0, -22); } let inFolder = false; Array.from(newFolder.children).forEach(child => { if (child.id == chatId + '-' + folderId + '-copy') { inFolder = true; } }); if (!inFolder) { if (chatId in CHATS) { CHATS[chatId].push(folderId); } else { CHATS[chatId] = [folderId]; } GM_setValue('chats', JSON.stringify(CHATS)); const chatAnchorCopy = addCopyedAnchor(chatId, folderId); chatAnchorCopy.style.display = folderHeader.classList.contains('active') ? 'flex' :'none'; newFolder.insertBefore(chatAnchorCopy, newFolder.children[1]); } } }); return newFolder; } function addMenu(folderMenuBtn) { document.querySelectorAll('.temp-menu').forEach(m => m.remove()); const menu = document.createElement('div'); menu.classList.add('temp-menu', 'ds-dropdown-menu', 'ds-elevated', 'ds-fade-in-zoom-in-enter', 'ds-fade-in-zoom-in-active'); menu.style.cssText = ` position: absolute; z-index: 9999; `; const rect = folderMenuBtn.getBoundingClientRect(); menu.style.left = (rect.left + window.scrollX + 20) + 'px'; menu.style.top = rect.bottom + window.scrollY + 'px'; document.body.appendChild(menu); const renameBtn = document.createElement('div'); renameBtn.classList.add('ds-dropdown-menu-option', 'ds-dropdown-menu-option--none'); renameBtn.addEventListener('click', () => { const folderHeader = folderMenuBtn.parentNode; const currentFolder = folderHeader.parentNode; const folderHeaderText = folderHeader.children[0]; const folderName = prompt('重命名文件夹:', FOLDERS[currentFolder.id]); if (folderName !== null) { const folderId = currentFolder.id; FOLDERS[folderId] = folderName; GM_setValue('folders', JSON.stringify(FOLDERS)); folderHeaderText.textContent = folderName; } menu.remove(); }); const renameIcon = document.createElement('i'); renameIcon.className = 'fa-solid fa-pen-to-square'; renameIcon.classList.add('ds-dropdown-menu-option__icon'); renameBtn.appendChild(renameIcon); const renameBtnText = document.createElement('div'); renameBtnText.classList.add('ds-dropdown-menu-option__label'); renameBtnText.textContent = 'Rename'; renameBtn.appendChild(renameBtnText); menu.appendChild(renameBtn); const deleteBtn = document.createElement('div'); deleteBtn.classList.add('ds-dropdown-menu-option', 'ds-dropdown-menu-option--error'); deleteBtn.addEventListener('click', () => { const folderHeader = folderMenuBtn.parentNode; const currentFolder = folderHeader.parentNode; let result = confirm('确定删除文件夹:' + FOLDERS[currentFolder.id]); if (result) { const folderId = currentFolder.id; for (let chatId in CHATS) { CHATS[chatId] = CHATS[chatId].filter(x => x !== folderId); } delete FOLDERS[folderId]; delete FOLDER_STATE[folderId]; FOLDER_SEQ = FOLDER_SEQ.filter(x => x != folderId); GM_setValue('chats', JSON.stringify(CHATS)); GM_setValue('folders', JSON.stringify(FOLDERS)); GM_setValue('folder_state', JSON.stringify(FOLDER_STATE)); GM_setValue('folder_seq', JSON.stringify(FOLDER_SEQ)); currentFolder.remove(); } menu.remove(); }); const deleteIcon = document.createElement('i'); deleteIcon.className = 'fa-solid fa-trash'; deleteIcon.classList.add('ds-dropdown-menu-option__icon'); deleteBtn.appendChild(deleteIcon); const deleteBtnText = document.createElement('div'); deleteBtnText.classList.add('ds-dropdown-menu-option__label'); deleteBtnText.textContent = 'Delete'; deleteBtnText.style.marginLeft = '2px'; deleteBtn.appendChild(deleteBtnText); menu.appendChild(deleteBtn); const removeMenu = (e) => { if (!menu.contains(e.target) && e.target !== folderMenuBtn) { menu.remove(); document.removeEventListener('click', removeMenu); } }; setTimeout(() => document.addEventListener('click', removeMenu), 0); return menu; } function addCopyedAnchor(chatId, folderId) { const chatAnchorCopy = document.getElementById(chatId).cloneNode(true); chatAnchorCopy.draggable = true; chatAnchorCopy.id = chatId + '-' + folderId + '-copy'; chatAnchorCopy.classList.add('chat'); chatAnchorCopy.children[1].remove(); chatAnchorCopy.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', e.target.id); currentDragId = e.target.id; }); chatAnchorCopy.addEventListener('click', (e) => { e.preventDefault(); document.getElementById(chatId).click(); }); return chatAnchorCopy; } // 页面初始化 function initUISettings() { const scrollArea = getScrollArea(); scrollArea.style.height = '40%'; const btnArea = addBtnArea(); scrollArea.parentNode.insertBefore(btnArea, scrollArea); const newFolderBtn = addNewFolderBtn(); btnArea.appendChild(newFolderBtn); const importFoldersBtn = addImportFoldersBtn(); btnArea.appendChild(importFoldersBtn); const exportFoldersBtn = addExportFoldersBtn(); btnArea.appendChild(exportFoldersBtn); const folderArea = addFolderArea(); scrollArea.parentNode.insertBefore(folderArea, scrollArea); const horizontalLine = document.createElement('div'); horizontalLine.style.cssText = ` height: 0.8px; background-color: #C0C0C0; width: 95%; margin: 0 auto; margin-top: 5px; `; scrollArea.parentNode.insertBefore(horizontalLine, scrollArea); scrollArea.addEventListener('dragover', (e) => { e.preventDefault(); if (isChatId(currentDragId) && currentDragId.endsWith('-copy')) { scrollArea.style.border = '1.5px solid blue'; } }); scrollArea.addEventListener('dragleave', (e) => { e.preventDefault(); if (isChatId(currentDragId) && currentDragId.endsWith('-copy')) { scrollArea.style.border = ''; } }); scrollArea.addEventListener('drop', (e) => { e.preventDefault(); if (isChatId(currentDragId)) { let chatId = e.dataTransfer.getData('text/plain'); if (chatId.endsWith('-copy')) { scrollArea.style.border = ''; document.getElementById(chatId).remove(); const folderId = chatId.slice(-21, -5); chatId = chatId.slice(0, -22); CHATS[chatId] = CHATS[chatId].filter(x => x != folderId); GM_setValue('chats', JSON.stringify(CHATS)); } } }); } function setOriginalAnchorsDraggable() { const chatAnchors = getOriginalAnchors(); chatAnchors.forEach(chatAnchor => { chatAnchor.draggable = true; chatAnchor.id = getChatId(chatAnchor); chatAnchor.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', e.target.id); currentDragId = e.target.id; }); }); } function initFoldersLoading() { // FOLDER_STATE、FOLDER_SEQ都与FOLDER保持一致。 const folderArea = document.getElementById('folder-area'); for (let folderId in FOLDERS) { if (!(folderId in FOLDER_STATE)) { FOLDER_STATE[folderId] = false; } } const removedFolderState = []; for (let folderId in FOLDER_STATE) { if (!(folderId in FOLDERS)) { removedFolderState.push(folderId); } } removedFolderState.forEach(folderId => delete FOLDER_STATE[folderId]); for (let folderId in FOLDERS) { if (!FOLDER_SEQ.includes(folderId)) { FOLDER_SEQ.push(folderId); } } FOLDER_SEQ = [...new Set(FOLDER_SEQ)]; const removedFolderSeq = []; FOLDER_SEQ.forEach(folderId => { if (folderId in FOLDERS) { const newFolder = addNewFolder(FOLDERS[folderId], folderId); const folderHeader = newFolder.children[0]; folderHeader.classList.toggle('active', FOLDER_STATE[folderId]); folderArea.appendChild(newFolder); } else { removedFolderSeq.push(folderId); } }); removedFolderSeq.forEach(folderId => { FOLDER_SEQ = FOLDER_SEQ.filter(x => x != folderId); }); GM_setValue('folder_state', JSON.stringify(FOLDER_STATE)); GM_setValue('folder_seq', JSON.stringify(FOLDER_SEQ)); } function initAnchorsLoading() { const removedChatIds = []; for (let chatId in CHATS) { if (!document.getElementById(chatId)) { removedChatIds.push(chatId); } } const chatAnchors = getOriginalAnchors(); chatAnchors.forEach(chatAnchor => { const chatId = getChatId(chatAnchor); if (chatId in CHATS) { const belongFolders = CHATS[chatId]; const activeFolders = []; belongFolders.forEach(folderId => { if (document.getElementById(folderId)) { activeFolders.push(folderId); const belongFolder = document.getElementById(folderId); const folderHeader = belongFolder.children[0]; let inFolder = false; Array.from(belongFolder.children).forEach(child => { if (child.id == chatId + '-' + folderId + '-copy') { inFolder = true; } }); if (!inFolder) { const chatAnchorCopy = addCopyedAnchor(chatId, folderId); chatAnchorCopy.style.display = folderHeader.classList.contains('active') ? 'flex' :'none'; belongFolder.appendChild(chatAnchorCopy); } } }); CHATS[chatId] = activeFolders; } }); removedChatIds.forEach(chatId => delete CHATS[chatId]); GM_setValue('chats', JSON.stringify(CHATS)); } function observeScrollArea () { const scrollArea = getScrollArea(); const observer = new MutationObserver((mutationList) => { for (const mutation of mutationList) { if (mutation.type !== "childList") continue; /* eslint-disable no-loop-func */ mutation.addedNodes.forEach((node) => { if (node.nodeType !== 1) return; let chatAnchor = null; if (node.tagName === "A") { chatAnchor = node; } else { chatAnchor = node.querySelector("a"); } if (chatAnchor) { chatAnchor.draggable = true; chatAnchor.id = getChatId(chatAnchor); chatAnchor.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', e.target.id); currentDragId = e.target.id; }); } }); mutation.removedNodes.forEach((node) => { if (node.nodeType !== 1) return; let chatAnchor = null; if (node.tagName === "A") { chatAnchor = node; } else { chatAnchor = node.querySelector("a"); } if (chatAnchor) { const chatId = getChatId(chatAnchor); delete CHATS[chatId]; GM_setValue('chats', JSON.stringify(CHATS)); for (let folderId in FOLDERS) { if (document.getElementById(chatId + '-' + folderId + '-copy')) { document.getElementById(chatId + '-' + folderId + '-copy').remove(); } } } }); } }); observer.observe(scrollArea, { childList: true, subtree: true }); } function listenDomain() { function updateSelectedState() { const chatId = extractIdFromUrl(location.href); const copyedAnchors = document.getElementById('folder-area').querySelectorAll('a[href^="/a/chat/s/"]'); copyedAnchors.forEach(anchor => { anchor.classList.remove(getAnchorSelectedClass()); }); if (chatId) { const selectedCopyedAnchors = document.getElementById('folder-area').querySelectorAll(`a[href="/a/chat/s/${chatId}"]`); selectedCopyedAnchors.forEach(anchor => { anchor.classList.add(getAnchorSelectedClass()); }); } } window.addEventListener("popstate", updateSelectedState); window.addEventListener("hashchange", updateSelectedState); ["pushState", "replaceState"].forEach(fn => { const orig = history[fn]; history[fn] = function (...args) { const ret = orig.apply(this, args); updateSelectedState(); return ret; }; }); updateSelectedState(); } function main() { addCSSClass(); waitFor(existChatAnchors, () => { initUISettings(); setOriginalAnchorsDraggable(); initFoldersLoading(); initAnchorsLoading(); observeScrollArea(); listenDomain(); }); } main(); })();