const seenMessages = new Set(); const messageContents = new Map(); const seenDataAnnounceMessages = new Set(); let awaitingTimes = []; let messages = []; let startTime = 0; async function init() { const data = await chrome.storage.local.get(['startTime', 'messages']); if (data?.startTime > 0) { startTime = data.startTime; } if (data.messages) { messages = data.messages; } checkNewMessages(); update(); } function dis(n) { if (n < 10) return "0" + n; return n.toString(); } function displayTime(rawTime) { if (rawTime < 3600) return `${dis(Math.floor((rawTime % 3600) / 60))}:${dis(rawTime % 60)}`; return `${Math.floor(rawTime / 3600)}:${dis(Math.floor((rawTime % 3600) / 60))}:${dis(rawTime % 60)}`; } function updateMessageContent(content, el, map) { if (el.innerHTML != content) el.innerHTML = content; } function updateMessageContents() { messageContents.forEach(updateMessageContent); } function checkNewMessages() { // Check announce messages and log their appearing times. const announceMessageElements = document.querySelectorAll("div[data-announce-message]"); for (let e of announceMessageElements) { if (seenDataAnnounceMessages.has(e)) continue; seenDataAnnounceMessages.add(e); const completionTime = Math.floor((Date.now() - startTime) / 1000); awaitingTimes.push(completionTime); } // Check in-call messages. const messageElements = document.querySelectorAll("div[data-message-id]"); let newElements = false; for (let messageNode of messageElements) { const el = messageNode.firstChild.firstChild.firstChild.firstChild; if (seenMessages.has(el)) continue; newElements = true; seenMessages.add(el); let completionTime = Math.floor((Date.now() - startTime) / 1000); // If awaiting times are available, use them first (i.e. the messages section just got opened). if (awaitingTimes.length) completionTime = awaitingTimes.shift(); const rootNode = messageNode.parentNode.parentNode; const name = rootNode.firstChild.firstChild.innerHTML; const dTime = displayTime(completionTime); if (startTime > 0) { messages.push({completionTime: completionTime, name: name, text: el.innerHTML, displayTime: dTime}); const messageContent = `(${dTime}) ${el.innerHTML}`; messageContents.set(el, messageContent); // Re-show all finishing times, as GMeet reset those each time a new message is written. setTimeout(updateMessageContents, 30); setTimeout(updateMessageContents, 60); setTimeout(updateMessageContents, 90); setTimeout(updateMessageContents, 120); setTimeout(updateMessageContents, 150); setTimeout(updateMessageContents, 180); } } if (newElements) { chrome.storage.local.set({ messages: messages }); } // If awaiting messages are still present, but the messages section is opened with no new messages, // delete all awaiting messages (that should never happen though, there was an error somewhere). if (messageElements.length && awaitingTimes.length) awaitingTimes = []; setTimeout(checkNewMessages, 100); } async function update() { const data = await chrome.storage.local.get(['startTime', 'endTime']); if (data?.startTime >= 0 && data.startTime != startTime) { startTime = data.startTime; messages = []; } setTimeout(update, 2000); } setTimeout(init, 20);