diff --git a/content.js b/content.js index b1fcd96..ff11ef5 100644 --- a/content.js +++ b/content.js @@ -150,19 +150,119 @@ function openChatById(chatId) { return deepLinkToChat(chatId); } -function extractChatAvatar(titleElement) { - const rowRoot = titleElement.closest('[role="listitem"], button, a, [role="button"]') || titleElement.parentElement; - if (!rowRoot) return ""; +function extractUrlFromBackgroundImage(backgroundImage) { + if (!backgroundImage || backgroundImage === "none") return ""; + const matched = backgroundImage.match(/url\(["']?(.*?)["']?\)/); + return matched?.[1] || ""; +} - const avatarImage = rowRoot.querySelector("img"); - if (avatarImage?.src) { - return avatarImage.src; +function getImageUrlFromElement(element) { + if (!element) return ""; + + if (element.tagName?.toLowerCase() === "img") { + return element.currentSrc || element.src || ""; } - const avatarCandidate = rowRoot.querySelector('[style*="background-image"]'); - const inlineStyle = avatarCandidate?.style?.backgroundImage || ""; - const matched = inlineStyle.match(/url\(["']?(.*?)["']?\)/); - return matched?.[1] || ""; + if (element.tagName?.toLowerCase() === "image") { + return element.getAttribute("href") || element.getAttribute("xlink:href") || ""; + } + + const attributeSrc = element.getAttribute?.("src"); + if (attributeSrc) { + return attributeSrc; + } + + const inlineBackground = extractUrlFromBackgroundImage(element.style?.backgroundImage || ""); + if (inlineBackground) { + return inlineBackground; + } + + try { + const computedBackground = extractUrlFromBackgroundImage(window.getComputedStyle(element).backgroundImage); + if (computedBackground) { + return computedBackground; + } + } catch (error) {} + + return ""; +} + +function findAvatarUrlInScope(scope) { + if (!scope || typeof scope.querySelectorAll !== "function") return ""; + + const directUrl = getImageUrlFromElement(scope); + if (directUrl) return directUrl; + + const candidates = scope.querySelectorAll([ + 'img', + 'image', + '[style*="background-image"]', + '[class*="avatar"]', + '[data-tid*="avatar"]', + '[id*="avatar"]' + ].join(",")); + + for (const candidate of candidates) { + const url = getImageUrlFromElement(candidate); + if (url) return url; + } + + return ""; +} + +function extractChatAvatarByRelativePath(titleElement, childLayer) { + let current = titleElement; + + for (let depth = 0; depth < 7; depth += 1) { + if (!current?.parentElement) return ""; + current = current.parentElement; + } + + let candidate = current.previousElementSibling; + if (!candidate) return ""; + + for (let depth = 0; depth < childLayer; depth += 1) { + if (!candidate?.children?.length) return ""; + candidate = candidate.children[0]; + } + + return getImageUrlFromElement(candidate); +} + +function extractChatAvatar(titleElement) { + let relativePathAvatar = extractChatAvatarByRelativePath(titleElement, 3); + if (relativePathAvatar) { + return relativePathAvatar; + } + relativePathAvatar = extractChatAvatarByRelativePath(titleElement, 4); + if (relativePathAvatar) { + return relativePathAvatar; + } + + const scopes = []; + const rowRoot = titleElement.closest('[role="listitem"], button, a, [role="button"]'); + + if (rowRoot) { + scopes.push(rowRoot); + } + + let current = titleElement; + for (let depth = 0; depth < 7 && current; depth += 1) { + scopes.push(current); + if (current.previousElementSibling) scopes.push(current.previousElementSibling); + if (current.nextElementSibling) scopes.push(current.nextElementSibling); + current = current.parentElement; + } + + const seen = new Set(); + for (const scope of scopes) { + if (!scope || seen.has(scope)) continue; + seen.add(scope); + const url = findAvatarUrlInScope(scope); + if (url) return url; + } + + return ""; } function scanVisibleChats() {