Files
blog/themes/Ying/assets/js/modules/linkify.js
T
QunLIn 20869a3c45
Deploy to Production / pre-check (push) Successful in 2m0s
Deploy to Production / build (push) Successful in 9m9s
Deploy to Production / deploy-edgeone (push) Successful in 4m3s
Deploy to Production / finalize (push) Successful in 29s
Deploy to Production / notify-failure (push) Skipped
RSS API 地址全部收敛到 hugo.toml [params.rssapi],切到 api.200181.xyz
- 新增 [params.rssapi] base 配置,主题 7 处硬编码改为读配置:
  head(preconnect+window.rssApiBase)、footer(构建时拉 links/feeds)、
  render-link(favicon)、circles/links 页 fetch、linkify.js(读 window.rssApiBase)
- scripts/fetch_greetings.js 支持 RSS_API_BASE 环境变量,默认新地址
- scfapi.usj.cc(国内代理)保持不变
2026-10-03 01:19:02 +08:00

86 lines
3.2 KiB
JavaScript

// linkify.js - Convert bare URLs to link cards, video URLs to players
(function() {
var URL_RE = /(https?:\/\/[^\s一-鿿 -〿＀-￯<>"')\]]+)/g;
var VIDEO_RE = /\.(mp4|webm|ogg|mov)(\?|$)/i;
var FAVICON_API = (window.rssApiBase || 'https://api.200181.xyz') + '/api/favicon?url=';
function getDomain(url) {
try { return new URL(url).hostname; } catch (e) { return url; }
}
function makeVideo(url) {
var video = document.createElement('video');
video.className = 'post-video';
video.controls = true;
video.preload = 'metadata';
video.playsInline = true;
var source = document.createElement('source');
source.src = url;
video.appendChild(source);
return video;
}
function makeCard(url) {
var domain = getDomain(url);
var card = document.createElement('a');
card.className = 'link-card';
card.href = '/tiaozhuan.html?target=' + btoa(url);
card.target = '_blank';
card.rel = 'noopener';
card.innerHTML = '<img class="link-card-icon" src="' + FAVICON_API + domain + '" alt="" loading="lazy" onerror="this.style.display=\'none\'">' +
'<span class="link-card-body"><span class="link-card-title">' + domain + '</span>' +
'<span class="link-card-url">' + url + '</span></span>' +
'<span class="link-card-arrow">↗</span>';
return card;
}
function linkify(root) {
var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
var textNodes = [];
while (walker.nextNode()) {
var node = walker.currentNode;
if (node.parentElement && node.parentElement.closest('a, .link-card, code, pre, video, #szh')) continue;
if (URL_RE.test(node.textContent)) textNodes.push(node);
}
textNodes.forEach(function(node) {
URL_RE.lastIndex = 0;
var text = node.textContent;
var parts = [];
var lastIdx = 0;
var match;
while ((match = URL_RE.exec(text)) !== null) {
if (match.index > lastIdx) {
parts.push(document.createTextNode(text.slice(lastIdx, match.index)));
}
if (VIDEO_RE.test(match[1])) {
parts.push(makeVideo(match[1]));
} else {
parts.push(makeCard(match[1]));
}
lastIdx = match.index + match[0].length;
}
if (parts.length === 0) return;
if (lastIdx < text.length) {
parts.push(document.createTextNode(text.slice(lastIdx)));
}
var frag = document.createDocumentFragment();
parts.forEach(function(p) { frag.appendChild(p); });
node.parentNode.replaceChild(frag, node);
});
}
function run() {
var content = document.querySelector('.post-content');
if (content) linkify(content);
}
window.initLinkify = run;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', run);
} else {
run();
}
})();