AttachHowOldtoUserinPosts

Show how old a user is in posts

当前为 2025-02-08 提交的版本,查看 最新版本

// ==UserScript==
// @name         AttachHowOldtoUserinPosts
// @namespace    https://jirehlov.com
// @version      2.1
// @description  Show how old a user is in posts
// @author       Jirehlov
// @match        https://bgm.tv/*
// @match        https://chii.in/*
// @match        https://bangumi.tv/*
// @grant        none
// @license      MIT
// ==/UserScript==
(function () {
	const delay = 4000;
	const ageColors = [
		{
			threshold: 2,
			color: "#FFC966"
		},
		{
			threshold: 5,
			color: "#FFA500"
		},
		{
			threshold: 10,
			color: "#F09199"
		},
		{
			threshold: Infinity,
			color: "#FF0000"
		}
	];
	let requestCount = 0;
	let usersToFetch = [];
	const sortedUserIds = Object.keys(localStorage).filter(key => key.startsWith("userAge_")).map(key => key.replace("userAge_", "")).filter(value => Number.isInteger(parseInt(value, 10))).map(value => parseInt(value, 10)).sort((a, b) => a - b);
	function calculateAge(birthDate) {
		const [year, month, day] = birthDate.split("-").map(num => num.padStart(2, "0"));
		const d = new Date(`${ year }-${ month }-${ day }T00:00:00+08:00`);
		const now = new Date();
		let age = now.getUTCFullYear() - d.getUTCFullYear();
		if (now.getUTCMonth() < d.getUTCMonth() || now.getUTCMonth() === d.getUTCMonth() && now.getUTCDate() <= d.getUTCDate())
			age--;
		return age;
	}
	function findClosestMatchingDates(userId) {
		let lower = -1, upper = -1;
		for (let i = 0; i < sortedUserIds.length; i++) {
			if (sortedUserIds[i] < userId) {
				lower = sortedUserIds[i];
			}
			if (sortedUserIds[i] > userId) {
				upper = sortedUserIds[i];
				break;
			}
		}
		if (lower !== -1 && upper !== -1) {
			let lowerDate = localStorage.getItem("userAge_" + lower);
			let upperDate = localStorage.getItem("userAge_" + upper);
			if (lowerDate === upperDate) {
				return lowerDate;
			}
		}
		return null;
	}
	function fetchAndStoreUserAge(userLink, delayTime) {
		setTimeout(() => {
			fetch(userLink, { credentials: "omit" }).then(response => response.text()).then(data => {
				const parser = new DOMParser();
				const doc = parser.parseFromString(data, "text/html");
				let registrationDate = doc.querySelector("ul.network_service li:first-child span.tip")?.textContent?.replace(/加入/g, "").trim();
				if (registrationDate) {
					const userId = userLink.split("/").pop();
					localStorage.setItem("userAge_" + userId, registrationDate);
					displayUserAge(userId, registrationDate);
				}
			}).catch(console.error);
		}, delayTime);
	}
	function displayUserAge(userId, registrationDate) {
		const userAnchor = $("strong a.l[href$='/user/" + userId + "']");
		if (userAnchor.length > 0 && userAnchor.next(".age-badge").length === 0) {
			const userAge = calculateAge(registrationDate);
			if (!isNaN(userAge)) {
				let badgeColor = ageColors.find(color => userAge <= color.threshold).color;
				const badge = $(`
                <span class="age-badge" style="
                    background-color: ${ badgeColor };
                    font-size: 11px;
                    padding: 2px 5px;
                    color: #FFF;
                    border-radius: 100px;
                    line-height: 150%;
                    display: inline-block;
                    position: relative;
                    cursor: pointer;
                ">${ userAge }年
                    <span class="tooltip" style="
                        visibility: hidden;
                        background-color: rgba(0, 0, 0, 0.75);
                        color: #fff;
                        text-align: center;
                        padding: 5px 8px;
                        border-radius: 5px;
                        position: absolute;
                        bottom: 150%;
                        left: 50%;
                        transform: translateX(-50%);
                        white-space: nowrap;
                        font-size: 12px;
                        opacity: 0;
                        transition: opacity 0.3s;
                        z-index: 1000;
                    ">${ registrationDate }</span>
                </span>
            `);
				badge.hover(function () {
					$(this).find(".tooltip").css({
						visibility: "visible",
						opacity: "1"
					});
				}, function () {
					$(this).find(".tooltip").css({
						visibility: "hidden",
						opacity: "0"
					});
				});
				userAnchor.after(badge);
			}
		}
	}
	function importUserAges() {
		const input = document.createElement("input");
		input.type = "file";
		input.accept = "application/json";
		input.onchange = function (event) {
			const file = event.target.files[0];
			if (file) {
				const reader = new FileReader();
				reader.onload = function (e) {
					try {
						const userAges = JSON.parse(e.target.result);
						Object.keys(userAges).forEach(key => {
							const storageKey = key.startsWith("userAge_") ? key : "userAge_" + key;
							localStorage.setItem(storageKey, userAges[key]);
						});
						alert("导入成功");
					} catch (error) {
						alert("无效的JSON文件\uFF1A", error);
					}
				};
				reader.readAsText(file);
			}
		};
		input.click();
	}
	function exportUserAges() {
		const userAges = {};
		Object.keys(localStorage).forEach(key => {
			if (key.startsWith("userAge_")) {
				userAges[key.replace("userAge_", "")] = localStorage.getItem(key);
			}
		});
		const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
		const entryCount = Object.keys(userAges).length;
		const filename = `userAges_${ timestamp }_${ entryCount }entries.json`;
		const blob = new Blob([JSON.stringify(userAges, null, 2)], { type: "application/json" });
		const url = URL.createObjectURL(blob);
		const a = document.createElement("a");
		a.href = url;
		a.download = filename;
		a.click();
		URL.revokeObjectURL(url);
	}
	function clearUserAges() {
		Object.keys(localStorage).forEach(key => {
			if (key.startsWith("userAge_")) {
				localStorage.removeItem(key);
			}
		});
		alert("所有用户生日数据已清除");
	}
	const badgeUserPanel = document.querySelector("ul#badgeUserPanel");
	if (badgeUserPanel) {
		const importButton = document.createElement("a");
		importButton.href = "#";
		importButton.textContent = "导入用户生日数据";
		importButton.onclick = event => {
			event.preventDefault();
			importUserAges();
		};
		const exportButton = document.createElement("a");
		exportButton.href = "#";
		exportButton.textContent = "导出用户生日数据";
		exportButton.onclick = event => {
			event.preventDefault();
			exportUserAges();
		};
		const clearButton = document.createElement("a");
		clearButton.href = "#";
		clearButton.textContent = "清除用户生日数据";
		clearButton.onclick = event => {
			event.preventDefault();
			clearUserAges();
		};
		const listItem = document.createElement("li");
		listItem.appendChild(importButton);
		badgeUserPanel.appendChild(listItem);
		const exportListItem = document.createElement("li");
		exportListItem.appendChild(exportButton);
		badgeUserPanel.appendChild(exportListItem);
		const clearListItem = document.createElement("li");
		clearListItem.appendChild(clearButton);
		badgeUserPanel.appendChild(clearListItem);
	}
	$("strong a.l:not(.avatar)").each(function () {
		const userLink = $(this).attr("href");
		const userId = userLink.split("/").pop();
		const avatarMatch = $(this).closest("div.inner").prev("a.avatar").find("span.avatarNeue").attr("style")?.match(/\/(\d+)\.jpg/);
		let realUserId = avatarMatch ? avatarMatch[1] : userId;
		let storedDate = localStorage.getItem("userAge_" + userId);
		if (!storedDate) {
			if (!isNaN(userId)) {
				storedDate = findClosestMatchingDates(userId);
				if (storedDate) {
					console.log(`${ userId } ${ storedDate }`);
				}
			} else if (!isNaN(realUserId)) {
				storedDate = findClosestMatchingDates(realUserId);
				if (storedDate) {
					console.log(`${ userId } ${ realUserId } ${ storedDate }`);
				}
			}
		}
		if (storedDate) {
			localStorage.setItem("userAge_" + userId, storedDate);
			displayUserAge(userId, storedDate);
		} else {
			usersToFetch.push(userLink);
		}
	});
	usersToFetch = [...new Set(usersToFetch)];
	console.log("Users to fetch:", usersToFetch);
	usersToFetch.forEach((userLink, index) => {
		fetchAndStoreUserAge(userLink, index * delay);
	});
	const jsonURL = "https://jirehlov.com/userages.json";
	function fetchUserAgesOnline() {
		const lastFetchTime = localStorage.getItem("lastFetchedUserAges");
		const now = Date.now();
		if (!lastFetchTime || now - parseInt(lastFetchTime, 10) > 7 * 24 * 60 * 60 * 1000) {
			fetch(jsonURL).then(response => response.json()).then(data => {
				Object.keys(data).forEach(key => {
					localStorage.setItem("userAge_" + key, data[key]);
				});
				localStorage.setItem("lastFetchedUserAges", now);
			}).catch(error => console.error("Failed to fetch user ages:", error));
		}
	}
	fetchUserAgesOnline();
}());

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址