Created
April 12, 2023 15:20
-
-
Save xinzhi/b56e6f03bcf320818a1506399a10368a to your computer and use it in GitHub Desktop.
自动展开显示 Twitter 图片 ALT 文本的扩展脚本,推荐搭配 Arc 浏览器使用
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. 打开 Arc 浏览器访问 Twitter 网站; | |
// 2. 左侧面板右下角点击 New Boost - Inject - A specific website(确认应用范围是 twitter.com) | |
// 3. 请空默认代码,粘贴本页面代码即可。 | |
// 效果测试地址: https://twitter.com/ciguleva/status/1637233764656107520?s=20 | |
const tweetSelector = 'article[data-testid="tweet"]'; | |
const tweetTextSelector = 'div[data-testid="tweetText"]'; | |
const tweetPhotoSelector = 'div[data-testid^="tweetPhoto"]'; | |
const appendAltText = (tweet, altText) => { | |
const tweetTextElement = tweet.querySelector(tweetTextSelector); | |
const existingList = | |
tweetTextElement?.querySelector("ol") ?? | |
(() => { | |
const newList = document.createElement("ol"); | |
tweetTextElement.appendChild(newList); | |
return newList; | |
})(); | |
const altPromptElement = | |
tweetTextElement.querySelector(".alt-prompt") ?? | |
(() => { | |
const altPromptText = document.createTextNode("\n\nALTs: "); | |
const newAltPrompt = document.createElement("span"); | |
newAltPrompt.className = "alt-prompt"; | |
newAltPrompt.appendChild(altPromptText); | |
tweetTextElement.insertBefore(newAltPrompt, existingList); | |
return newAltPrompt; | |
})(); | |
const listItem = document.createElement("li"); | |
listItem.textContent = altText; | |
existingList.appendChild(listItem); | |
}; | |
const tweetContainsMedia = (tweet) => | |
tweet.querySelector(tweetPhotoSelector) !== null; | |
const processTweet = (tweet) => { | |
if (tweet.hasAttribute("data-processed") || !tweetContainsMedia(tweet)) { | |
return; | |
} | |
tweet.setAttribute("data-processed", "true"); | |
tweet.querySelectorAll(tweetPhotoSelector).forEach((photo) => { | |
const altText = photo.getAttribute("aria-label"); | |
if (altText && altText.length >= 10) { | |
appendAltText(tweet, altText); | |
} | |
}); | |
}; | |
const handleIntersection = (entries) => { | |
entries.forEach((entry) => { | |
if ( | |
entry.isIntersecting && | |
entry.target.matches(tweetSelector) && | |
!entry.target.hasAttribute("data-processed") && | |
tweetContainsMedia(entry.target) | |
) { | |
processTweet(entry.target); | |
} | |
}); | |
}; | |
const processAddedNode = (addedNode) => { | |
if (addedNode.nodeType !== Node.ELEMENT_NODE) { | |
return; | |
} | |
addedNode.querySelectorAll(tweetSelector).forEach((tweet) => { | |
processTweet(tweet); | |
observer.observe(tweet); | |
}); | |
}; | |
const observer = new IntersectionObserver(handleIntersection, { | |
threshold: 0.5, | |
}); | |
const targetNode = document.body; | |
const observerConfig = { childList: true, subtree: true }; | |
const mutationObserver = new MutationObserver((mutationsList) => | |
mutationsList.forEach(({ addedNodes }) => | |
addedNodes.forEach(processAddedNode) | |
) | |
); | |
document.querySelectorAll(tweetSelector).forEach((tweet) => { | |
processTweet(tweet); | |
observer.observe(tweet); | |
}); | |
mutationObserver.observe(targetNode, observerConfig); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment