(function () {
const TALK_API_URL = 'https://mm.liushen.fun/api/echo/page';
const TALK_CACHE_KEY = 'liushenEchoCacheV2';
const TALK_CACHE_TIME_KEY = 'liushenEchoCacheTimeV2';
const TALK_CACHE_DURATION = 30 * 60 * 1000;
const TALK_AVATAR = 'https://p.liiiu.cn/i/2025/03/13/67d2fc82d329c.webp';
const shuoshuoState = window.__liushenShuoshuoState || (window.__liushenShuoshuoState = {
resizeHandler: null,
afterRenderTimer: null,
listenersBound: false
});
function cleanupShuoshuo() {
if (shuoshuoState.afterRenderTimer) {
window.clearTimeout(shuoshuoState.afterRenderTimer);
shuoshuoState.afterRenderTimer = null;
}
if (shuoshuoState.resizeHandler) {
window.removeEventListener('resize', shuoshuoState.resizeHandler);
shuoshuoState.resizeHandler = null;
}
}
function renderTalks() {
cleanupShuoshuo();
const talkContainer = document.querySelector('#talk');
if (!talkContainer) return;
talkContainer.innerHTML = '';
const generateIconSVG = () => {
return '';
};
const waterfall = (container) => {
function getMargin(side, element) {
const styles = window.getComputedStyle(element);
return parseFloat(styles[`margin${side}`]) || 0;
}
function toPx(value) {
return `${value}px`;
}
function getTop(element) {
return parseFloat(element.style.top);
}
function getLeft(element) {
return parseFloat(element.style.left);
}
function getWidth(element) {
return element.clientWidth;
}
function getHeight(element) {
return element.clientHeight;
}
function getBottom(element) {
return getTop(element) + getHeight(element) + getMargin('Bottom', element);
}
function getRight(element) {
return getLeft(element) + getWidth(element) + getMargin('Right', element);
}
function sortColumns(elements) {
elements.sort((left, right) => {
return getBottom(left) === getBottom(right)
? getLeft(right) - getLeft(left)
: getBottom(right) - getBottom(left);
});
}
if (typeof container === 'string') {
container = document.querySelector(container);
}
if (!container) return;
const items = Array.from(container.children).map(item => {
item.style.position = 'absolute';
return item;
});
container.style.position = 'relative';
const columns = [];
if (items.length) {
items[0].style.top = '0px';
items[0].style.left = toPx(getMargin('Left', items[0]));
columns.push(items[0]);
}
let index = 1;
for (; index < items.length; index += 1) {
const previous = items[index - 1];
const current = items[index];
const fits = getRight(previous) + getWidth(current) <= getWidth(container);
if (!fits) break;
current.style.top = previous.style.top;
current.style.left = toPx(getRight(previous) + getMargin('Left', current));
columns.push(current);
}
for (; index < items.length; index += 1) {
sortColumns(columns);
const current = items[index];
const column = columns.pop();
current.style.top = toPx(getBottom(column) + getMargin('Top', current));
current.style.left = toPx(getLeft(column));
columns.push(current);
}
sortColumns(columns);
const tallestColumn = columns[0];
container.style.height = tallestColumn ? toPx(getBottom(tallestColumn) + getMargin('Bottom', tallestColumn)) : '0px';
const currentWidth = getWidth(container);
shuoshuoState.resizeHandler = () => {
const currentContainer = document.querySelector('#talk');
if (!currentContainer || !document.body.contains(currentContainer)) {
cleanupShuoshuo();
return;
}
if (getWidth(currentContainer) !== currentWidth) {
waterfall(currentContainer);
}
};
window.addEventListener('resize', shuoshuoState.resizeHandler);
};
const parseMaybeJson = (value) => {
return value && typeof value === 'object' ? value : null;
};
const getEchoExtension = (item) => {
return parseMaybeJson(item?.extension);
};
const getEchoExtensionType = (item) => {
return getEchoExtension(item)?.type || '';
};
const getEchoExtensionPayload = (item) => {
const extension = getEchoExtension(item);
return extension?.payload || null;
};
const getEchoImages = (item) => {
if (!Array.isArray(item?.echo_files)) return [];
return item.echo_files
.map(entry => entry?.file || entry)
.filter(file => {
const category = String(file?.category || '').toLowerCase();
const contentType = String(file?.content_type || '').toLowerCase();
return category === 'image' || contentType.startsWith('image/');
})
.map(file => {
let url = file?.url;
if (!url) return null;
// 如果是相对路径,补全为完整 URL
if (url.startsWith('/')) {
url = 'https://mm.liushen.fun' + url;
} else if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'https://mm.liushen.fun/' + url;
}
return url;
})
.filter(Boolean);
};
const getEchoTags = (item) => {
if (!Array.isArray(item?.tags) || !item.tags.length) return ['无标签'];
return item.tags.map(tag => tag?.name || tag).filter(Boolean);
};
const formatTime = (time) => {
// 如果是 Unix 时间戳(秒),转换为毫秒
const timestamp = time < 10000000000 ? time * 1000 : time;
const date = new Date(timestamp);
const pad = value => String(value).padStart(2, '0');
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
};
const renderTextContent = (content) => {
return (content || '')
.replace(/\[(.*?)\]\((.*?)\)/g, '@$1')
.replace(/- \[ \]/g, '[]')
.replace(/- \[x\]/gi, '[x]')
.replace(/\n/g, '
');
};
const buildImageHtml = (images) => {
if (!images.length) return '';
const imageLinks = images.map(url => {
const safeUrl = `${url}?fmt=webp&q=75`;
return ``;
}).join('');
return `