VoidVerified

Display a verified sign next to user's name in AniList.

当前为 2023-10-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name VoidVerified
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.4.1
  5. // @description Display a verified sign next to user's name in AniList.
  6. // @author voidnyan
  7. // @match https://anilist.co/*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. "use strict";
  14. const version = "0.4.1";
  15. const evaluationIntervalInSeconds = 1;
  16. const localStorageColors = "void-verified-colors";
  17.  
  18. const verified = {
  19. copyColorFromProfile: true,
  20. moveSubscribeButtons: true,
  21. hideLikeCount: false,
  22. username: {
  23. enabled: true,
  24. enabledForReplies: true,
  25. enabledForProfileName: true,
  26. color: "white",
  27. sign: "✔",
  28. },
  29. highlight: {
  30. enabled: true,
  31. enabledForReplies: true,
  32. enabledForSmallCards: false,
  33. color: undefined,
  34. size: "5px",
  35. },
  36. };
  37.  
  38. const shouldIntervalBeUsed =
  39. verified.username.enabledForProfileName || verified.highlight.enabled;
  40.  
  41. let verifiedUsers = [
  42. {
  43. username: "voidnyan",
  44. sign: "💻",
  45. },
  46. ].map((u) => (typeof u === "string" ? { username: u } : u));
  47.  
  48. const colorsInLocalStorage = JSON.parse(
  49. localStorage.getItem(localStorageColors)
  50. );
  51.  
  52. if (colorsInLocalStorage !== null) {
  53. verifiedUsers = verifiedUsers.map((u) =>
  54. colorsInLocalStorage !== null && u.color
  55. ? u
  56. : {
  57. ...u,
  58. color: colorsInLocalStorage.find(
  59. (c) => c.username === u.username
  60. )?.color,
  61. }
  62. );
  63. }
  64.  
  65. let usernameStyles = "";
  66. let highlightStyles = "";
  67. let otherStyles = "";
  68.  
  69. createStyles();
  70.  
  71. function createStyles() {
  72. usernameStyles = "";
  73. highlightStyles = "";
  74. for (const user of verifiedUsers) {
  75. if (verified.username.enabled) {
  76. createUsernameCSS(user);
  77. }
  78.  
  79. if (verified.highlight.enabled) {
  80. createHighlightCSS(
  81. user,
  82. `div.wrap:has( div.header > a.name[href*="${user.username}"] )`
  83. );
  84. createHighlightCSS(
  85. user,
  86. `div.wrap:has( div.details > a.name[href*="${user.username}"] )`
  87. );
  88. }
  89.  
  90. if (verified.highlight.enabledForReplies) {
  91. createHighlightCSS(
  92. user,
  93. `div.reply:has( a.name[href*="${user.username}"] )`
  94. );
  95. }
  96. }
  97.  
  98. if (
  99. verified.highlight.enabled &&
  100. !verified.highlight.enabledForSmallCards
  101. ) {
  102. disableHighlightOnSmallCards();
  103. }
  104.  
  105. if (verified.moveSubscribeButtons) {
  106. otherStyles += `
  107. .has-label::before {
  108. top: -30px !important;
  109. left: unset !important;
  110. right: -10px;
  111. }
  112.  
  113. .has-label[label="Unsubscribe"],
  114. .has-label[label="Subscribe"] {
  115. font-size: 0.875em !important;
  116. }
  117.  
  118. .has-label[label="Unsubscribe"] {
  119. color: rgba(var(--color-green),.8);
  120. }
  121. `;
  122. }
  123.  
  124. if (verified.hideLikeCount) {
  125. otherStyles += `
  126. .like-wrap .count {
  127. display: none;
  128. }
  129. `;
  130. }
  131. }
  132.  
  133. function createUsernameCSS(user) {
  134. usernameStyles += `
  135. a.name[href*="${user.username}"]::after {
  136. content: "${user.sign ?? verified.username.sign}";
  137. color: ${
  138. user.color ??
  139. verified.username.color ??
  140. "rgb(var(--color-blue))"
  141. }
  142. }
  143. `;
  144. }
  145.  
  146. function createHighlightCSS(user, selector) {
  147. highlightStyles += `
  148. ${selector} {
  149. margin-right: -${verified.highlight.size};
  150. border-right: ${verified.highlight.size} solid ${
  151. user.color ?? verified.highlight.color ?? "rgb(var(--color-blue))"
  152. };
  153. border-radius: 5px;
  154. }
  155. `;
  156. }
  157.  
  158. function moveAndDisplaySubscribeButton() {
  159. if (!verified.moveSubscribeButtons) {
  160. return;
  161. }
  162.  
  163. const subscribeButtons = document.querySelectorAll(
  164. "span[label='Unsubscribe'], span[label='Subscribe']"
  165. );
  166. for (const subscribeButton of subscribeButtons) {
  167. if (subscribeButton.parentNode.classList.contains("actions")) {
  168. continue;
  169. }
  170.  
  171. if (verified.autoLikeOnSubscribe) {
  172. subscribeButton.addEventListener("click", likeActivity);
  173. }
  174.  
  175. const container = subscribeButton.parentNode.parentNode;
  176. const actions = container.querySelector(".actions");
  177. actions.append(subscribeButton);
  178. }
  179. }
  180.  
  181. function likeActivity() {
  182. // const container = this.parentNode;
  183. // const likeButton = container.querySelector(".like-wrap .button");
  184. // if (likeButton.classList.contains("liked")) {
  185. // return;
  186. //
  187. // // likeButton.click();
  188. // likeButton.dispatchEvent(new Event("click"));
  189. }
  190.  
  191. function disableHighlightOnSmallCards() {
  192. highlightStyles += `
  193. div.wrap:has(div.small) {
  194. margin-right: 0px !important;
  195. border-right: 0px solid black !important;
  196. }
  197. `;
  198. }
  199.  
  200. const usernameLink = createStyleLink(usernameStyles, "username");
  201. const highlightLink = createStyleLink(highlightStyles, "highlight");
  202. const profileLink = createStyleLink("", "profile");
  203. const otherLink = createStyleLink(otherStyles, "other");
  204.  
  205. function refreshHomePage() {
  206. if (!verified.highlight.enabled) {
  207. return;
  208. }
  209.  
  210. const oldHighlightLink = document.getElementById(
  211. "void-verified-highlight-styles"
  212. );
  213. const newHighlightLink = createStyleLink(highlightStyles, "highlight");
  214. oldHighlightLink.remove();
  215. }
  216.  
  217. function verifyProfile() {
  218. if (!verified.username.enabledForProfileName) {
  219. return;
  220. }
  221.  
  222. const usernameHeader = document.querySelector("h1.name");
  223. const username = usernameHeader.innerHTML.trim();
  224.  
  225. const user = verifiedUsers.find((u) => u.username === username);
  226. if (!user) {
  227. profileLink.href =
  228. "data:text/css;charset=UTF-8," + encodeURIComponent("");
  229. return;
  230. }
  231.  
  232. const profileStyle = `
  233. h1.name::after {
  234. content: "${user.sign ?? verified.username.sign}"
  235. }
  236. `;
  237. profileLink.href =
  238. "data:text/css;charset=UTF-8," + encodeURIComponent(profileStyle);
  239. }
  240.  
  241. function copyUserColor() {
  242. const usernameHeader = document.querySelector("h1.name");
  243. const username = usernameHeader.innerHTML.trim();
  244. const user = verifiedUsers.find((u) => u.username === username);
  245.  
  246. if (
  247. user.copyColorFromProfile === false ||
  248. (!user.copyColorFromProfile && !verified.copyColorFromProfile)
  249. ) {
  250. return;
  251. }
  252.  
  253. const color =
  254. getComputedStyle(usernameHeader).getPropertyValue("--color-blue");
  255. user.color = `rgb(${color})`;
  256. verifiedUsers = verifiedUsers.map((u) =>
  257. u.username !== user.username ? u : user
  258. );
  259.  
  260. createStyles();
  261.  
  262. const oldHighlightLink = document.getElementById(
  263. "void-verified-highlight-styles"
  264. );
  265. const newHighlightLink = createStyleLink(highlightStyles, "highlight");
  266. oldHighlightLink.remove();
  267.  
  268. const oldUsernameLink = document.getElementById(
  269. "void-verified-username-styles"
  270. );
  271. const newUsernameLink = createStyleLink(usernameStyles, "username");
  272. oldUsernameLink.remove();
  273.  
  274. addOrUpdateColorToLocalStorage(user);
  275. }
  276.  
  277. function addOrUpdateColorToLocalStorage(user) {
  278. let localColors = JSON.parse(localStorage.getItem(localStorageColors));
  279.  
  280. if (localColors === null) {
  281. localStorage.setItem(
  282. localStorageColors,
  283. JSON.stringify([{ username: user.username, color: user.color }])
  284. );
  285. return;
  286. }
  287.  
  288. let localStorageUser = localColors.find(
  289. (u) => u.username === user.username
  290. );
  291. if (localStorageUser) {
  292. localStorageUser.color = user.color;
  293. localColors = localColors.map((u) =>
  294. u.username === localStorageUser.username ? localStorageUser : u
  295. );
  296. } else {
  297. localColors.push({ username: user.username, color: user.color });
  298. }
  299.  
  300. localStorage.setItem(localStorageColors, JSON.stringify(localColors));
  301. }
  302.  
  303. function createStyleLink(styles, id) {
  304. const link = document.createElement("link");
  305. link.setAttribute("id", `void-verified-${id}-styles`);
  306. link.setAttribute("rel", "stylesheet");
  307. link.setAttribute("type", "text/css");
  308. link.setAttribute(
  309. "href",
  310. "data:text/css;charset=UTF-8," + encodeURIComponent(styles)
  311. );
  312. document.head?.append(link);
  313. return link;
  314. }
  315.  
  316. let currentPath = "";
  317. function hasPathChanged(path) {
  318. if (path === currentPath) {
  319. return false;
  320. }
  321. currentPath = path;
  322. return true;
  323. }
  324.  
  325. function handleIntervalScripts() {
  326. const path = window.location.pathname;
  327.  
  328. moveAndDisplaySubscribeButton();
  329.  
  330. if (path === "/home") {
  331. refreshHomePage();
  332. return;
  333. }
  334.  
  335. if (!hasPathChanged(path)) {
  336. return;
  337. }
  338.  
  339. if (path.startsWith("/user/")) {
  340. verifyProfile();
  341. copyUserColor();
  342. }
  343. }
  344.  
  345. if (shouldIntervalBeUsed) {
  346. setInterval(handleIntervalScripts, evaluationIntervalInSeconds * 1000);
  347. }
  348.  
  349. console.log(`VoidVerified ${version} loaded.`);
  350. })();

QingJ © 2025

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