browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.url) { groupTabs(tabId); } }); const colors = [ "blue", "cyan", "grey", "green", "orange", "pink", "purple", "red", "yellow", ]; async function groupTabs(tabId) { const tabs = await browser.tabs.query({ currentWindow: true }); const domainGroups = {}; const groupIds = []; for (let tab of tabs) { if (!groupIds.includes(tab.groupId)) { groupIds.push(tab.groupId); } const hostname = new URL(tab.url).hostname; const parts = hostname.split("."); let domain = parts[0]; if (parts.length > 1) { parts.pop(); if (parts[0] == "www") { parts.shift(); } domain = toTitleCase(parts.join(" ")); } if (domain == "") { domain = "Browser"; } if (tab.groupId == -1 || tab.id == tabId || tab.active) { if (!domainGroups[domain]) { domainGroups[domain] = []; } domainGroups[domain].push(tab.id); } } for (const groupId in groupIds) { if (groupIds[groupId] != -1) { let tabGroup = await browser.tabGroups.get(groupIds[groupId]); if (tabGroup.title in domainGroups) { const updatedGroup = await browser.tabs.group({ tabIds: domainGroups[tabGroup.title], groupId: tabGroup.id, }); delete domainGroups[tabGroup.title]; } } } for (const domain in domainGroups) { const groupId = await browser.tabs.group({ tabIds: domainGroups[domain], }); await browser.tabGroups.update(groupId, { title: domain, color: colors[groupId % colors.length], }); } } function toTitleCase(str) { str = str.replace(/[-_]/g, " "); return str.replace( /\w(\S)*/g, (text) => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase(), ); }