UserStatusSub

萌娘百科UserStatus订阅

Установить этот скрипт?
Рекомендуемый автором скрипт

Вам также может понравится JustMoeComments.

Установить этот скрипт

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         UserStatusSub
// @namespace    https://github.com/gui-ying233/UserStatusSub
// @version      1.3.0
// @description  萌娘百科UserStatus订阅
// @author       鬼影233
// @contributor  BearBin@BearBin1215
// @license      MIT
// @match        *.moegirl.org.cn/*
// @icon         https://img.moegirl.org.cn/common/b/b7/%E5%A4%A7%E8%90%8C%E5%AD%97.svg
// @supportURL   https://github.com/gui-ying233/UserStatusSub/issues
// ==/UserScript==

(() => {
	"use strict";
	if (new URLSearchParams(window.location.search).get("safemode")) return;
	$(() =>
		(async () => {
			window.addEventListener("storage", e => {
				if (e.key === "userStatusSub") {
					if (e.newValue) {
						localStorage.setItem("userStatusSub", e.newValue);
					} else {
						localStorage.removeItem("userStatusSub");
					}
				}
			});

			await mw.loader.using([
				"mediawiki.api",
				"mediawiki.notification",
				"mediawiki.util",
				"oojs-ui",
			]);

			const api = new mw.Api();

			mw.util.addCSS(`.userStatus {
		width: 100%;
		display: grid;
		grid-template-columns: repeat(auto-fit, 11em);
		gap: 1em;
		padding: 1em;
		justify-content: center;
	}

	.userStatusImg {
		width: 25px;
		vertical-align: middle;
	}

	.userStatusRaw {
		display: grid;
		gap: 0.5em;
		border: var(--theme-just-kidding-text-color) dashed 1px;
		padding: 0.5em;
	}

	.userStatusContent {
		max-height: 11em;
		overflow: auto;
		transition: max-height 350ms;
	}

	.userStatusContent:hover {
		max-height: 100%;
	}

	#userStatuUpdate {
		margin: 1em 0;
	}`);

			/**
			 * @return {JSON}
			 */
			function userStatusGetLocalStorage() {
				return Object.values(
					JSON.parse(localStorage.getItem("userStatusSub")) || {}
				);
			}
			async function userStatusSetLocalStorage() {
				if (
					document
						.querySelector("#userStatuSummary > textarea")
						.value.trim()
				) {
					let subList = [];
					for (const t of [
						...new Set(
							document
								.querySelector("#userStatuSummary > textarea")
								.value.trim()
								.split("\n")
								.map(str => str.trim())
								.filter(str => str)
						),
					]) {
						await api
							.get({
								action: "query",
								format: "json",
								prop: "revisions",
								titles: `User:${t}/Status`,
								utf8: 1,
								formatversion: 2,
								rvprop: "timestamp",
							})
							.then(d => {
								if (d.query.pages[0].missing) {
									mw.notify(`用户${t}不存在`, {
										type: "warn",
									});
								} else {
									subList.push({
										title: t,
										timestamp:
											d.query.pages[0].revisions[0]
												.timestamp,
									});
								}
							});
					}
					localStorage.setItem(
						"userStatusSub",
						JSON.stringify(subList)
					);
					document.querySelector("#userStatuSummary > textarea");
				} else {
					localStorage.removeItem("userStatusSub");
				}
			}

			/**
			 * @param {JSON} subList
			 */
			async function updateUserStatus(subList) {
				const userStatusUpdateButton =
					document.getElementById("userStatuUpdate");
				userStatusUpdateButton.style.pointerEvents = "none";
				userStatusUpdateButton.classList.add("oo-ui-widget-disabled");
				userStatusUpdateButton.classList.remove("oo-ui-widget-enabled");
				userStatusUpdateButton.setAttribute("aria-disabled", "true");
				document.body.querySelector(".userStatus").innerHTML = "";
				userStatusSetLocalStorage();
				for (const u of subList) {
					try {
						await api
							.get({
								action: "parse",
								format: "json",
								page: `User:${u.title}/Status`,
								prop: "text",
								disabletoc: 1,
								utf8: 1,
								formatversion: 2,
							})
							.then(d => {
								const userStatusRaw =
									document.createElement("div");
								userStatusRaw.classList.add("userStatusRaw");
								userStatusRaw.innerHTML += d.parse.text;
								switch (
									userStatusRaw.innerText.trim().toLowerCase()
								) {
									case "online":
									case "on":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/9/94/Symbol_support_vote.svg"> <b style="color:green;">在线</b>';
										break;
									case "busy":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/c/c5/Symbol_support2_vote.svg"> <b style="color:blue;">忙碌</b>';
										break;
									case "offline":
									case "off":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/7/7f/Symbol_oppose_vote.svg"> <b style="color:red;">离线</b>';
										break;
									case "away":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/6/6c/Time2wait.svg"> <b style="color:grey;">已离开</b>';
										break;
									case "sleeping":
									case "sleep":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/5/54/Symbol_wait.svg"> <b style="color:purple;">在睡觉</b>';
										break;
									case "wikibreak":
									case "break":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/6/61/Symbol_abstain_vote.svg"> <b style="color:brown;">正在放萌百假期</b>';
										break;
									case "holiday":
										userStatusRaw.innerHTML =
											'<img class="userStatusImg" src="https://img.moegirl.org.cn/common/3/30/Symbol_deferred.svg"> <b style="color:#7B68EE;">处于假期中</b>';
										break;
								}
								userStatusRaw.innerHTML = `<b class="userStatusUserName">${u.title}</b><div class="userStatusContent">${userStatusRaw.innerHTML}</div>`;
								document.body
									.querySelector(".userStatus")
									.append(userStatusRaw);
								userStatusSubDialog.updateSize();
							});
					} catch (e) {
						if (e !== "missingtitle") {
							console.error(e);
						}
					}
				}
				userStatusUpdateButton.style.pointerEvents = "auto";
				userStatusUpdateButton.classList.remove(
					"oo-ui-widget-disabled"
				);
				userStatusUpdateButton.classList.add("oo-ui-widget-enabled");
				userStatusUpdateButton.setAttribute("aria-disabled", "false");
			}

			/* 感谢BearBin@BearBin1215提供的的OOUI部分 */
			const $body = $("body");

			class userStatusSubWindow extends OO.ui.ProcessDialog {
				static static = {
					...super.static,
					tagName: "div",
					name: "userStatus",
					title: "用户状态监控",
					actions: [
						{
							action: "cancel",
							label: "取消",
							flags: ["safe", "close", "destructive"],
						},
						{
							action: "submit",
							label: "保存",
							flags: ["primary", "progressive"],
						},
					],
				};
				constructor(config) {
					super(config);
				}
				initialize() {
					super.initialize();
					this.panelLayout = new OO.ui.PanelLayout({
						scrollable: false,
						expanded: false,
						padded: true,
					});

					const $userStatus = document.createElement("div");
					$userStatus.classList.add("userStatus");

					const $label = document.createElement("p");
					$label.innerText = "订阅列表:";
					const userStatusInputBox =
						new OO.ui.MultilineTextInputWidget({
							placeholder: "仅填写用户名,每个用户名一行",
							id: "userStatuSummary",
							autosize: true,
						});
					const userStatusUpdateButton = new OO.ui.ButtonWidget({
						label: "更新列表",
						flags: ["primary"],
						id: "userStatuUpdate",
					});
					userStatusUpdateButton.on("click", async () => {
						await updateUserStatus(
							userStatusInputBox
								.getValue()
								.trim()
								.split("\n")
								.map(str => str.trim())
								.filter(str => str)
								.map(str => {
									return { title: str };
								})
						);
						this.updateSize();
					});

					this.panelLayout.$element.append(
						$userStatus,
						$label,
						userStatusInputBox.$element,
						userStatusUpdateButton.$element
					);
					this.$body.append(this.panelLayout.$element);
				}

				getActionProcess(action) {
					if (action === "cancel") {
						return new OO.ui.Process(() => {
							this.close({ action });
						}, this);
					} else if (action === "submit") {
						userStatusSetLocalStorage();
						return new OO.ui.Process(() => {
							this.close({ action });
						}, this);
					}
					return super.getActionProcess(action);
				}
			}

			const windowManager = new OO.ui.WindowManager({});
			$body.append(windowManager.$element);
			const userStatusSubDialog = new userStatusSubWindow({
				size: "larger",
			});
			windowManager.addWindows([userStatusSubDialog]);

			mw.util
				.addPortletLink(
					"p-cactions",
					"javascript:void(0);",
					"用户状态监控",
					"ca-userstatussub"
				)
				.addEventListener("click", async () => {
					$("#mw-notification-area").appendTo("body");
					windowManager.openWindow(userStatusSubDialog);
					document.body.querySelector(
						"#userStatuSummary > textarea"
					).value = userStatusGetLocalStorage()
						.map(u => u.title)
						.join("\n");
					await updateUserStatus(userStatusGetLocalStorage());
				});

			const waitTime = 300000;

			var timestamps = {};
			(async () => {
				if (Notification.permission !== "denied") {
					Notification.requestPermission();
				}
				for (const u of userStatusGetLocalStorage()) {
					timestamps[u.title] = u.timestamp;
					setInterval(() => {
						api.get({
							action: "query",
							format: "json",
							prop: "revisions",
							titles: `User:${u.title}/Status`,
							utf8: 1,
							formatversion: 2,
							rvprop: "timestamp|content",
						}).then(d => {
							const timestamp =
								d.query.pages[0].revisions[0].timestamp;
							if (timestamp !== timestamps[u.title]) {
								localStorage.setItem(
									"userStatusSub",
									JSON.stringify(
										userStatusGetLocalStorage()
									).replace(
										`"title":"${u.title}","timestamp":"${
											timestamps[u.title]
										}"`,
										`"title":"${u.title}","timestamp":"${timestamp}"`
									)
								);
								timestamps[u.title] = timestamp;
								let status =
									d.query.pages[0].revisions[0].content
										.trim()
										.toLowerCase();
								switch (status) {
									case "online":
									case "on":
										status = "在线";
										break;
									case "busy":
										status = "忙碌";
										break;
									case "offline":
									case "off":
										status = "离线";
										break;
									case "away":
										status = "已离开";
										break;
									case "sleeping":
									case "sleep":
										status = "在睡觉";
										break;
									case "wikibreak":
									case "break":
										status = "正在放萌百假期";
										break;
									case "holiday":
										status = "处于假期中";
										break;
									default:
										const s = document.createElement("div");
										s.innerHTML = status;
										status = s.innerText;
								}
								new Notification(`${u.title}已更新:`, {
									body: status,
									icon: `//commons.moegirl.org.cn/extensions/Avatar/avatar.php?user=${u.title}`,
								});
							}
						});
					}, waitTime);
					await (() => {
						return new Promise(resolve =>
							setTimeout(
								resolve,
								waitTime / userStatusGetLocalStorage().length
							)
						);
					})();
				}
			})();
		})()
	);
})();