重新整理了一下目录,更改了部分内容的实现方式
This commit is contained in:
浪子
2025-03-17 08:13:35 +08:00
parent 81af4b6590
commit 5c91195745
39 changed files with 461 additions and 297 deletions
+120
View File
@@ -0,0 +1,120 @@
;
(() => {
var farallonHelper = class {
getCookie(t) {
if (0 < document.cookie.length) {
var e = document.cookie.indexOf(t + "=");
if (-1 != e) {
e = e + t.length + 1;
var n = document.cookie.indexOf(";", e);
return -1 == n && (n = document.cookie.length), document.cookie.substring(e, n);
}
}
return "";
}
};
var farallonBase = class extends farallonHelper {
is_single = false;
post_id = 0;
is_archive = false;
VERSION = "0.7.0";
constructor() {
super();
this.initCopyright();
this.initThemeSwitch();
this.initBack2Top();
this.initSearch();
}
initSearch() {
document.querySelector('[data-action="show-search"]').addEventListener("click", () => {
document.querySelector(".site--header__center .inner").classList.toggle("search--active");
});
}
initBack2Top() {
if (document.querySelector(".backToTop")) {
const backToTop = document.querySelector(
".backToTop"
);
window.addEventListener("scroll", () => {
const t = window.scrollY || window.pageYOffset;
t > 200 ? backToTop.classList.add("is-active") : backToTop.classList.remove("is-active");
});
backToTop.addEventListener("click", () => {
window.scrollTo({ top: 0, behavior: "smooth" });
});
}
}
initCopyright() {
const copyright = `<div class="site--footer__info">由<a href="https://www.typecho.org" target="_blank">Typecho</a> 驱动 <br>
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa &nbsp;<br>Made with<a href="https://www.imsun.org" target="_blank"> Sun</a> / version ${this.VERSION}
</div>`;
document.querySelector(".site--footer__content").insertAdjacentHTML("afterend", copyright);
document.querySelector(".icon--copryrights").addEventListener("click", () => {
document.querySelector(".site--footer__info").classList.toggle("active");
});
}
initThemeSwitch() {
const theme = localStorage.getItem("theme") ? localStorage.getItem("theme") : "auto";
const html = `<div class="fixed--theme">
<span class="${theme == "dark" ? "is-active" : ""}" data-action-value="dark">
<svg fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"
style="color: currentcolor; width: 16px; height: 16px;">
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"></path>
</svg>
</span>
<span class="${theme == "light" ? "is-active" : ""}" data-action-value="light">
<svg fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"
style="color: currentcolor; width: 16px; height: 16px;">
<circle cx="12" cy="12" r="5"></circle>
<path d="M12 1v2"></path>
<path d="M12 21v2"></path>
<path d="M4.22 4.22l1.42 1.42"></path>
<path d="M18.36 18.36l1.42 1.42"></path>
<path d="M1 12h2"></path>
<path d="M21 12h2"></path>
<path d="M4.22 19.78l1.42-1.42"></path>
<path d="M18.36 5.64l1.42-1.42"></path>
</svg>
</span>
<span class="${theme == "auto" ? "is-active" : ""}" data-action-value="auto">
<svg fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"
style="color: currentcolor; width: 16px; height: 16px;">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
<path d="M8 21h8"></path>
<path d="M12 17v4"></path>
</svg>
</span>
</div>`;
document.querySelector("body").insertAdjacentHTML("beforeend", html);
document.querySelectorAll(".fixed--theme span").forEach((item) => {
item.addEventListener("click", () => {
if (item.classList.contains("is-active"))
return;
document.querySelectorAll(".fixed--theme span").forEach((item2) => {
item2.classList.remove("is-active");
});
if (item.dataset.actionValue == "dark") {
localStorage.setItem("theme", "dark");
document.querySelector("body").classList.remove("auto");
document.querySelector("body").classList.add("dark");
item.classList.add("is-active");
} else if (item.dataset.actionValue == "light") {
localStorage.setItem("theme", "light");
document.querySelector("body").classList.remove("auto");
document.querySelector("body").classList.remove("dark");
item.classList.add("is-active");
} else if (item.dataset.actionValue == "auto") {
localStorage.setItem("theme", "auto");
document.querySelector("body").classList.remove("dark");
document.querySelector("body").classList.add("auto");
item.classList.add("is-active");
}
});
});
}
};
new farallonBase();
})();
+350
View File
@@ -0,0 +1,350 @@
class Douban {
constructor(config) {
this.container = config.container;
this.types = config.types ?? [
"movie",
"book",
"music",
"game",
"drama",
];
this.baseAPI = config.baseAPI;
this.ver = "1.0.6";
this.type = "movie";
this.status = "done";
this.finished = false;
this.paged = 1;
this.genre_list = [
{
name: "已看",
value: "done",
},
{
name: "在看",
value: "doing",
},
{
name: "想看",
value: "mark",
},
];
this.subjects = [];
this._create();
}
on(event, element, callback) {
const nodeList = document.querySelectorAll(element);
nodeList.forEach((item) => {
item.addEventListener(event, callback);
});
}
_handleGenreClick() {
this.on("click", ".db--genreItem", (t) => {
const self = t.currentTarget;
if (self.classList.contains("is-active")) {
return;
}
document.querySelector(".db--list").innerHTML = "";
document.querySelector(".lds-ripple").classList.remove("u-hide");
this.status = self.dataset.status || ""; // Provide a default value of an empty string if self.dataset.status is undefined
this._renderGenre();
this.paged = 1;
this.finished = false;
this.subjects = [];
this._fetchData();
});
}
_reanderTypes() {
document.querySelector(".db--nav").innerHTML = this.types
.map((item) => {
return `<span class="db--navItem JiEun${
this.type == item ? " current" : ""
}" data-type="${item}">${item}</span>`;
})
.join("");
this._handleNavClick();
}
_renderGenre() {
document.querySelector(".db--genres").innerHTML = this.genre_list
.map((item) => {
return `<span class="db--genreItem${
this.status == item.value ? " is-active" : ""
}" data-status="${item.value}">${item.name}</span>`;
})
.join("");
this._handleGenreClick();
}
_fetchData() {
const params = new URLSearchParams({
paged: this.paged.toString(),
type: this.type,
status: this.status,
});
fetch(this.baseAPI + "list?" + params.toString())
.then((response) => response.json())
.then((t) => {
console.log(t.results);
if (t.results.length) {
if (
document
.querySelector(".db--list")
.classList.contains("db--list__card")
) {
this.subjects = [...this.subjects, ...t.results];
this._randerDateTemplate();
} else {
this.subjects = [...this.subjects, ...t.results];
this._randerListTemplate();
}
document
.querySelector(".lds-ripple")
.classList.add("u-hide");
} else {
this.finished = true;
document
.querySelector(".lds-ripple")
.classList.add("u-hide");
}
});
}
_randerDateTemplate() {
const result = this.subjects.reduce((result, item) => {
const date = new Date(item.create_time);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const key = `${year}-${month.toString().padStart(2, "0")}`;
if (Object.prototype.hasOwnProperty.call(result, key)) {
result[key].push(item);
} else {
result[key] = [item];
}
return result;
}, {});
let html = ``;
for (let key in result) {
const date = key.split("-");
html += `<div class="db--listBydate"><div class="db--titleDate"><div class="db--titleDate__day">${date[1]}</div><div class="db--titleDate__month">${date[0]}</div></div><div class="db--dateList__card">`;
html += result[key]
.map((movie) => {
return `<div class="db--item${
this.type == "music" ? " db--item__music" : ""
}"><img src="${
movie.poster
}" referrerpolicy="no-referrer" class="db--image"><div class="db--score ">${
movie.douban_score > 0
? '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" ><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>' +
movie.douban_score
: ""
}${
movie.year > 0 ? " · " + movie.year : ""
}</div><div class="db--title"><a href="${
movie.link
}" target="_blank">${movie.name}</a></div></div>`;
})
.join("");
html += `</div></div>`;
}
document.querySelector(".db--list").innerHTML = html;
}
_randerListTemplate() {
document.querySelector(".db--list").innerHTML = this.subjects
.map((item) => {
return `<div class="db--item"><img src="${
item.poster
}" referrerpolicy="no-referrer" class="db--image"><div class="ipc-signpost ">${
item.create_time
}</div><div class="db--score ">${
item.douban_score
? '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" ><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>' +
item.douban_score
: ""
}${
item.year ? " · " + item.year : ""
}</div><div class="db--title"><a href="${
item.link
}" target="_blank">${item.name}</a></div>
</div>
</div>`;
})
.join("");
}
_handleScroll() {
window.addEventListener("scroll", () => {
var t = window.scrollY || window.pageYOffset;
const moreElement = document.querySelector(
".block-more"
);
if (
moreElement.offsetTop + -window.innerHeight < t &&
document
.querySelector(".lds-ripple")
.classList.contains("u-hide") &&
!this.finished
) {
document
.querySelector(".lds-ripple")
.classList.remove("u-hide");
this.paged++;
this._fetchData();
}
});
}
_handleNavClick() {
this.on("click", ".db--navItem", (t) => {
const self = t.currentTarget;
if (self.classList.contains("current")) return;
this.status = "done";
this.type = self.dataset.type;
this._renderGenre();
document.querySelector(".db--list").innerHTML = "";
document.querySelector(".lds-ripple").classList.remove("u-hide");
document
.querySelector(".db--navItem.current")
.classList .remove("current");
self.classList.add("current");
this.paged = 1;
this.finished = false;
this.subjects = [];
this._fetchData();
});
}
_create() {
if (document.querySelector(".db--container")) {
const container = document.querySelector(
this.container
);
if (!container) return;
container.innerHTML = `<nav class="db--nav">
</nav>
<div class="db--genres">
</div>
<div class="db--list db--list__card">
</div>
<div class="block-more block-more__centered">
<div class="lds-ripple">
</div>
</div>`;
this._renderGenre();
this._reanderTypes();
this._fetchData();
this._handleScroll();
}
if (document.querySelector(".js-db")) {
document.querySelectorAll(".js-db").forEach((item) => {
const db = item;
const id = db.dataset.id;
const type = db.dataset.type;
const nodeParent = db.parentNode;
fetch(this.baseAPI + `${type}/${id}`).then((response) => {
response.json().then((t) => {
if (t.data) {
const data = t.data;
const node = document.createElement("div");
node.classList.add("doulist-item");
node.innerHTML = `<div class="doulist-subject">
<div class="doulist-post"><img decoding="async" referrerpolicy="no-referrer" src="${data.poster}"></div>
<div class="doulist-content">
<div class="doulist-title"><a href="${data.link}" class="cute" target="_blank" rel="external nofollow">${data.name}</a></div>
<div class="rating"><span class="allstardark"><span class="allstarlight" style="width:55%"></span></span><span class="rating_nums"> ${data.douban_score} </span></div>
<div class="abstract">${data.card_subtitle}</div>
</div>
</div>`;
nodeParent.replaceWith(node);
}
});
});
});
}
if (document.querySelector(".db--collection")) {
document
.querySelectorAll(".db--collection")
.forEach((item) => {
this._fetchCollection(item);
});
}
}
_fetchCollection(item) {
const type = item.dataset.style ? item.dataset.style : "card";
fetch(
this.baseAPI +
"/list?type=" +
item.dataset.type +
"&paged=1&start_time=" +
item.dataset.start +
"&end_time=" +
item.dataset.end
)
.then((response) => response.json())
.then((t) => {
if (t.length) {
if (type == "card") {
item.innerHTML += t
.map((movie) => {
return `<div class="doulist-item">
<div class="doulist-subject">
<div class="db--viewTime ">Marked ${movie.create_time}</div>
<div class="doulist-post"><img referrerpolicy="no-referrer" src="${movie.poster}"></div><div class="doulist-content"><div class="doulist-title"><a href="${movie.link}" class="cute" target="_blank" rel="external nofollow">${movie.name}</a></div><div class="rating"><span class="allstardark"><span class="allstarlight" style="width:75%"></span></span><span class="rating_nums">${movie.douban_score}</span></div><div class="abstract">${movie.card_subtitle}</div></div></div></div>`;
})
.join("");
} else {
const result = t.reduce(
(result, item) => {
if (
Object.prototype.hasOwnProperty.call(
result,
item.create_time
)
) {
result[item.create_time].push(item);
} else {
result[item.create_time] = [item];
}
return result;
},
{}
);
let html = ``;
for (let key in result) {
html += `<div class="db--date">${key}</div><div class="db--dateList">`;
html += result[key]
.map((movie) => {
return `<div class="db--card__list">
<img referrerpolicy="no-referrer" src="${
movie.poster
}">
<div>
<div class="title"><a href="${
movie.link
}" class="cute" target="_blank" rel="external nofollow">${
movie.name
}</a></div>
<div class="rating"><span class="allstardark"><span class="allstarlight" style="width:75%"></span></span><span class="rating_nums">${
movie.douban_score
}</span></div>
${movie.remark || movie.card_subtitle}
</div>
</div>`;
})
.join("");
html += `</div>`;
}
item.innerHTML = html;
}
}
});
}
}
+65
View File
@@ -0,0 +1,65 @@
document.addEventListener('DOMContentLoaded', function() {
const donateBtn = document.getElementById('donate-btn');
const qrcodePanel = document.getElementById('qrcode-panel');
const donateClose = document.getElementById('donate-close');
const methodBtns = document.querySelectorAll('.donate-method-btn');
const qrImages = document.querySelectorAll('.qr-image');
let isVisible = false;
// 切换支付方式
function switchPayMethod(method) {
// 更新按钮状态
methodBtns.forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.method === method) {
btn.classList.add('active');
}
});
// 更新二维码显示
qrImages.forEach(img => {
img.classList.remove('active');
if (img.dataset.method === method) {
img.classList.add('active');
}
});
}
// 点击打赏按钮切换二维码显示状态
function toggleQRCode(event) {
event.stopPropagation();
isVisible = !isVisible;
qrcodePanel.style.display = isVisible ? 'block' : 'none';
}
// 点击关闭按钮隐藏二维码
function hideQRCode(event) {
event.stopPropagation();
isVisible = false;
qrcodePanel.style.display = 'none';
}
// 点击二维码面板之外的地方隐藏二维码
function handleDocumentClick(event) {
if (isVisible && !qrcodePanel.contains(event.target) && !donateBtn.contains(event.target)) {
isVisible = false;
qrcodePanel.style.display = 'none';
}
}
// 绑定事件监听器
donateBtn.addEventListener('click', toggleQRCode);
donateClose.addEventListener('click', hideQRCode);
document.addEventListener('click', handleDocumentClick);
// 绑定支付方式切换按钮事件
methodBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
const method = e.target.dataset.method;
switchPayMethod(method);
});
});
// 初始化显示第一个支付方式
switchPayMethod('wechat');
});
File diff suppressed because one or more lines are too long
+6
View File
File diff suppressed because one or more lines are too long
+142
View File
@@ -0,0 +1,142 @@
class NeoDB {
constructor(config) {
this.container = config.container;
this.types = config.types ?? ["book", "movie", "tv", "music", "game", "podcast"];
this.baseAPI = config.baseAPI;
this.type = "movie";
this.status = "complete";
this.finished = false;
this.paged = 1;
this.subjects = [];
this._create();
}
on(event, element, callback) {
const nodeList = document.querySelectorAll(element);
nodeList.forEach((item) => {
item.addEventListener(event, callback);
});
}
_handleTypeClick() {
this.on("click", ".neodb-navItem", (t) => {
const self = t.currentTarget;
if (self.classList.contains("current")) return;
this.type = self.dataset.type;
document.querySelector(".neodb-list").innerHTML = "";
document.querySelector(".lds-ripple").classList.remove("u-hide");
document.querySelector(".neodb-navItem.current").classList.remove("current");
self.classList.add("current");
this.paged = 1;
this.finished = false;
this.subjects = [];
this._fetchData();
});
}
_renderTypes() {
document.querySelector(".neodb-nav").innerHTML = this.types
.map((item) => {
return `<span class="neodb-navItem${
this.type == item ? " current" : ""
}" data-type="${item}">${item}</span>`;
})
.join("");
this._handleTypeClick();
}
_fetchData() {
const params = new URLSearchParams({
type: "complete",
category: this.type,
page: this.paged.toString(),
});
return fetch(this.baseAPI + "?" + params.toString())
.then((response) => response.json())
.then((data) => {
if (data.length) {
// 过滤重复项
data = data.filter(item => !this.subjects.some(existing => existing.item.id === item.item.id));
if (data.length) {
this.subjects = [...this.subjects, ...data];
this._renderListTemplate();
}
document.querySelector(".lds-ripple").classList.add("u-hide");
} else {
this.finished = true; // 没有更多数据
document.querySelector(".lds-ripple").classList.add("u-hide");
}
});
}
_renderListTemplate() {
document.querySelector(".neodb-list").innerHTML = this.subjects
.map((item) => {
const coverImage = item.item.cover_image_url;
const title = item.item.title;
const rating = item.item.rating;
const link = item.item.id;
return `<div class="neodb-item">
<img src="${coverImage}" referrerpolicy="no-referrer" class="neodb-image">
<div class="neodb-score">
${rating ? `<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>${rating}` : ""}
</div>
<div class="neodb-title">
<a href="${link}" target="_blank">${title}</a>
</div>
</div>`;
})
.join("");
}
_handleScroll() {
let isLoading = false; // 标志位,表示是否正在加载数据
let lastScrollTop = 0; // 上一次的滚动位置
window.addEventListener("scroll", () => {
const scrollY = window.scrollY || window.pageYOffset;
const moreElement = document.querySelector(".block-more");
// 检查滚动到底部的条件
if (
moreElement.offsetTop + moreElement.clientHeight <= scrollY + window.innerHeight &&
document.querySelector(".lds-ripple").classList.contains("u-hide") &&
!this.finished &&
!isLoading // 确保没有正在加载数据
) {
isLoading = true; // 设置标志位为 true,表示正在加载数据
document.querySelector(".lds-ripple").classList.remove("u-hide");
this.paged++;
this._fetchData().finally(() => {
isLoading = false; // 数据加载完成后,重置标志位
});
}
// 更新上一次的滚动位置
lastScrollTop = scrollY;
});
}
_create() {
if (document.querySelector(".neodb-container")) {
const container = document.querySelector(this.container);
if (!container) return;
container.innerHTML = `
<nav class="neodb-nav"></nav>
<div class="neodb-list"></div>
<div class="block-more block-more__centered">
<div class="lds-ripple"></div>
</div>
`;
this._renderTypes();
this._fetchData();
this._handleScroll();
}
}
}
+186
View File
@@ -0,0 +1,186 @@
document.addEventListener('DOMContentLoaded', function() {
const tooltip = document.getElementById('copyTooltip');
let timeoutId = null;
// 确保初始状态下提示框是隐藏的
tooltip.style.display = 'none';
// 复制函数
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
// 显示提示
tooltip.style.display = 'block';
tooltip.style.opacity = '1';
// 清除之前的定时器(如果存在)
if (timeoutId) clearTimeout(timeoutId);
// 设置新的定时器
timeoutId = setTimeout(() => {
tooltip.style.opacity = '0';
setTimeout(() => {
tooltip.style.display = 'none';
}, 300); // 等待淡出动画完成后再隐藏
}, 1500);
}).catch(err => {
tooltip.textContent = '复制失败,请重试';
tooltip.style.display = 'block';
tooltip.style.opacity = '1';
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
tooltip.style.opacity = '0';
setTimeout(() => {
tooltip.style.display = 'none';
tooltip.textContent = '复制成功!'; // 重置文本
}, 300);
}, 1500);
console.error('复制失败:', err);
});
}
// 给所有复制链接添加点击事件
document.querySelectorAll('.text').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const textToCopy = this.getAttribute('data-copy') || this.textContent;
copyToClipboard(textToCopy);
});
});
});
document.addEventListener('DOMContentLoaded', (event) => {
const targetClassElement = document.querySelector('.post--single__title');
const postContent = document.querySelector('.post--single__content');
if (!postContent) return;
let found = false;
for (let i = 1; i <= 6 &&!found; i++) {
if (postContent.querySelector(`h${i}`)) {
found = true;
}
}
if (!found) return;
const heads = postContent.querySelectorAll('h1, h2, h3, h4, h5, h6');
const toc = document.createElement('div');
toc.id = 'toc';
toc.innerHTML = '<details class="toc" open><summary class="toc-title">目录</summary><nav id="TableOfContents"><ul></ul></nav></details>';
// 插入到指定 class 元素之后
if (targetClassElement) {
targetClassElement.parentNode.insertBefore(toc, targetClassElement.nextSibling);
}
let currentLevel = 0;
let currentList = toc.querySelector('ul');
let levelCounts = [0];
heads.forEach((head, index) => {
const level = parseInt(head.tagName.substring(1));
if (levelCounts[level] === undefined) {
levelCounts[level] = 1;
} else {
levelCounts[level]++;
}
// 重置下级标题的计数器
levelCounts = levelCounts.slice(0, level + 1);
if (currentLevel === 0) {
currentLevel = level;
}
while (level > currentLevel) {
let newList = document.createElement('ul');
if (!currentList.lastElementChild) {
currentList.appendChild(newList);
} else {
currentList.lastElementChild.appendChild(newList);
}
currentList = newList;
currentLevel++;
levelCounts[currentLevel] = 1;
}
while (level < currentLevel) {
currentList = currentList.parentElement;
if (currentList.tagName.toLowerCase() === 'li') {
currentList = currentList.parentElement;
}
currentLevel--;
}
const anchor = head.textContent.trim().replace(/\s+/g, '-');
head.id = anchor;
const item = document.createElement('li');
const link = document.createElement('a');
link.href = `#${anchor}`;
link.textContent = `${head.textContent}`;
link.style.textDecoration = 'none';
item.appendChild(link);
currentList.appendChild(item);
});
});
function fetchWithRetry(url, retries = 3) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text(); // 首先获取文本响应
})
.then(text => {
try {
return JSON.parse(text); // 尝试解析 JSON
} catch (e) {
console.error('Invalid JSON:', text);
throw new Error('Invalid JSON response');
}
})
.catch(error => {
if (retries > 0) {
console.log(`Retrying... (${retries} attempts left)`);
return new Promise(resolve => setTimeout(resolve, 1000)) // 等待1秒
.then(() => fetchWithRetry(url, retries - 1));
}
throw error;
});
}
document.addEventListener('DOMContentLoaded', function() {
const doubanLinks = document.querySelectorAll('a[href^="https://movie.douban.com/subject/"]');
doubanLinks.forEach(link => {
const url = link.href;
const movieId = url.match(/subject\/(\d+)/)[1];
link.innerHTML += ' <span class="loading">(加载中...)</span>';
fetchWithRetry(`https://api.loliko.cn/movies/${movieId}`)
.then(data => {
const movieInfo = createMovieInfoHTML(data, url);
const wrapper = document.createElement('div');
wrapper.innerHTML = movieInfo;
link.parentNode.replaceChild(wrapper, link);
})
.catch(error => {
console.error('Error fetching movie data:', error);
// 显示错误消息给用户
link.innerHTML = `<span style="color: red;">加载失败</span> <a href="${url}" target="_blank">查看豆瓣电影详情</a>`;
})
.finally(() => {
const loadingSpan = link.querySelector('.loading');
if (loadingSpan) {
loadingSpan.remove();
}
});
});
});
function createMovieInfoHTML(data, originalUrl) {
if (!data || data.error || Object.keys(data).length === 0) {
return `<a href="${originalUrl}" target="_blank">查看豆瓣电影详情</a>`;
}
return `
<div class=doulist-item>
<div class=doulist-subject>
<div class=doulist-post>
<img decoding=async referrerpolicy=no-referrer src=${data.img}>
</div>
<div class=doulist-content>
<div class=doulist-title>
<a href="${originalUrl}" class=cute target="_blank" rel="external nofollow"> ${data.name} </a>
</div>
<div class=rating>
<span class=rating_nums>豆瓣评分 : ${data.rating}</span>
</div>
<div class=abstract>
${data.year}年 · ${data.country} · ${data.genre} · 导演: ${data.director} · 演员 : ${data.actor}
</div>
</div>
</div>
</div>
`;
}