ech0-shuoshuo.js
· 19 KiB · JavaScript
Raw
function renderTalks() {
const talkContainer = document.querySelector('#talk');
if (!talkContainer) return;
talkContainer.innerHTML = '';
const generateIconSVG = () => {
return `<svg viewBox="0 0 512 512"xmlns="http://www.w3.org/2000/svg"class="is-badge icon"><path d="m512 268c0 17.9-4.3 34.5-12.9 49.7s-20.1 27.1-34.6 35.4c.4 2.7.6 6.9.6 12.6 0 27.1-9.1 50.1-27.1 69.1-18.1 19.1-39.9 28.6-65.4 28.6-11.4 0-22.3-2.1-32.6-6.3-8 16.4-19.5 29.6-34.6 39.7-15 10.2-31.5 15.2-49.4 15.2-18.3 0-34.9-4.9-49.7-14.9-14.9-9.9-26.3-23.2-34.3-40-10.3 4.2-21.1 6.3-32.6 6.3-25.5 0-47.4-9.5-65.7-28.6-18.3-19-27.4-42.1-27.4-69.1 0-3 .4-7.2 1.1-12.6-14.5-8.4-26-20.2-34.6-35.4-8.5-15.2-12.8-31.8-12.8-49.7 0-19 4.8-36.5 14.3-52.3s22.3-27.5 38.3-35.1c-4.2-11.4-6.3-22.9-6.3-34.3 0-27 9.1-50.1 27.4-69.1s40.2-28.6 65.7-28.6c11.4 0 22.3 2.1 32.6 6.3 8-16.4 19.5-29.6 34.6-39.7 15-10.1 31.5-15.2 49.4-15.2s34.4 5.1 49.4 15.1c15 10.1 26.6 23.3 34.6 39.7 10.3-4.2 21.1-6.3 32.6-6.3 25.5 0 47.3 9.5 65.4 28.6s27.1 42.1 27.1 69.1c0 12.6-1.9 24-5.7 34.3 16 7.6 28.8 19.3 38.3 35.1 9.5 15.9 14.3 33.4 14.3 52.4zm-266.9 77.1 105.7-158.3c2.7-4.2 3.5-8.8 2.6-13.7-1-4.9-3.5-8.8-7.7-11.4-4.2-2.7-8.8-3.6-13.7-2.9-5 .8-9 3.2-12 7.4l-93.1 140-42.9-42.8c-3.8-3.8-8.2-5.6-13.1-5.4-5 .2-9.3 2-13.1 5.4-3.4 3.4-5.1 7.7-5.1 12.9 0 5.1 1.7 9.4 5.1 12.9l58.9 58.9 2.9 2.3c3.4 2.3 6.9 3.4 10.3 3.4 6.7-.1 11.8-2.9 15.2-8.7z"fill="#1da1f2"></path></svg>`;
}
const waterfall = (a) => {
function b(a, b) {
var c = window.getComputedStyle(b);
return parseFloat(c["margin" + a]) || 0
}
function c(a) {
return a + "px"
}
function d(a) {
return parseFloat(a.style.top)
}
function e(a) {
return parseFloat(a.style.left)
}
function f(a) {
return a.clientWidth
}
function g(a) {
return a.clientHeight
}
function h(a) {
return d(a) + g(a) + b("Bottom", a)
}
function i(a) {
return e(a) + f(a) + b("Right", a)
}
function j(a) {
a = a.sort(function (a, b) {
return h(a) === h(b) ? e(b) - e(a) : h(b) - h(a)
})
}
function k(b) {
f(a) != t && (b.target.removeEventListener(b.type, arguments.callee), waterfall(a))
}
"string" == typeof a && (a = document.querySelector(a));
var l = [].map.call(a.children, function (a) {
return a.style.position = "absolute", a
});
a.style.position = "relative";
var m = [];
l.length && (l[0].style.top = "0px", l[0].style.left = c(b("Left", l[0])), m.push(l[0]));
for (var n = 1; n < l.length; n++) {
var o = l[n - 1],
p = l[n],
q = i(o) + f(p) <= f(a);
if (!q) break;
p.style.top = o.style.top, p.style.left = c(i(o) + b("Left", p)), m.push(p)
}
for (; n < l.length; n++) {
j(m);
var p = l[n],
r = m.pop();
p.style.top = c(h(r) + b("Top", p)), p.style.left = c(e(r)), m.push(p)
}
j(m);
var s = m[0];
a.style.height = c(h(s) + b("Bottom", s));
var t = f(a);
window.addEventListener ? window.addEventListener("resize", k) : document.body.onresize = k
};
const fetchAndRenderTalks = () => {
const url = 'https://says.liushen.fun/api';
const cacheKey = 'talksCache';
const cacheTimeKey = 'talksCacheTime';
const cacheDuration = 30 * 60 * 1000; // 半个小时 (30 分钟)
const cachedData = localStorage.getItem(cacheKey);
const cachedTime = localStorage.getItem(cacheTimeKey);
const currentTime = new Date().getTime();
// 判断缓存是否有效
if (cachedData && cachedTime && (currentTime - cachedTime < cacheDuration)) {
const data = JSON.parse(cachedData);
renderTalks(data); // 使用缓存渲染数据
} else {
if (talkContainer) {
talkContainer.innerHTML = '';
fetch(url + "/messages/page", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
page: 1,
pageSize: 30
})
})
.then(res => res.json())
.then(data => {
if (data.code === 1 && data.data && Array.isArray(data.data.items)) {
// 缓存数据
localStorage.setItem(cacheKey, JSON.stringify(data.data.items));
localStorage.setItem(cacheTimeKey, currentTime.toString());
renderTalks(data.data.items); // 渲染数据
}
})
.catch(error => {
console.error('Error fetching data:', error);
});
}
}
// 渲染函数
function renderTalks(list) {
// 确保 data 是一个数组
if (Array.isArray(list)) {
let items = list.map(item => formatTalk(item, url));
items.forEach(item => talkContainer.appendChild(generateTalkElement(item)));
waterfall('#talk');
} else {
console.error('Data is not an array:', list);
}
}
};
const formatTalk = (item, url) => {
let date = formatTime(new Date(item.created_at).toString());
let content = item.content;
const baseUrl = url;
let imgs = Array.isArray(item.images) ? item.images.map(img => {
const imageUrl = img.image_url;
// 如果是相对地址(不以 http 或 https 开头),则拼接 baseUrl
return /^https?:\/\//.test(imageUrl) ? imageUrl : `${baseUrl}${imageUrl}`;
}) : [];
let text = content;
content = text.replace(/\[(.*?)\]\((.*?)\)/g, `<a href="$2" target="_blank" rel="nofollow noopener noreferrer">@$1</a>`)
.replace(/- \[ \]/g, '⚪')
.replace(/- \[x\]/g, '⚫');
// 保留换行符,转换 \n 为 <br>
content = content.replace(/\n/g, '<br>');
// 将content用一个类包裹,便于后续处理
content = `<div class="talk_content_text">${content}</div>`;
if (imgs.length > 0) {
const imgDiv = document.createElement('div');
imgDiv.className = 'zone_imgbox';
imgs.forEach(e => {
const imgLink = document.createElement('a');
imgLink.href = e;
imgLink.setAttribute('data-fancybox', 'gallery');
imgLink.className = 'fancybox';
imgLink.setAttribute('data-thumb', e);
const imgTag = document.createElement('img');
imgTag.src = e;
imgLink.appendChild(imgTag);
imgDiv.appendChild(imgLink);
});
content += imgDiv.outerHTML;
}
// 外链分享功能
if (item.extension_type ==="WEBSITE") {
let extension = item.extension ? JSON.parse(item.extension) : {};
const externalUrl = extension.site;
const externalTitle = extension.title;
const externalFavicon = "https://p.liiiu.cn/i/2025/03/13/67d2fc82d329c.webp" // item.externalFavicon;
const externalContainer = `
<div class="shuoshuo-external-link">
<a class="external-link" href="${externalUrl}" target="_blank" rel="nofollow noopener noreferrer">
<div class="external-link-left" style="background-image: url(${externalFavicon})"></div>
<div class="external-link-right">
<div class="external-link-title">${externalTitle}</div>
<div>点击跳转<i class="fa-solid fa-angle-right"></i></div>
</div>
</a>
</div>`;
content += externalContainer;
}
// const ext = JSON.parse(item.ext || '{}');
else if (item.extension_type === "MUSIC") {
const musicUrl = item.extension;
if (musicUrl && musicUrl.includes('music.163.com')) {
const match = musicUrl.match(/id=(\d+)/);
const musicServer = "netease";
const musicType = "song";
const musicId = match ? match[1] : '';
content += `
<meting-js server="${musicServer}" type="${musicType}" id="${musicId}" api="https://met.liiiu.cn/meting/api?server=:server&type=:type&id=:id&r=:r"></meting-js>
`;
} else {
// 懒得适配,自己搞
}
}
// if (ext.doubanMovie && ext.doubanMovie.id) {
// const doubanMovie = ext.doubanMovie;
// const doubanMovieUrl = doubanMovie.url;
// const doubanTitle = doubanMovie.title;
// // const doubanDesc = doubanMovie.desc || '暂无描述';
// const doubanImage = doubanMovie.image;
// const doubanDirector = doubanMovie.director || '未知导演';
// const doubanRating = doubanMovie.rating || '暂无评分';
// // const doubanReleaseDate = doubanMovie.releaseDate || '未知上映时间';
// // const doubanActors = doubanMovie.actors || '未知演员';
// const doubanRuntime = doubanMovie.runtime || '未知时长';
// content += `
// <a class="douban-card" href="${doubanMovieUrl}" target="_blank" rel="nofollow noopener noreferrer">
// <div class="douban-card-bgimg" style="background-image: url('${doubanImage}');"></div>
// <div class="douban-card-left">
// <div class="douban-card-img" style="background-image: url('${doubanImage}');"></div>
// </div>
// <div class="douban-card-right">
// <div class="douban-card-item"><span>电影名: </span><strong>${doubanTitle}</strong></div>
// <div class="douban-card-item"><span>导演: </span><span>${doubanDirector}</span></div>
// <div class="douban-card-item"><span>评分: </span><span>${doubanRating}</span></div>
// <div class="douban-card-item"><span>时长: </span><span>${doubanRuntime}</span></div>
// </div>
// </a>
// `;
// }
// if (ext.doubanBook && ext.doubanBook.id) {
// const doubanBook = ext.doubanBook;
// const bookUrl = doubanBook.url;
// const bookTitle = doubanBook.title;
// // const bookDesc = doubanBook.desc;
// const bookImage = doubanBook.image;
// const bookAuthor = doubanBook.author;
// const bookRating = doubanBook.rating;
// const bookPubDate = doubanBook.pubDate;
// const bookTemplate = `
// <a class="douban-card" href="${bookUrl}" target="_blank" rel="nofollow noopener noreferrer">
// <div class="douban-card-bgimg" style="background-image: url('${bookImage}');"></div>
// <div class="douban-card-left">
// <div class="douban-card-img" style="background-image: url('${bookImage}');"></div>
// </div>
// <div class="douban-card-right">
// <div class="douban-card-item">
// <span>书名: </span><strong>${bookTitle}</strong>
// </div>
// <div class="douban-card-item">
// <span>作者: </span><span>${bookAuthor}</span>
// </div>
// <div class="douban-card-item">
// <span>出版年份: </span><span>${bookPubDate}</span>
// </div>
// <div class="douban-card-item">
// <span>评分: </span><span>${bookRating}</span>
// </div>
// </div>
// </a>
// `;
// content += bookTemplate;
// }
else if (item.extension_type === "VIDEO") {
// const videoType = ext.video.type;
const BVId = item.extension;
// Bilibili 视频模板
// const NewVideoUrl = videoUrl.replace("player.bilibili.com/player.html", "www.bilibili.com/blackboard/html5mobileplayer.html")
const biliTemplate = `
<div style="position: relative; padding: 30% 45%; margin-top: 10px;">
<iframe
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;"
src="https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=${BVId}&as_wide=1&high_quality=1&danmaku=0"
scrolling="no"
border="0"
frameborder="no"
framespacing="0"
allowfullscreen="true"
loading="lazy"
>
</iframe>
</div>
`;
// 将模板插入到 DOM 中
content += biliTemplate;
// else if (videoType === 'youtube') {
// // YouTube 视频模板
// // 从形如https://youtu.be/2V6lvCUPT8I?si=DVhUas6l6qlAr6Ru的链接中提取视频 ID2V6lvCUPT8I
// const youtubeTemplate = `
// <div style="position: relative; padding: 30% 45%; margin-top: 10px;">
// <iframe width="100%"
// style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;"
// src="${videoUrl}"
// title="YouTube video player"
// frameborder="0"
// allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
// referrerpolicy="strict-origin-when-cross-origin"
// allowfullscreen>
// </iframe>
// </div>
// `;
// // 将模板插入到 DOM 中
// content += youtubeTemplate;
// }
}
return {
content: content,
user: item.username || '匿名',
avatar: 'https://p.liiiu.cn/i/2024/03/29/66061417537af.png',
date: date,
location: item.location || '陕西西安',
tags: item.tags ? item.tags.split(',').filter(tag => tag.trim() !== '') : ['日常点滴'],
text: content.replace(/\[(.*?)\]\((.*?)\)/g, '[链接]' + `${imgs.length ? '[图片]' : ''}`)
};
};
const generateTalkElement = (item) => {
const talkItem = document.createElement('div');
talkItem.className = 'talk_item';
const talkMeta = document.createElement('div');
talkMeta.className = 'talk_meta';
const avatar = document.createElement('img');
avatar.className = 'no-lightbox avatar';
avatar.src = item.avatar;
const info = document.createElement('div');
info.className = 'info';
const talkNick = document.createElement('span');
talkNick.className = 'talk_nick';
talkNick.innerHTML = `${item.user} ${generateIconSVG()}`;
const talkDate = document.createElement('span');
talkDate.className = 'talk_date';
talkDate.textContent = item.date;
const talkContent = document.createElement('div');
talkContent.className = 'talk_content';
talkContent.innerHTML = item.content;
const talkBottom = document.createElement('div');
talkBottom.className = 'talk_bottom';
const TagContainer = document.createElement('div');
const talkTag = document.createElement('span');
talkTag.className = 'talk_tag';
talkTag.textContent = `🏷️${item.tags}`;
const locationTag = document.createElement('span');
locationTag.className = 'location_tag';
locationTag.textContent = `🌍${item.location}`;
TagContainer.appendChild(talkTag);
TagContainer.appendChild(locationTag);
const commentLink = document.createElement('a');
commentLink.href = 'javascript:;';
commentLink.onclick = () => goComment(item.text);
const commentIcon = document.createElement('span');
commentIcon.className = 'icon';
const commentIconInner = document.createElement('i');
commentIconInner.className = 'fa-solid fa-message fa-fw';
commentIcon.appendChild(commentIconInner);
commentLink.appendChild(commentIcon);
talkMeta.appendChild(avatar);
info.appendChild(talkNick);
info.appendChild(talkDate);
talkMeta.appendChild(info);
talkItem.appendChild(talkMeta);
talkItem.appendChild(talkContent);
talkBottom.appendChild(TagContainer);
talkBottom.appendChild(commentLink);
talkItem.appendChild(talkBottom);
return talkItem;
};
const goComment = (e) => {
const match = e.match(/<div class="talk_content_text">([\s\S]*?)<\/div>/);
const textContent = match ? match[1] : "";
const n = document.querySelector(".atk-textarea");
n.value = `> ${textContent}\n\n`;
n.focus();
btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
// const n = document.querySelector(".atk-textarea");
// n.value = `> ${e}\n\n`;
// n.focus();
// btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
};
const formatTime = (time) => {
const d = new Date(time);
const ls = [
d.getFullYear(),
d.getMonth() + 1,
d.getDate(),
d.getHours(),
d.getMinutes(),
d.getSeconds(),
];
const r = ls.map((a) => (a.toString().length === 1 ? '0' + a : a));
return `${r[0]}-${r[1]}-${r[2]} ${r[3]}:${r[4]}`;
};
fetchAndRenderTalks();
}
renderTalks();
// function whenDOMReady() {
// const talkContainer = document.querySelector('#talk');
// talkContainer.innerHTML = '';
// fetchAndRenderTalks();
// }
// whenDOMReady();
// document.addEventListener("pjax:complete", whenDOMReady);
1 | function renderTalks() { |
2 | const talkContainer = document.querySelector('#talk'); |
3 | if (!talkContainer) return; |
4 | talkContainer.innerHTML = ''; |
5 | const generateIconSVG = () => { |
6 | return `<svg viewBox="0 0 512 512"xmlns="http://www.w3.org/2000/svg"class="is-badge icon"><path d="m512 268c0 17.9-4.3 34.5-12.9 49.7s-20.1 27.1-34.6 35.4c.4 2.7.6 6.9.6 12.6 0 27.1-9.1 50.1-27.1 69.1-18.1 19.1-39.9 28.6-65.4 28.6-11.4 0-22.3-2.1-32.6-6.3-8 16.4-19.5 29.6-34.6 39.7-15 10.2-31.5 15.2-49.4 15.2-18.3 0-34.9-4.9-49.7-14.9-14.9-9.9-26.3-23.2-34.3-40-10.3 4.2-21.1 6.3-32.6 6.3-25.5 0-47.4-9.5-65.7-28.6-18.3-19-27.4-42.1-27.4-69.1 0-3 .4-7.2 1.1-12.6-14.5-8.4-26-20.2-34.6-35.4-8.5-15.2-12.8-31.8-12.8-49.7 0-19 4.8-36.5 14.3-52.3s22.3-27.5 38.3-35.1c-4.2-11.4-6.3-22.9-6.3-34.3 0-27 9.1-50.1 27.4-69.1s40.2-28.6 65.7-28.6c11.4 0 22.3 2.1 32.6 6.3 8-16.4 19.5-29.6 34.6-39.7 15-10.1 31.5-15.2 49.4-15.2s34.4 5.1 49.4 15.1c15 10.1 26.6 23.3 34.6 39.7 10.3-4.2 21.1-6.3 32.6-6.3 25.5 0 47.3 9.5 65.4 28.6s27.1 42.1 27.1 69.1c0 12.6-1.9 24-5.7 34.3 16 7.6 28.8 19.3 38.3 35.1 9.5 15.9 14.3 33.4 14.3 52.4zm-266.9 77.1 105.7-158.3c2.7-4.2 3.5-8.8 2.6-13.7-1-4.9-3.5-8.8-7.7-11.4-4.2-2.7-8.8-3.6-13.7-2.9-5 .8-9 3.2-12 7.4l-93.1 140-42.9-42.8c-3.8-3.8-8.2-5.6-13.1-5.4-5 .2-9.3 2-13.1 5.4-3.4 3.4-5.1 7.7-5.1 12.9 0 5.1 1.7 9.4 5.1 12.9l58.9 58.9 2.9 2.3c3.4 2.3 6.9 3.4 10.3 3.4 6.7-.1 11.8-2.9 15.2-8.7z"fill="#1da1f2"></path></svg>`; |
7 | } |
8 | const waterfall = (a) => { |
9 | function b(a, b) { |
10 | var c = window.getComputedStyle(b); |
11 | return parseFloat(c["margin" + a]) || 0 |
12 | } |
13 | |
14 | function c(a) { |
15 | return a + "px" |
16 | } |
17 | |
18 | function d(a) { |
19 | return parseFloat(a.style.top) |
20 | } |
21 | |
22 | function e(a) { |
23 | return parseFloat(a.style.left) |
24 | } |
25 | |
26 | function f(a) { |
27 | return a.clientWidth |
28 | } |
29 | |
30 | function g(a) { |
31 | return a.clientHeight |
32 | } |
33 | |
34 | function h(a) { |
35 | return d(a) + g(a) + b("Bottom", a) |
36 | } |
37 | |
38 | function i(a) { |
39 | return e(a) + f(a) + b("Right", a) |
40 | } |
41 | |
42 | function j(a) { |
43 | a = a.sort(function (a, b) { |
44 | return h(a) === h(b) ? e(b) - e(a) : h(b) - h(a) |
45 | }) |
46 | } |
47 | |
48 | function k(b) { |
49 | f(a) != t && (b.target.removeEventListener(b.type, arguments.callee), waterfall(a)) |
50 | } |
51 | "string" == typeof a && (a = document.querySelector(a)); |
52 | var l = [].map.call(a.children, function (a) { |
53 | return a.style.position = "absolute", a |
54 | }); |
55 | a.style.position = "relative"; |
56 | var m = []; |
57 | l.length && (l[0].style.top = "0px", l[0].style.left = c(b("Left", l[0])), m.push(l[0])); |
58 | for (var n = 1; n < l.length; n++) { |
59 | var o = l[n - 1], |
60 | p = l[n], |
61 | q = i(o) + f(p) <= f(a); |
62 | if (!q) break; |
63 | p.style.top = o.style.top, p.style.left = c(i(o) + b("Left", p)), m.push(p) |
64 | } |
65 | for (; n < l.length; n++) { |
66 | j(m); |
67 | var p = l[n], |
68 | r = m.pop(); |
69 | p.style.top = c(h(r) + b("Top", p)), p.style.left = c(e(r)), m.push(p) |
70 | } |
71 | j(m); |
72 | var s = m[0]; |
73 | a.style.height = c(h(s) + b("Bottom", s)); |
74 | var t = f(a); |
75 | window.addEventListener ? window.addEventListener("resize", k) : document.body.onresize = k |
76 | }; |
77 | |
78 | const fetchAndRenderTalks = () => { |
79 | const url = 'https://says.liushen.fun/api'; |
80 | const cacheKey = 'talksCache'; |
81 | const cacheTimeKey = 'talksCacheTime'; |
82 | const cacheDuration = 30 * 60 * 1000; // 半个小时 (30 分钟) |
83 | |
84 | const cachedData = localStorage.getItem(cacheKey); |
85 | const cachedTime = localStorage.getItem(cacheTimeKey); |
86 | const currentTime = new Date().getTime(); |
87 | |
88 | // 判断缓存是否有效 |
89 | if (cachedData && cachedTime && (currentTime - cachedTime < cacheDuration)) { |
90 | const data = JSON.parse(cachedData); |
91 | renderTalks(data); // 使用缓存渲染数据 |
92 | } else { |
93 | if (talkContainer) { |
94 | talkContainer.innerHTML = ''; |
95 | fetch(url + "/messages/page", { |
96 | method: 'POST', |
97 | headers: { |
98 | 'Content-Type': 'application/json', |
99 | }, |
100 | body: JSON.stringify({ |
101 | page: 1, |
102 | pageSize: 30 |
103 | }) |
104 | }) |
105 | .then(res => res.json()) |
106 | .then(data => { |
107 | if (data.code === 1 && data.data && Array.isArray(data.data.items)) { |
108 | // 缓存数据 |
109 | localStorage.setItem(cacheKey, JSON.stringify(data.data.items)); |
110 | localStorage.setItem(cacheTimeKey, currentTime.toString()); |
111 | renderTalks(data.data.items); // 渲染数据 |
112 | } |
113 | }) |
114 | .catch(error => { |
115 | console.error('Error fetching data:', error); |
116 | }); |
117 | } |
118 | } |
119 | |
120 | // 渲染函数 |
121 | function renderTalks(list) { |
122 | // 确保 data 是一个数组 |
123 | if (Array.isArray(list)) { |
124 | let items = list.map(item => formatTalk(item, url)); |
125 | items.forEach(item => talkContainer.appendChild(generateTalkElement(item))); |
126 | waterfall('#talk'); |
127 | } else { |
128 | console.error('Data is not an array:', list); |
129 | } |
130 | } |
131 | }; |
132 | |
133 | |
134 | const formatTalk = (item, url) => { |
135 | let date = formatTime(new Date(item.created_at).toString()); |
136 | let content = item.content; |
137 | const baseUrl = url; |
138 | let imgs = Array.isArray(item.images) ? item.images.map(img => { |
139 | const imageUrl = img.image_url; |
140 | // 如果是相对地址(不以 http 或 https 开头),则拼接 baseUrl |
141 | return /^https?:\/\//.test(imageUrl) ? imageUrl : `${baseUrl}${imageUrl}`; |
142 | }) : []; |
143 | let text = content; |
144 | content = text.replace(/\[(.*?)\]\((.*?)\)/g, `<a href="$2" target="_blank" rel="nofollow noopener noreferrer">@$1</a>`) |
145 | .replace(/- \[ \]/g, '⚪') |
146 | .replace(/- \[x\]/g, '⚫'); |
147 | // 保留换行符,转换 \n 为 <br> |
148 | content = content.replace(/\n/g, '<br>'); |
149 | // 将content用一个类包裹,便于后续处理 |
150 | content = `<div class="talk_content_text">${content}</div>`; |
151 | if (imgs.length > 0) { |
152 | const imgDiv = document.createElement('div'); |
153 | imgDiv.className = 'zone_imgbox'; |
154 | imgs.forEach(e => { |
155 | const imgLink = document.createElement('a'); |
156 | imgLink.href = e; |
157 | imgLink.setAttribute('data-fancybox', 'gallery'); |
158 | imgLink.className = 'fancybox'; |
159 | imgLink.setAttribute('data-thumb', e); |
160 | const imgTag = document.createElement('img'); |
161 | imgTag.src = e; |
162 | imgLink.appendChild(imgTag); |
163 | imgDiv.appendChild(imgLink); |
164 | }); |
165 | content += imgDiv.outerHTML; |
166 | } |
167 | |
168 | // 外链分享功能 |
169 | if (item.extension_type ==="WEBSITE") { |
170 | let extension = item.extension ? JSON.parse(item.extension) : {}; |
171 | const externalUrl = extension.site; |
172 | const externalTitle = extension.title; |
173 | const externalFavicon = "https://p.liiiu.cn/i/2025/03/13/67d2fc82d329c.webp" // item.externalFavicon; |
174 | |
175 | const externalContainer = ` |
176 | <div class="shuoshuo-external-link"> |
177 | <a class="external-link" href="${externalUrl}" target="_blank" rel="nofollow noopener noreferrer"> |
178 | <div class="external-link-left" style="background-image: url(${externalFavicon})"></div> |
179 | <div class="external-link-right"> |
180 | <div class="external-link-title">${externalTitle}</div> |
181 | <div>点击跳转<i class="fa-solid fa-angle-right"></i></div> |
182 | </div> |
183 | </a> |
184 | </div>`; |
185 | |
186 | content += externalContainer; |
187 | } |
188 | |
189 | // const ext = JSON.parse(item.ext || '{}'); |
190 | |
191 | else if (item.extension_type === "MUSIC") { |
192 | const musicUrl = item.extension; |
193 | if (musicUrl && musicUrl.includes('music.163.com')) { |
194 | const match = musicUrl.match(/id=(\d+)/); |
195 | const musicServer = "netease"; |
196 | const musicType = "song"; |
197 | const musicId = match ? match[1] : ''; |
198 | |
199 | content += ` |
200 | <meting-js server="${musicServer}" type="${musicType}" id="${musicId}" api="https://met.liiiu.cn/meting/api?server=:server&type=:type&id=:id&r=:r"></meting-js> |
201 | `; |
202 | } else { |
203 | // 懒得适配,自己搞 |
204 | } |
205 | } |
206 | |
207 | // if (ext.doubanMovie && ext.doubanMovie.id) { |
208 | // const doubanMovie = ext.doubanMovie; |
209 | // const doubanMovieUrl = doubanMovie.url; |
210 | // const doubanTitle = doubanMovie.title; |
211 | // // const doubanDesc = doubanMovie.desc || '暂无描述'; |
212 | // const doubanImage = doubanMovie.image; |
213 | // const doubanDirector = doubanMovie.director || '未知导演'; |
214 | // const doubanRating = doubanMovie.rating || '暂无评分'; |
215 | // // const doubanReleaseDate = doubanMovie.releaseDate || '未知上映时间'; |
216 | // // const doubanActors = doubanMovie.actors || '未知演员'; |
217 | // const doubanRuntime = doubanMovie.runtime || '未知时长'; |
218 | |
219 | // content += ` |
220 | // <a class="douban-card" href="${doubanMovieUrl}" target="_blank" rel="nofollow noopener noreferrer"> |
221 | // <div class="douban-card-bgimg" style="background-image: url('${doubanImage}');"></div> |
222 | // <div class="douban-card-left"> |
223 | // <div class="douban-card-img" style="background-image: url('${doubanImage}');"></div> |
224 | // </div> |
225 | // <div class="douban-card-right"> |
226 | // <div class="douban-card-item"><span>电影名: </span><strong>${doubanTitle}</strong></div> |
227 | // <div class="douban-card-item"><span>导演: </span><span>${doubanDirector}</span></div> |
228 | // <div class="douban-card-item"><span>评分: </span><span>${doubanRating}</span></div> |
229 | // <div class="douban-card-item"><span>时长: </span><span>${doubanRuntime}</span></div> |
230 | // </div> |
231 | // </a> |
232 | // `; |
233 | // } |
234 | |
235 | // if (ext.doubanBook && ext.doubanBook.id) { |
236 | // const doubanBook = ext.doubanBook; |
237 | // const bookUrl = doubanBook.url; |
238 | // const bookTitle = doubanBook.title; |
239 | // // const bookDesc = doubanBook.desc; |
240 | // const bookImage = doubanBook.image; |
241 | // const bookAuthor = doubanBook.author; |
242 | // const bookRating = doubanBook.rating; |
243 | // const bookPubDate = doubanBook.pubDate; |
244 | |
245 | // const bookTemplate = ` |
246 | // <a class="douban-card" href="${bookUrl}" target="_blank" rel="nofollow noopener noreferrer"> |
247 | // <div class="douban-card-bgimg" style="background-image: url('${bookImage}');"></div> |
248 | // <div class="douban-card-left"> |
249 | // <div class="douban-card-img" style="background-image: url('${bookImage}');"></div> |
250 | // </div> |
251 | // <div class="douban-card-right"> |
252 | // <div class="douban-card-item"> |
253 | // <span>书名: </span><strong>${bookTitle}</strong> |
254 | // </div> |
255 | // <div class="douban-card-item"> |
256 | // <span>作者: </span><span>${bookAuthor}</span> |
257 | // </div> |
258 | // <div class="douban-card-item"> |
259 | // <span>出版年份: </span><span>${bookPubDate}</span> |
260 | // </div> |
261 | // <div class="douban-card-item"> |
262 | // <span>评分: </span><span>${bookRating}</span> |
263 | // </div> |
264 | // </div> |
265 | // </a> |
266 | // `; |
267 | |
268 | // content += bookTemplate; |
269 | // } |
270 | |
271 | else if (item.extension_type === "VIDEO") { |
272 | // const videoType = ext.video.type; |
273 | const BVId = item.extension; |
274 | // Bilibili 视频模板 |
275 | // const NewVideoUrl = videoUrl.replace("player.bilibili.com/player.html", "www.bilibili.com/blackboard/html5mobileplayer.html") |
276 | const biliTemplate = ` |
277 | <div style="position: relative; padding: 30% 45%; margin-top: 10px;"> |
278 | <iframe |
279 | style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;" |
280 | src="https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=${BVId}&as_wide=1&high_quality=1&danmaku=0" |
281 | scrolling="no" |
282 | border="0" |
283 | frameborder="no" |
284 | framespacing="0" |
285 | allowfullscreen="true" |
286 | loading="lazy" |
287 | > |
288 | </iframe> |
289 | </div> |
290 | `; |
291 | // 将模板插入到 DOM 中 |
292 | content += biliTemplate; |
293 | |
294 | |
295 | // else if (videoType === 'youtube') { |
296 | // // YouTube 视频模板 |
297 | // // 从形如https://youtu.be/2V6lvCUPT8I?si=DVhUas6l6qlAr6Ru的链接中提取视频 ID2V6lvCUPT8I |
298 | // const youtubeTemplate = ` |
299 | // <div style="position: relative; padding: 30% 45%; margin-top: 10px;"> |
300 | // <iframe width="100%" |
301 | // style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;" |
302 | // src="${videoUrl}" |
303 | // title="YouTube video player" |
304 | // frameborder="0" |
305 | // allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" |
306 | // referrerpolicy="strict-origin-when-cross-origin" |
307 | // allowfullscreen> |
308 | // </iframe> |
309 | // </div> |
310 | // `; |
311 | // // 将模板插入到 DOM 中 |
312 | // content += youtubeTemplate; |
313 | // } |
314 | } |
315 | |
316 | return { |
317 | content: content, |
318 | user: item.username || '匿名', |
319 | avatar: 'https://p.liiiu.cn/i/2024/03/29/66061417537af.png', |
320 | date: date, |
321 | location: item.location || '陕西西安', |
322 | tags: item.tags ? item.tags.split(',').filter(tag => tag.trim() !== '') : ['日常点滴'], |
323 | text: content.replace(/\[(.*?)\]\((.*?)\)/g, '[链接]' + `${imgs.length ? '[图片]' : ''}`) |
324 | }; |
325 | }; |
326 | |
327 | const generateTalkElement = (item) => { |
328 | const talkItem = document.createElement('div'); |
329 | talkItem.className = 'talk_item'; |
330 | |
331 | const talkMeta = document.createElement('div'); |
332 | talkMeta.className = 'talk_meta'; |
333 | |
334 | const avatar = document.createElement('img'); |
335 | avatar.className = 'no-lightbox avatar'; |
336 | avatar.src = item.avatar; |
337 | |
338 | const info = document.createElement('div'); |
339 | info.className = 'info'; |
340 | |
341 | const talkNick = document.createElement('span'); |
342 | talkNick.className = 'talk_nick'; |
343 | talkNick.innerHTML = `${item.user} ${generateIconSVG()}`; |
344 | |
345 | const talkDate = document.createElement('span'); |
346 | talkDate.className = 'talk_date'; |
347 | talkDate.textContent = item.date; |
348 | |
349 | const talkContent = document.createElement('div'); |
350 | talkContent.className = 'talk_content'; |
351 | talkContent.innerHTML = item.content; |
352 | |
353 | const talkBottom = document.createElement('div'); |
354 | talkBottom.className = 'talk_bottom'; |
355 | |
356 | const TagContainer = document.createElement('div'); |
357 | |
358 | const talkTag = document.createElement('span'); |
359 | talkTag.className = 'talk_tag'; |
360 | talkTag.textContent = `🏷️${item.tags}`; |
361 | |
362 | const locationTag = document.createElement('span'); |
363 | locationTag.className = 'location_tag'; |
364 | locationTag.textContent = `🌍${item.location}`; |
365 | |
366 | TagContainer.appendChild(talkTag); |
367 | TagContainer.appendChild(locationTag); |
368 | |
369 | const commentLink = document.createElement('a'); |
370 | commentLink.href = 'javascript:;'; |
371 | commentLink.onclick = () => goComment(item.text); |
372 | const commentIcon = document.createElement('span'); |
373 | commentIcon.className = 'icon'; |
374 | const commentIconInner = document.createElement('i'); |
375 | commentIconInner.className = 'fa-solid fa-message fa-fw'; |
376 | commentIcon.appendChild(commentIconInner); |
377 | commentLink.appendChild(commentIcon); |
378 | |
379 | talkMeta.appendChild(avatar); |
380 | info.appendChild(talkNick); |
381 | info.appendChild(talkDate); |
382 | talkMeta.appendChild(info); |
383 | talkItem.appendChild(talkMeta); |
384 | talkItem.appendChild(talkContent); |
385 | talkBottom.appendChild(TagContainer); |
386 | talkBottom.appendChild(commentLink); |
387 | talkItem.appendChild(talkBottom); |
388 | |
389 | return talkItem; |
390 | }; |
391 | |
392 | const goComment = (e) => { |
393 | const match = e.match(/<div class="talk_content_text">([\s\S]*?)<\/div>/); |
394 | const textContent = match ? match[1] : ""; |
395 | const n = document.querySelector(".atk-textarea"); |
396 | n.value = `> ${textContent}\n\n`; |
397 | n.focus(); |
398 | btf.snackbarShow("已为您引用该说说,不删除空格效果更佳"); |
399 | // const n = document.querySelector(".atk-textarea"); |
400 | // n.value = `> ${e}\n\n`; |
401 | // n.focus(); |
402 | // btf.snackbarShow("已为您引用该说说,不删除空格效果更佳"); |
403 | }; |
404 | |
405 | const formatTime = (time) => { |
406 | const d = new Date(time); |
407 | const ls = [ |
408 | d.getFullYear(), |
409 | d.getMonth() + 1, |
410 | d.getDate(), |
411 | d.getHours(), |
412 | d.getMinutes(), |
413 | d.getSeconds(), |
414 | ]; |
415 | const r = ls.map((a) => (a.toString().length === 1 ? '0' + a : a)); |
416 | return `${r[0]}-${r[1]}-${r[2]} ${r[3]}:${r[4]}`; |
417 | }; |
418 | |
419 | fetchAndRenderTalks(); |
420 | } |
421 | |
422 | renderTalks(); |
423 | |
424 | // function whenDOMReady() { |
425 | // const talkContainer = document.querySelector('#talk'); |
426 | // talkContainer.innerHTML = ''; |
427 | // fetchAndRenderTalks(); |
428 | // } |
429 | // whenDOMReady(); |
430 | // document.addEventListener("pjax:complete", whenDOMReady); |
twikoo-comments.js
· 370 B · JavaScript
Raw
const goComment = (e) => {
const n = document.querySelector(".el-textarea__inner");
n.value = `> ${e}\n\n`;
n.focus();
btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
};
// 如果是twikoo评论区,请自行替换goComment函数,注意,如果评论区开了懒加载可能导致无法找到元素。
1 | const goComment = (e) => { |
2 | const n = document.querySelector(".el-textarea__inner"); |
3 | n.value = `> ${e}\n\n`; |
4 | n.focus(); |
5 | btf.snackbarShow("已为您引用该说说,不删除空格效果更佳"); |
6 | }; |
7 | |
8 | // 如果是twikoo评论区,请自行替换goComment函数,注意,如果评论区开了懒加载可能导致无法找到元素。 |