diff options
| author | yo momma <shutup@oops.wtf> | 2026-01-30 09:52:51 +0000 |
|---|---|---|
| committer | yo momma <shutup@oops.wtf> | 2026-01-30 09:52:51 +0000 |
| commit | 5bcf2586305bb9f246497558f46f2fa15f686364 (patch) | |
| tree | b08e56aebc4f1b27dda222f8f46e7c3f3d8d780d /static/js/pichat.butt.js | |
| parent | 5aea6f7791d9a5238581b04d2198205c90495baf (diff) | |
Fix: restore hotlinks + cache-bust pichat.js
Diffstat (limited to 'static/js/pichat.butt.js')
| -rwxr-xr-x | static/js/pichat.butt.js | 104 |
1 files changed, 85 insertions, 19 deletions
diff --git a/static/js/pichat.butt.js b/static/js/pichat.butt.js index 220e873..f0baae5 100755 --- a/static/js/pichat.butt.js +++ b/static/js/pichat.butt.js @@ -65,18 +65,68 @@ function normalizeUrl(url) { } URLRegex = /((\b(http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi; -PicRegex = /\.(jpg|jpeg|png|gif|bmp)$/i; +PicRegex = /\.(jpg|jpeg|png|gif|bmp|svg|webp|fid)$/i; +VideoRegex = /\.(mp4|webm|mov|m4v|gifv)$/i; + +function splitTrailingPunctuation(url) { + if (!url) return { "url": url, "suffix": "" }; + var match = url.match(/[)\]\}\.,!\?;:'"]+$/); + if (!match) return { "url": url, "suffix": "" }; + return { "url": url.slice(0, -match[0].length), "suffix": match[0] }; +} + +function imgurIdFromUri(uri) { + var host = parseDomain(uri.host || ""); + if (!host || !host.match(/(^|\\.)imgur\\.com$/i)) return null; + if (!uri.file) return null; + + var fileLower = uri.file.toLowerCase(); + if (PicRegex.test(fileLower) || VideoRegex.test(fileLower)) return null; + + if (!uri.file.match(/^[A-Za-z0-9]+$/)) return null; + return uri.file; +} + +function imgurCandidateUrls(id) { + var base = "https://i.imgur.com/" + id; + return [base + ".jpg", base + ".png", base + ".gif", base + ".jpeg"]; +} + +function imgurHotlinkFallback(img) { + try { + var candidates = (img.getAttribute("data-imgur-candidates") || "").split("|"); + if (!candidates.length || !candidates[0]) return; + + var idx = parseInt(img.getAttribute("data-imgur-idx") || "0", 10); + var next = idx + 1; + if (next >= candidates.length) { + var link = img.parentNode; + if (link && link.tagName == "A") { + var href = link.getAttribute("href") || ""; + while (link.firstChild) link.removeChild(link.firstChild); + link.appendChild(document.createTextNode(href)); + } + return; + } + + img.setAttribute("data-imgur-idx", "" + next); + img.src = candidates[next]; + } catch (e) {} +} function getImagesAsArray(text) { var imgs = [] var urls = text.match(URLRegex) if (urls === null) return imgs for (var i = 0; i<urls.length; i++){ - var url = urls[i] - var normalized = normalizeUrl(url); - var urlWithoutParams = normalized.replace(/[?#].*$/i, ""); - if (PicRegex.test(urlWithoutParams)) - imgs.push(normalized) + var split = splitTrailingPunctuation(urls[i]); + var normalized = normalizeUrl(split.url); + var uri = parseUri(normalized); + var imgurId = imgurIdFromUri(uri); + var candidate = imgurId ? imgurCandidateUrls(imgurId)[0] : normalized; + + var urlWithoutParams = candidate.replace(/[?#].*$/i, ""); + if (PicRegex.test(urlWithoutParams)) imgs.push(candidate) } return imgs } @@ -89,22 +139,35 @@ function linkify(text) { // durty hack to use a global to check this... but otherwise i'd have to rewrite the String.replace function? :/ var LastMsgContainsImage = false function linkReplace(url) { - //var urlWithoutParams = url.replace(/\?.*$/i, ""); - - linkUrl = normalizeUrl(url); - - var uri = parseUri(url) + var split = splitTrailingPunctuation(url); + linkUrl = normalizeUrl(split.url); + var uri = parseUri(linkUrl); + + var imgurId = imgurIdFromUri(uri); + if (imgurId) { + LastMsgContainsImage = true; + var candidates = imgurCandidateUrls(imgurId); + var first = candidates[0]; + return "<a target=\"_blank\" href=\"" + linkUrl + "\">" + + "<img src=\"" + first + "\" class=\"imgur-hotlink\" data-imgur-idx=\"0\" data-imgur-candidates=\"" + candidates.join('|') + "\" onerror=\"imgurHotlinkFallback(this)\">" + + "</a>" + split.suffix; + } + switch(getUriType(uri)) { case 'image': LastMsgContainsImage = true; - return "<a target='_blank' href='" + linkUrl + "'><img src='" + linkUrl + "'></a>"; break; - case 'youtube': + return "<a target='_blank' href='" + linkUrl + "'><img src='" + linkUrl + "'></a>" + split.suffix; + case 'video': + LastMsgContainsImage = true; + var videoUrl = linkUrl.replace(/\.gifv([?#].*)?$/i, '.mp4$1'); + return "<a target=\"_blank\" href=\"" + linkUrl + "\"><video src=\"" + videoUrl + "\" autoplay loop muted controls playsinline></video></a>" + split.suffix; + case 'youtube': Youtube.startAnimation(); - return "<a target='_blank' class='youtube' href='" + linkUrl + "'>" + - "<img class='youtube-thumb' width='130' height='97' src='"+Youtube.nextThumbUrl(uri.queryKey.v)+"'>" + - "<img class='youtube-controls' src='/static/img/youtube.controls.png'></a>"; break; + return "<a target=\"_blank\" class=\"youtube\" href=\"" + linkUrl + "\">" + + "<img class=\"youtube-thumb\" width=\"130\" height=\"97\" src=\"" + Youtube.nextThumbUrl(uri.queryKey.v) + "\">" + + "<img class=\"youtube-controls\" src=\"/static/img/youtube.controls.png\"></a>" + split.suffix; default: - return "<a target='_blank' href='" + linkUrl + "'>" + url + "</a>"; + return "<a target=\"_blank\" href=\"" + linkUrl + "\">" + split.url + "</a>" + split.suffix; } } @@ -130,7 +193,7 @@ Youtube = { var img = $(this); // yt thumb url example: https://i.ytimg.com/vi/0123456789A/1.jpg var src = img.attr("src") || "" - var match = src.match(/\\/vi\\/([^/]{11})\\/(\\d)\\.jpg/i) + var match = src.match(/\/vi\/([^/]{11})\/(\d)\.jpg/i) if (!match) return var v = match[1] var num = match[2] @@ -149,8 +212,11 @@ Youtube = { function getUriType(uri){ if (PicRegex.test(uri.file.toLowerCase())) return "image"; + + if (VideoRegex.test(uri.file.toLowerCase())) + return "video"; - if (parseDomain(uri.host) == "youtube.com" && 'v' in uri.queryKey || uri.anchor.indexOf('v') != -1) + if (parseDomain(uri.host) == "youtube.com" && ('v' in uri.queryKey || uri.anchor.indexOf('v') != -1)) return "youtube"; return "link"; |
