MetaFilter: restore the glory days of the IMG tag by inlining images linked in comments
// ==UserScript==
// @name MeFi Inline Images
// @namespace https://github.com/klipspringr/mefi-userscripts
// @version 2025-09-09-a
// @description MetaFilter: restore the glory days of the IMG tag by inlining images linked in comments
// @author Klipspringer
// @supportURL https://github.com/klipspringr/mefi-userscripts
// @license MIT
// @match *://*.metafilter.com/*
// ==/UserScript==
;(async () => {
;("use strict")
const IMG_CLASS = "mfit"
const ATTRIBUTE_DONE = "data-mfit"
if (
!/^\/(\d|comments\.mefi)/.test(window.location.pathname) ||
/rss$/.test(window.location.pathname)
) {
return
}
const onImageError = (e) => e.target.remove() // if fail to load, remove element
const run = async (target) => {
const start = performance.now()
const nodes = (target ?? document).querySelectorAll(
`div.comments a:not(.smallcopy *):not([${ATTRIBUTE_DONE}])`
)
let count = 0
nodes.forEach((node) => {
let href = node.getAttribute("href")
if (!href) return
const imgur = href.match(
/^https?:\/\/(?:i\.)?imgur.com\/(\w+)$/
)?.[1]
if (imgur) {
// using i subdomain saves a 302 redirect
// .png works even if MIME type is different
href = `https://i.imgur.com/${imgur}.png`
} else if (!/\.(avif|gif|jpg|jpeg|png|webp)$/i.test(href)) {
return
}
// don't inject images twice - e.g. when new comments loaded a second time
node.setAttribute(ATTRIBUTE_DONE, "done")
const img = document.createElement("img")
img.setAttribute("src", href)
img.setAttribute("class", IMG_CLASS)
img.addEventListener("error", onImageError)
// we're setting display:block on the img. so a following <br> causes an empty line
if (node.nextElementSibling?.tagName === "BR")
node.nextElementSibling.remove()
node.insertAdjacentElement("afterend", img)
count += 1
})
console.log(
"mefi-inline-images",
nodes.length,
count,
Math.round(performance.now() - start) + "ms"
)
}
const styleElement = document.createElement("style")
styleElement.textContent = `img.${IMG_CLASS} {
display: block;
max-width: 100%;
max-height: 50vh;
width: auto;
height: auto;
object-fit: contain;
border: 1px solid rgba(0, 0, 0, 0.2);
}`
document.body.insertAdjacentElement("beforeend", styleElement)
const newCommentsElement = document.getElementById("newcomments")
if (newCommentsElement) {
const observer = new MutationObserver(() => run(newCommentsElement))
observer.observe(newCommentsElement, { childList: true })
}
run()
})()