switch shuoshuo function to ech0

This commit is contained in:
2026-01-20 09:22:42 +08:00
parent 8db2cab4d6
commit 39fcced835
9 changed files with 412 additions and 433 deletions

View File

@@ -1167,6 +1167,7 @@ inject:
- <link rel="stylesheet" href="/css/style.css"> - <link rel="stylesheet" href="/css/style.css">
- <link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/rightmenu/rightmenu.css"> - <link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/rightmenu/rightmenu.css">
- <link rel="stylesheet" href="/css/shuoshuo.css"> - <link rel="stylesheet" href="/css/shuoshuo.css">
- <link rel="stylesheet" href="/css/shuoshuoshouye.css">
- <link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/webfont/font.css"> - <link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/webfont/font.css">
- <link rel="stylesheet" href="/css/poem.css"> - <link rel="stylesheet" href="/css/poem.css">
- <link rel="stylesheet" href="https://fastly.jsdelivr.net/npm/aplayer/dist/APlayer.min.css" media="all" onload="this.media=&quot;all&quot;"> - <link rel="stylesheet" href="https://fastly.jsdelivr.net/npm/aplayer/dist/APlayer.min.css" media="all" onload="this.media=&quot;all&quot;">
@@ -1183,6 +1184,7 @@ inject:
- <script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar/calendar.js"></script> - <script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar/calendar.js"></script>
- <script src="https://unpkg.com/chinese-lunar@0.1.4/lib/chinese-lunar.js"></script> - <script src="https://unpkg.com/chinese-lunar@0.1.4/lib/chinese-lunar.js"></script>
- <script src="/js/random.js"></script> - <script src="/js/random.js"></script>
- <script src="/js/shuoshuoshouye.js"></script>
# CDN Settings # CDN Settings
# Don't modify the following settings unless you know how they work # Don't modify the following settings unless you know how they work

View File

@@ -41,6 +41,7 @@ html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside
#body-wrap(class=pageType) #body-wrap(class=pageType)
include ./header/index.pug include ./header/index.pug
include ./others/memos_home.pug
main#content-inner.layout(class=hideAside) main#content-inner.layout(class=hideAside)
if body if body

View File

@@ -0,0 +1,7 @@
if (is_home())
#main_top
#bber-talk.cardHover.bb_talk_swipper(onclick=`pjax.loadUrl("/shuoshuo/")`)
svg.icon(t='1660960757124', viewBox='0 0 1024 1024', version='1.1', xmlns='http://www.w3.org/2000/svg', p-id='3946', width='200', height='200')
path(d='M526.432 924.064c-20.96 0-44.16-12.576-68.96-37.344L274.752 704H192c-52.928 0-96-43.072-96-96V416c0-52.928 43.072-96 96-96h82.752l182.624-182.624c24.576-24.576 47.744-37.024 68.864-37.024C549.184 100.352 576 116 576 160v704c0 44.352-26.72 60.064-49.568 60.064zM192 384c-17.632 0-32 14.368-32 32v192c0 17.664 14.368 32 32 32h96c8.48 0 16.64 3.36 22.624 9.376l192.064 192.096c3.392 3.36 6.496 6.208 9.312 8.576V174.016a145.824 145.824 0 0 0-9.376 8.608l-192 192C304.64 380.64 296.48 384 288 384h-96zM687.584 730.368a31.898 31.898 0 0 1-18.656-6.016c-14.336-10.304-17.632-30.304-7.328-44.672l12.672-17.344C707.392 617.44 736 578.624 736 512c0-69.024-25.344-102.528-57.44-144.928-5.664-7.456-11.328-15.008-16.928-22.784-10.304-14.336-7.04-34.336 7.328-44.672 14.368-10.368 34.336-7.04 44.672 7.328 5.248 7.328 10.656 14.464 15.968 21.504C764.224 374.208 800 421.504 800 512c0 87.648-39.392 141.12-74.144 188.32l-12.224 16.736c-6.272 8.704-16.064 13.312-26.048 13.312z', p-id='3947')
path(d='M796.448 839.008a31.906 31.906 0 0 1-21.088-7.936c-13.28-11.648-14.624-31.872-2.976-45.152C836.608 712.672 896 628.864 896 512s-59.392-200.704-123.616-273.888c-11.648-13.312-10.304-33.504 2.976-45.184 13.216-11.648 33.44-10.336 45.152 2.944C889.472 274.56 960 373.6 960 512s-70.528 237.472-139.488 316.096c-6.368 7.232-15.2 10.912-24.064 10.912z', p-id='3948')
ul.talk-list 说说加载中。。。

View File

@@ -1,3 +1,27 @@
:root {
--liushen-card-bg: #fff;
--liushen-card-border: 1px solid #e3e8f7;
--card-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.09);
--card-hover-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.2);
--liushen-card-secondbg: #f1f3f8;
--liushen-button-hover-bg: #2679cc;
--liushen-text: #4c4948;
--liushen-button-bg: #f1f3f8;
--liushen-fancybox-bg: rgba(255,255,255,0.5);
}
:root, [data-theme=dark] {
--liushen-card-bg: #181818;
--liushen-card-secondbg: #30343f;
--liushen-card-border: 1px solid #42444a;
--card-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.09);
--card-hover-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.2);
--liushen-button-bg: #30343f;
--liushen-button-hover-bg: #2679cc;
--liushen-text: rgba(255,255,255,0.702);
--liushen-fancybox-bg: rgba(0,0,0,0.5);
}
/* 卡片初始化 */ /* 卡片初始化 */
#talk .talk_item { #talk .talk_item {
width: calc(33.333% - 6px); width: calc(33.333% - 6px);
@@ -174,56 +198,6 @@
position: relative; position: relative;
} }
.douban-card .douban-card-bgimg {
background-position: 50%;
background-repeat: no-repeat;
background-size: 100%;
filter: blur(15px) brightness(.6);
height: 115%;
position: absolute;
width: 115%;
}
.douban-card .douban-card-left {
align-items: center;
display: flex;
flex-direction: column;
position: relative;
}
.douban-card .douban-card-left .douban-card-img {
transition: all .5s ease;
height: 130px;
position: relative;
width: 80px;
background-position: 50%;
background-repeat: no-repeat;
background-size: 100%;
}
.douban-card .douban-card-left:hover .douban-card-img {
filter: blur(5px) brightness(.6);
transform: perspective(800px) rotateX(180deg);
}
.douban-card .douban-card-right {
color: #faebd7;
display: flex;
flex-direction: column;
font-size: 14px;
line-height: 1.5;
margin-left: 12px;
position: relative;
}
.douban-card .douban-card-right .douban-card-item {
margin-top: 4px;
max-width: 95%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 外链卡片 */ /* 外链卡片 */
#talk .talk_item .talk_content .shuoshuo-external-link { #talk .talk_item .talk_content .shuoshuo-external-link {
/* 无下划线 */ /* 无下划线 */

View File

@@ -0,0 +1,123 @@
/* maintop */
#main_top {
display: flex;
justify-content: center;
z-index: 1;
max-width: 1400px;
margin: 20px auto;
width: 100%;
padding: 0 15px;
margin-top: 40px;
margin-bottom: 0px;
}
.hide-aside #main_top {
width: 80%;
}
.hide-aside #main_top #bber-talk {
max-width: 936px;
}
@media screen and (min-width: 2000px) {
.hide-aside #main_top #bber-talk {
max-width: 80%;
}
#main_top {
max-width: 70%;
}
}
@media screen and (max-width: 1210px) {
.hide-aside #main_top {
padding: 0 12px;
}
}
@media screen and (max-width: 900px) {
.hide-aside #main_top {
width: 100%;
padding: 0 15px;
}
}
@media screen and (max-width: 768px) {
.hide-aside #main_top {
padding: 0 5px;
}
div#main_top {
margin-top: 20px;
padding: 0 5px;
}
}
#bber-talk {
/* border-radius: 8px; */
/* background: var(--card-bg); */
/* box-shadow: none; */
box-sizing: border-box;
/* transition: all .3s ease-in-out; */
cursor: pointer;
width: 100%;
min-height: 50px;
padding: .5rem 1rem;
display: flex;
align-items: center;
overflow: hidden;
font-weight: 700;
}
#bber-talk,
#bber-talk a {
color: var(--font-color);
}
#bber-talk svg.icon {
width: 1em;
height: 1em;
vertical-align: -.15em;
fill: currentColor;
overflow: hidden;
font-size: 20px;
}
#bber-talk .item i {
margin-left: 5px;
}
#bber-talk > i {
font-size: 1.1rem;
}
#bber-talk .talk-list {
flex: 1;
max-height: 32px;
font-size: 16px;
padding: 0;
margin: 0;
overflow: hidden;
}
#bber-talk .talk-list:hover {
color: var(--default-bg-color);
transition: all .2s ease-in-out;
}
#bber-talk .talk-list li {
list-style: none;
width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
margin-left: 10px;
}
@media screen and (min-width: 770px) {
#bber-talk .talk-list {
text-align: center;
margin-right: 20px;
}
}

View File

@@ -1,25 +1,5 @@
/* #card-newest-comments img {border-radius: 10px; /* 设置最新评论圆角半径为10px可以根据需要调整} */ /* #card-newest-comments img {border-radius: 10px; /* 设置最新评论圆角半径为10px可以根据需要调整} */
/* 说说轮播 */
#bber-talk {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
backdrop-filter: blur(10px);
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 说说轮播 */
[data-theme=dark] #bber-talk {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
backdrop-filter: blur(10px);
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 侧边栏个人信息卡片动态渐变色 */ /* 侧边栏个人信息卡片动态渐变色 */
#aside-content>.card-widget.card-info { #aside-content>.card-widget.card-info {
position: relative; position: relative;

View File

@@ -1,111 +0,0 @@
document.addEventListener("DOMContentLoaded", () => {
initializeCard();
});
document.addEventListener("pjax:complete", () => {
initializeCard();
});
function initializeCard() {
cardTimes();
cardRefreshTimes();
}
let year, month, week, date, dates, weekStr, monthStr, asideTime, asideDay, asideDayNum, animalYear, ganzhiYear, lunarMon, lunarDay;
const now = new Date();
function cardRefreshTimes() {
const e = document.getElementById("card-widget-schedule");
if (e) {
asideDay = (now - asideTime) / 1e3 / 60 / 60 / 24;
e.querySelector("#pBar_year").value = asideDay;
e.querySelector("#p_span_year").innerHTML = (asideDay / 365 * 100).toFixed(1) + "%";
e.querySelector(".schedule-r0 .schedule-d1 .aside-span2").innerHTML = `还剩<a> ${(365 - asideDay).toFixed(0)} </a>天`;
e.querySelector("#pBar_month").value = date;
e.querySelector("#pBar_month").max = dates;
e.querySelector("#p_span_month").innerHTML = (date / dates * 100).toFixed(1) + "%";
e.querySelector(".schedule-r1 .schedule-d1 .aside-span2").innerHTML = `还剩<a> ${(dates - date)} </a>天`;
e.querySelector("#pBar_week").value = week === 0 ? 7 : week;
e.querySelector("#p_span_week").innerHTML = ((week === 0 ? 7 : week) / 7 * 100).toFixed(1) + "%";
e.querySelector(".schedule-r2 .schedule-d1 .aside-span2").innerHTML = `还剩<a> ${(7 - (week === 0 ? 7 : week))} </a>天`;
}
}
function cardTimes() {
year = now.getFullYear();
month = now.getMonth();
week = now.getDay();
date = now.getDate();
const e = document.getElementById("card-widget-calendar");
if (e) {
const isLeapYear = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
weekStr = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][week];
const monthData = [
{ month: "1月", days: 31 },
{ month: "2月", days: isLeapYear ? 29 : 28 },
{ month: "3月", days: 31 },
{ month: "4月", days: 30 },
{ month: "5月", days: 31 },
{ month: "6月", days: 30 },
{ month: "7月", days: 31 },
{ month: "8月", days: 31 },
{ month: "9月", days: 30 },
{ month: "10月", days: 31 },
{ month: "11月", days: 30 },
{ month: "12月", days: 31 }
];
monthStr = monthData[month].month;
dates = monthData[month].days;
const t = (week + 8 - date % 7) % 7;
let n = "", d = false, s = 7 - t;
const o = (dates - s) % 7 === 0 ? Math.floor((dates - s) / 7) + 1 : Math.floor((dates - s) / 7) + 2;
const c = e.querySelector("#calendar-main");
const l = e.querySelector("#calendar-date");
l.style.fontSize = ["64px", "48px", "36px"][Math.min(o - 3, 2)];
for (let i = 0; i < o; i++) {
if (!c.querySelector(`.calendar-r${i}`)) {
c.innerHTML += `<div class='calendar-r${i}'></div>`;
}
for (let j = 0; j < 7; j++) {
if (i === 0 && j === t) {
n = 1;
d = true;
}
const r = n === date ? " class='now'" : "";
if (!c.querySelector(`.calendar-r${i} .calendar-d${j} a`)) {
c.querySelector(`.calendar-r${i}`).innerHTML += `<div class='calendar-d${j}'><a${r}>${n}</a></div>`;
}
if (n >= dates) {
n = "";
d = false;
}
if (d) {
n += 1;
}
}
}
const lunarDate = chineseLunar.solarToLunar(new Date(year, month, date));
animalYear = chineseLunar.format(lunarDate, "A");
ganzhiYear = chineseLunar.format(lunarDate, "T").slice(0, -1);
lunarMon = chineseLunar.format(lunarDate, "M");
lunarDay = chineseLunar.format(lunarDate, "d");
const newYearDate = new Date("2026/02/16 00:00:00");
const daysUntilNewYear = Math.floor((newYearDate - now) / 1e3 / 60 / 60 / 24);
asideTime = new Date(`${new Date().getFullYear()}/01/01 00:00:00`);
asideDay = (now - asideTime) / 1e3 / 60 / 60 / 24;
asideDayNum = Math.floor(asideDay);
const weekNum = week - asideDayNum % 7 >= 0 ? Math.ceil(asideDayNum / 7) : Math.ceil(asideDayNum / 7) + 1;
e.querySelector("#calendar-week").innerHTML = `${weekNum}周&nbsp;${weekStr}`;
e.querySelector("#calendar-date").innerHTML = date.toString().padStart(2, "0");
e.querySelector("#calendar-solar").innerHTML = `${year}${monthStr}&nbsp;第${asideDay.toFixed(0)}`;
e.querySelector("#calendar-lunar").innerHTML = `${ganzhiYear}${animalYear}年&nbsp;${lunarMon}${lunarDay}`;
document.getElementById("schedule-days").innerHTML = daysUntilNewYear;
}
}

View File

@@ -1,6 +1,5 @@
function renderTalks() { function renderTalks() {
const talkContainer = document.querySelector('#talk'); const talkContainer = document.querySelector('#talk');
const domain = 'https://mm.biss.click';
if (!talkContainer) return; if (!talkContainer) return;
talkContainer.innerHTML = ''; talkContainer.innerHTML = '';
const generateIconSVG = () => { const generateIconSVG = () => {
@@ -77,235 +76,162 @@ function renderTalks() {
}; };
const fetchAndRenderTalks = () => { const fetchAndRenderTalks = () => {
const url = 'https://mm.biss.click/api/memo/list'; const url = 'https://mm.biss.click/api/echo/page';
const cacheKey = 'talksCache'; const cacheKey = 'talksCache';
const cacheTimeKey = 'talksCacheTime'; const cacheTimeKey = 'talksCacheTime';
const cacheDuration = 30 * 60 * 1000; // 半个小时 (30 分钟) const cacheDuration = 30 * 60 * 1000;
const cachedData = localStorage.getItem(cacheKey); const cachedData = localStorage.getItem(cacheKey);
const cachedTime = localStorage.getItem(cacheTimeKey); const cachedTime = localStorage.getItem(cacheTimeKey);
const currentTime = new Date().getTime(); const now = Date.now();
// 判断缓存是否有效 if (cachedData && cachedTime && (now - cachedTime < cacheDuration)) {
if (cachedData && cachedTime && (currentTime - cachedTime < cacheDuration)) { renderTalksList(JSON.parse(cachedData));
const data = JSON.parse(cachedData);
renderTalks(data); // 使用缓存渲染数据
} else { } else {
if (talkContainer) {
talkContainer.innerHTML = '';
fetch(url, { fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: { 'Content-Type': 'application/json' },
'Content-Type': 'application/json', body: JSON.stringify({ page: 1, pageSize: 30 })
},
body: JSON.stringify({
size: 30
})
}) })
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.code === 0 && data.data && Array.isArray(data.data.list)) { if (data.code === 1 && data.data && Array.isArray(data.data.items)) {
// 缓存数据 localStorage.setItem(cacheKey, JSON.stringify(data.data.items));
localStorage.setItem(cacheKey, JSON.stringify(data.data.list)); localStorage.setItem(cacheTimeKey, now.toString());
localStorage.setItem(cacheTimeKey, currentTime.toString()); renderTalksList(data.data.items);
renderTalks(data.data.list); // 渲染数据
} }
}) })
.catch(error => { .catch(err => console.error('Error fetching:', err));
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 renderTalksList = (list) => {
list.map(formatTalk).forEach(item => talkContainer.appendChild(generateTalkElement(item)));
waterfall('#talk');
};
const formatTalk = (item, url) => { const formatTalk = (item) => {
let date = formatTime(new Date(item.createdAt).toString()); const date = formatTime(item.created_at);
let content = item.content; let content = item.content || '';
let imgs = item.imgs ? item.imgs.split(',') : []; content = content.replace(/\[(.*?)\]\((.*?)\)/g, `<a href="$2" target="_blank" rel="nofollow noopener">@$1</a>`)
let text = content;
content = text.replace(/\[(.*?)\]\((.*?)\)/g, `<a href="$2">@$1</a>`)
.replace(/- \[ \]/g, '⚪') .replace(/- \[ \]/g, '⚪')
.replace(/- \[x\]/g, '⚫'); .replace(/- \[x\]/g, '⚫')
// 保留换行符,转换 \n 为 <br> .replace(/\n/g, '<br>');
content = content.replace(/\n/g, '<br>');
// 将content用一个类包裹便于后续处理
content = `<div class="talk_content_text">${content}</div>`; content = `<div class="talk_content_text">${content}</div>`;
if (imgs.length > 0) {
// 图片
if (Array.isArray(item.images) && item.images.length > 0) {
const imgDiv = document.createElement('div'); const imgDiv = document.createElement('div');
imgDiv.className = 'zone_imgbox'; imgDiv.className = 'zone_imgbox';
imgs.forEach(e => { item.images.forEach(img => {
const imgLink = document.createElement('a'); const link = document.createElement('a');
const imgUrl = domain + e; link.href = img.image_url + "?fmt=webp&q=75";
imgLink.href = imgUrl; link.setAttribute('data-fancybox', 'gallery');
imgLink.setAttribute('data-fancybox', 'gallery'); link.className = 'fancybox';
imgLink.className = 'fancybox';
imgLink.setAttribute('data-thumb', e);
const imgTag = document.createElement('img'); const imgTag = document.createElement('img');
imgTag.src = domain + e; imgTag.src = img.image_url + "?fmt=webp&q=75";
imgLink.appendChild(imgTag); link.appendChild(imgTag);
imgDiv.appendChild(imgLink); imgDiv.appendChild(link);
}); });
content += imgDiv.outerHTML; content += imgDiv.outerHTML;
} }
// 外链分享功能 // 外链 / GitHub 项目
if (item.externalUrl) { // 外链 / GitHub 项目
const externalUrl = item.externalUrl; if (['WEBSITE', 'GITHUBPROJ'].includes(item.extension_type)) {
const externalTitle = item.externalTitle; let siteUrl = '', title = '';
const externalFavicon = item.externalFavicon; let extensionBack = "https://p.liiiu.cn/i/2024/07/27/66a4632bbf06e.webp";
const externalContainer = ` // 解析 extension 字段
try {
const extObj = typeof item.extension === 'string' ? JSON.parse(item.extension) : item.extension;
siteUrl = extObj.site || extObj.url || item.extension;
title = extObj.title || siteUrl;
} catch {
siteUrl = item.extension;
title = siteUrl;
}
// 特殊处理 GitHub 项目
if (item.extension_type === 'GITHUBPROJ') {
extensionBack = "https://p.liiiu.cn/i/2024/07/27/66a461a3098aa.webp";
// 提取 GitHub 项目名
const match = siteUrl.match(/^https?:\/\/github\.com\/[^/]+\/([^/?#]+)/i);
if (match) {
title = match[1]; // 获取仓库名
} else {
// fallback从最后一个路径段提取
try {
const parts = new URL(siteUrl).pathname.split('/').filter(Boolean);
title = parts.pop() || siteUrl;
} catch {
// 如果 URL 无效则保留原始
}
}
}
// 输出 HTML 结构
content += `
<div class="shuoshuo-external-link"> <div class="shuoshuo-external-link">
<a class="external-link" href="${externalUrl}" target="_blank" rel="external nofollow noopener noreferrer"> <a class="external-link" href="${siteUrl}" target="_blank" rel="nofollow noopener">
<div class="external-link-left" style="background-image: url(${externalFavicon})"></div> <div class="external-link-left" style="background-image:url(${extensionBack})"></div>
<div class="external-link-right"> <div class="external-link-right">
<div class="external-link-title">${externalTitle}</div> <div class="external-link-title">${title}</div>
<div>点击跳转<i class="fa-solid fa-angle-right"></i></div> <div>点击跳转<i class="fa-solid fa-angle-right"></i></div>
</div> </div>
</a> </a>
</div>`; </div>`;
content += externalContainer;
} }
const ext = JSON.parse(item.ext || '{}');
if (ext.music && ext.music.id) { // 音乐
const music = ext.music; if (item.extension_type === 'MUSIC' && item.extension) {
const musicUrl = music.api.replace(':server', music.server) const link = item.extension;
.replace(':type', music.type) let server = '';
.replace(':id', music.id); if (link.includes('music.163.com')) server = 'netease';
else if (link.includes('y.qq.com')) server = 'tencent';
const idMatch = link.match(/id=(\d+)/);
const id = idMatch ? idMatch[1] : '';
if (server && id) {
content += `<meting-js server="${server}" type="song" id="${id}" api="https://met.liiiu.cn/meting/api?server=:server&type=:type&id=:id&auth=:auth&r=:r"></meting-js>`;
}
}
// 视频
if (item.extension_type === 'VIDEO' && item.extension) {
const video = item.extension;
if (video.startsWith('BV')) {
const bilibiliUrl = `https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=${video}&as_wide=1&high_quality=1&danmaku=0`;
content += ` content += `
<meting-js server="${music.server}" type="${music.type}" id="${music.id}" api="${music.api}"></meting-js>
`;
}
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">
<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">
<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;
}
if (ext.video && ext.video.type) {
const videoType = ext.video.type;
const videoUrl = ext.video.value;
if (videoType === 'bilibili') {
// Bilibili 视频模板
// 从形如https://www.bilibili.com/video/BV1VGAPeAEMQ/?vd_source=91b3158d27d98ff41f842508c3794a13 的链接中提取视频 BV1VGAPeAEMQ
const biliTemplate = `
<div style="position: relative; padding: 30% 45%; margin-top: 10px;"> <div style="position: relative; padding: 30% 45%; margin-top: 10px;">
<iframe <iframe style="position:absolute;width:100%;height:100%;left:0;top:0;border-radius:12px;"
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;" src="${bilibiliUrl}"
src="${videoUrl}&autoplay=0"
scrolling="no"
frameborder="no" frameborder="no"
allowfullscreen> allowfullscreen="true"
</iframe> loading="lazy"></iframe>
</div> </div>`;
`; } else {
// 将模板插入到 DOM 中 const youtubeUrl = `https://www.youtube.com/embed/${video}`;
content += biliTemplate; content += `
} else if (videoType === 'youtube') {
// YouTube 视频模板
// 从形如https://youtu.be/2V6lvCUPT8I?si=DVhUas6l6qlAr6Ru的链接中提取视频 ID2V6lvCUPT8I
const youtubeTemplate = `
<div style="position: relative; padding: 30% 45%; margin-top: 10px;"> <div style="position: relative; padding: 30% 45%; margin-top: 10px;">
<iframe width="100%" <iframe style="position:absolute;width:100%;height:100%;left:0;top:0;border-radius:12px;"
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;" src="${youtubeUrl}"
src="${videoUrl}"
title="YouTube video player" title="YouTube video player"
frameborder="0" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
allowfullscreen> </div>`;
</iframe>
</div>
`;
// 将模板插入到 DOM 中
content += youtubeTemplate;
} }
} }
return { return {
content: content, content,
user: item.user.nickname || '匿名', user: item.username || '匿名',
avatar: item.user.avatarUrl || 'https://p.liiiu.cn/i/2024/03/29/66061417537af.png', avatar: 'https://p.liiiu.cn/i/2025/03/13/67d2fc82d329c.webp',
date: date, date,
location: item.location || '山西', location: '',
tags: item.tags ? item.tags.split(',').filter(tag => tag.trim() !== '') : ['无标签'], tags: Array.isArray(item.tags) && item.tags.length ? item.tags.map(t => t.name) : ['无标签'],
text: content.replace(/\[(.*?)\]\((.*?)\)/g, '[链接]' + `${imgs.length ? '[图片]' : ''}`) text: content.replace(/\[(.*?)\]\((.*?)\)/g, '[链接]')
}; };
}; };
@@ -315,21 +241,22 @@ function renderTalks() {
const talkMeta = document.createElement('div'); const talkMeta = document.createElement('div');
talkMeta.className = 'talk_meta'; talkMeta.className = 'talk_meta';
const avatar = document.createElement('img'); const avatar = document.createElement('img');
avatar.className = 'no-lightbox avatar'; avatar.className = 'no-lightbox avatar';
avatar.src = item.avatar; avatar.src = item.avatar;
const info = document.createElement('div'); const info = document.createElement('div');
info.className = 'info'; info.className = 'info';
const nick = document.createElement('span');
const talkNick = document.createElement('span'); nick.className = 'talk_nick';
talkNick.className = 'talk_nick'; nick.innerHTML = `${item.user} ${generateIconSVG()}`;
talkNick.innerHTML = `${item.user} ${generateIconSVG()}`; const date = document.createElement('span');
date.className = 'talk_date';
const talkDate = document.createElement('span'); date.textContent = item.date;
talkDate.className = 'talk_date'; info.appendChild(nick);
talkDate.textContent = item.date; info.appendChild(date);
talkMeta.appendChild(avatar);
talkMeta.appendChild(info);
const talkContent = document.createElement('div'); const talkContent = document.createElement('div');
talkContent.className = 'talk_content'; talkContent.className = 'talk_content';
@@ -337,38 +264,29 @@ function renderTalks() {
const talkBottom = document.createElement('div'); const talkBottom = document.createElement('div');
talkBottom.className = 'talk_bottom'; talkBottom.className = 'talk_bottom';
const tags = document.createElement('div');
const TagContainer = document.createElement('div'); const tag = document.createElement('span');
tag.className = 'talk_tag';
const talkTag = document.createElement('span'); tag.textContent = `🏷️${item.tags}`;
talkTag.className = 'talk_tag'; //const loc = document.createElement('span');
talkTag.textContent = `🏷️${item.tags}`; //loc.className = 'location_tag';
//loc.textContent = `🌍${item.location}`;
const locationTag = document.createElement('span'); tags.appendChild(tag);
locationTag.className = 'location_tag'; //tags.appendChild(loc);
locationTag.textContent = `🌍${item.location}`;
TagContainer.appendChild(talkTag);
TagContainer.appendChild(locationTag);
const commentLink = document.createElement('a'); const commentLink = document.createElement('a');
commentLink.href = 'javascript:;'; commentLink.href = 'javascript:;';
commentLink.onclick = () => goComment(item.text); commentLink.onclick = () => goComment(item.text);
const commentIcon = document.createElement('span'); const icon = document.createElement('span');
commentIcon.className = 'icon'; icon.className = 'icon';
const commentIconInner = document.createElement('i'); icon.innerHTML = '<i class="fa-solid fa-message fa-fw"></i>';
commentIconInner.className = 'fa-solid fa-message fa-fw'; commentLink.appendChild(icon);
commentIcon.appendChild(commentIconInner);
commentLink.appendChild(commentIcon); talkBottom.appendChild(tags);
talkBottom.appendChild(commentLink);
talkMeta.appendChild(avatar);
info.appendChild(talkNick);
info.appendChild(talkDate);
talkMeta.appendChild(info);
talkItem.appendChild(talkMeta); talkItem.appendChild(talkMeta);
talkItem.appendChild(talkContent); talkItem.appendChild(talkContent);
talkBottom.appendChild(TagContainer);
talkBottom.appendChild(commentLink);
talkItem.appendChild(talkBottom); talkItem.appendChild(talkBottom);
return talkItem; return talkItem;
@@ -377,28 +295,16 @@ function renderTalks() {
const goComment = (e) => { const goComment = (e) => {
const match = e.match(/<div class="talk_content_text">([\s\S]*?)<\/div>/); const match = e.match(/<div class="talk_content_text">([\s\S]*?)<\/div>/);
const textContent = match ? match[1] : ""; const textContent = match ? match[1] : "";
const n = document.querySelector(".tk-input el-textarea"); const textarea = document.querySelector("tk-input el-textarea");
n.value = `> ${textContent}\n\n`; textarea.value = `> ${textContent}\n\n`;
n.focus(); textarea.focus();
btf.snackbarShow("已为您引用该说说,不删除空格效果更佳"); btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
// const n = document.querySelector(".atk-textarea");
// n.value = `> ${e}\n\n`;
// n.focus();
// btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
}; };
const formatTime = (time) => { const formatTime = (time) => {
const d = new Date(time); const d = new Date(time);
const ls = [ const pad = (n) => n.toString().padStart(2, '0');
d.getFullYear(), return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
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(); fetchAndRenderTalks();

View File

@@ -0,0 +1,97 @@
let talkTimer = null;
const cacheKey = 'talksCache';
const cacheTimeKey = 'talksCacheTime';
const cacheDuration = 30 * 60 * 1000; // 缓存有效期 30分钟
function indexTalk() {
if (talkTimer) {
clearInterval(talkTimer);
talkTimer = null;
}
if (!document.getElementById('bber-talk')) return;
function toText(ls) {
return ls.map(item => {
let c = item.content || '';
const hasImg = /\!\[.*?\]\(.*?\)/.test(c);
const hasLink = /\[.*?\]\(.*?\)/.test(c);
c = c
.replace(/#(.*?)\s/g, '')
.replace(/\{.*?\}/g, '')
.replace(/\!\[.*?\]\(.*?\)/g, '<i class="fa-solid fa-image"></i>')
.replace(/\[.*?\]\(.*?\)/g, '<i class="fa-solid fa-link"></i>');
const icons = [];
if (item.images?.length && !hasImg) icons.push('fa-solid fa-image');
if (item.extension_type === 'VIDEO') icons.push('fa-solid fa-video');
if (item.extension_type === 'MUSIC') icons.push('fa-solid fa-music');
if (item.extension_type === 'WEBSITE' && !hasLink) icons.push('fa-solid fa-link');
if (item.extension_type === 'GITHUBPROJ' && !hasLink) icons.push('fab fa-github');
if (icons.length) c += ' ' + icons.map(i => `<i class="${i}"></i>`).join(' ');
return c;
});
}
// 渲染与轮播
function talk(ls) {
let html = '';
ls.forEach((item, i) => {
html += `<li class="item item-${i + 1}">${item}</li>`;
});
let box = document.querySelector("#bber-talk .talk-list");
if (!box) return;
box.innerHTML = html;
talkTimer = setInterval(() => {
if (box.children.length > 0) {
box.appendChild(box.children[0]);
}
}, 3000);
}
const cachedData = localStorage.getItem(cacheKey);
const cachedTime = localStorage.getItem(cacheTimeKey);
const currentTime = new Date().getTime();
// 判断缓存是否有效
if (cachedData && cachedTime && (currentTime - cachedTime < cacheDuration)) {
const data = toText(JSON.parse(cachedData));
talk(data.slice(0, 6)); // 使用缓存渲染数据
} else {
fetch('https://mm.biss.click/api/echo/page', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ page: 1, pageSize: 30 })
})
.then(res => res.json())
.then(data => {
// 适配新版结构code=1 且 data.items 存在
if (data.code === 1 && data.data && Array.isArray(data.data.items)) {
localStorage.setItem(cacheKey, JSON.stringify(data.data.items));
localStorage.setItem(cacheTimeKey, currentTime.toString());
const formattedData = toText(data.data.items);
talk(formattedData.slice(0, 6));
} else {
console.warn('Unexpected API response format:', data);
}
})
.catch(error => console.error('Error fetching data:', error));
}
}
// pjax 支持
function whenDOMReady() {
indexTalk();
}
whenDOMReady();
document.addEventListener("pjax:complete", whenDOMReady);