您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add multiples shortcuts + custom ones
- // ==UserScript==
- // @name AniList Shortcuts
- // @version 1.0
- // @description Add multiples shortcuts + custom ones
- // @author Mio.
- // @namespace https://github.com/dear-clouds/mio-userscripts
- // @supportURL https://github.com/dear-clouds/mio-userscripts/issues
- // @icon https://www.google.com/s2/favicons?sz=64&domain=anilist.co
- // @license GPL-3.0
- // @match *://*.anilist.co/*
- // @grant none
- // ==/UserScript==
- (function () {
- 'use strict';
- // Function to inject Font Awesome CSS
- function injectFontAwesome() {
- const faLink = document.createElement('link');
- faLink.rel = 'stylesheet';
- faLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
- faLink.integrity = 'sha512-pap5K1fL5c4sLcXmpopbPWha8z36H1EJGgUK6YyE1Wfo2jydN12wPuABanVbBv8d5kZdO8+8PpJ1f8kz0gJ0Mg==';
- faLink.crossOrigin = 'anonymous';
- faLink.referrerPolicy = 'no-referrer';
- document.head.appendChild(faLink);
- }
- injectFontAwesome();
- // Utility function to wait for an element to appear in the DOM
- function waitForElement(selector, timeout = 10000) {
- return new Promise((resolve, reject) => {
- const intervalTime = 100;
- let timeElapsed = 0;
- const interval = setInterval(() => {
- const element = document.querySelector(selector);
- if (element) {
- clearInterval(interval);
- resolve(element);
- }
- timeElapsed += intervalTime;
- if (timeElapsed >= timeout) {
- clearInterval(interval);
- reject(`Element ${selector} not found within ${timeout}ms`);
- }
- }, intervalTime);
- });
- }
- // Function to add a link with Font Awesome icon
- function addLinkWithIcon(element, url, linkText, iconName) {
- const link = document.createElement('a');
- link.href = url;
- link.target = '_blank';
- link.rel = 'noopener noreferrer';
- link.style.textDecoration = 'none';
- link.style.color = 'inherit';
- link.style.display = 'flex';
- link.style.alignItems = 'center';
- link.style.marginLeft = '10px';
- const icon = document.createElement('i');
- icon.className = `fa fa-${iconName}`;
- icon.style.marginRight = '5px';
- link.appendChild(icon);
- link.appendChild(document.createTextNode(linkText));
- element.appendChild(link);
- }
- // Function to create a sticky box on forum comments
- function createStickyBoxLink() {
- // Prevent multiple sticky boxes
- if (document.querySelector('.sticky-box')) return;
- const stickyBox = document.createElement('div');
- stickyBox.classList.add('sticky-box');
- stickyBox.style.position = 'fixed';
- stickyBox.style.right = '10px';
- stickyBox.style.top = '200px';
- stickyBox.style.width = '200px';
- stickyBox.style.padding = '10px';
- stickyBox.style.backgroundColor = 'rgb(var(--color-foreground))';
- stickyBox.style.borderRadius = '4px';
- stickyBox.style.transition = 'height 0.5s, opacity 0.5s';
- stickyBox.style.overflow = 'hidden';
- stickyBox.style.zIndex = '1000';
- const header = document.createElement('h3');
- header.innerText = 'Shortcuts';
- header.style.fontSize = 'medium';
- header.style.marginTop = '5';
- stickyBox.appendChild(header);
- const linksContainer = document.createElement('div');
- stickyBox.appendChild(linksContainer);
- const addIcon = document.createElement('span');
- addIcon.innerText = '+';
- addIcon.style.position = 'absolute';
- addIcon.style.top = '5px';
- addIcon.style.right = '5px';
- addIcon.style.cursor = 'pointer';
- addIcon.style.fontWeight = 'bold';
- addIcon.onclick = function () {
- const isHidden = userInput.style.display === 'none';
- userInput.style.display = isHidden ? 'block' : 'none';
- shortcutNameInput.style.display = isHidden ? 'block' : 'none';
- validateButton.style.display = isHidden ? 'block' : 'none';
- };
- stickyBox.appendChild(addIcon);
- const toggleVisibilityIcon = document.createElement('i');
- toggleVisibilityIcon.className = 'fa fa-eye';
- toggleVisibilityIcon.style.cursor = 'pointer';
- toggleVisibilityIcon.style.position = 'absolute';
- toggleVisibilityIcon.style.top = '5px';
- toggleVisibilityIcon.style.left = '5px';
- toggleVisibilityIcon.style.fontSize = '14px';
- toggleVisibilityIcon.onclick = function () {
- if (stickyBox.style.height !== '25px') {
- stickyBox.style.width = '25px';
- stickyBox.style.height = '25px';
- linksContainer.style.display = 'none';
- header.style.display = 'none';
- addIcon.style.display = 'none';
- toggleVisibilityIcon.className = 'fa fa-eye-slash';
- } else {
- stickyBox.style.width = '200px';
- stickyBox.style.height = 'auto';
- linksContainer.style.display = 'block';
- header.style.display = 'block';
- addIcon.style.display = 'block';
- toggleVisibilityIcon.className = 'fa fa-eye';
- }
- };
- stickyBox.appendChild(toggleVisibilityIcon);
- function appendLinkToContainer(linkName, linkURL) {
- const linkElement = document.createElement('a');
- linkElement.href = linkURL;
- linkElement.innerText = linkName;
- linkElement.style.fontSize = 'smaller';
- linkElement.target = '_blank';
- linkElement.style.display = 'flex';
- linkElement.style.alignItems = 'center';
- linkElement.style.marginBottom = '5px';
- linkElement.style.color = 'var(--color-blue)';
- linkElement.style.textDecoration = 'none';
- linkElement.addEventListener('click', (e) => {
- e.preventDefault();
- window.open(linkURL, '_blank');
- });
- const favicon = document.createElement('img');
- try {
- const urlObj = new URL(linkURL);
- favicon.src = `https://www.google.com/s2/favicons?domain=${urlObj.hostname}`;
- } catch {
- favicon.src = '';
- }
- favicon.style.marginRight = '5px';
- favicon.style.width = '16px';
- favicon.style.height = '16px';
- linkElement.prepend(favicon);
- const deleteIcon = document.createElement('span');
- deleteIcon.innerText = ' ×';
- deleteIcon.style.color = 'rgb(var(--color-blue))';
- deleteIcon.style.cursor = 'pointer';
- deleteIcon.style.marginLeft = 'auto';
- deleteIcon.onclick = function (event) {
- event.stopPropagation();
- linksContainer.removeChild(linkElement);
- const savedLinks = JSON.parse(localStorage.getItem('MioAniListShortcuts') || '[]');
- const updatedLinks = savedLinks.filter(l => l.url !== linkURL);
- localStorage.setItem('MioAniListShortcuts', JSON.stringify(updatedLinks));
- };
- linkElement.appendChild(deleteIcon);
- linksContainer.appendChild(linkElement);
- }
- const userInput = document.createElement('input');
- userInput.type = 'text';
- userInput.placeholder = 'Enter your link';
- userInput.style.display = 'none';
- userInput.style.backgroundColor = 'rgb(var(--color-background))';
- userInput.style.color = 'rgb(var(--color-blue))';
- userInput.style.border = '1px solid var(--color-border)';
- userInput.style.borderRadius = '3px';
- userInput.style.padding = '5px';
- userInput.style.fontSize = 'smaller';
- userInput.style.marginTop = '5px';
- stickyBox.appendChild(userInput);
- const shortcutNameInput = document.createElement('input');
- shortcutNameInput.type = 'text';
- shortcutNameInput.placeholder = 'Name of the shortcut';
- shortcutNameInput.style.display = 'none';
- shortcutNameInput.style.backgroundColor = 'rgb(var(--color-background))';
- shortcutNameInput.style.color = 'rgb(var(--color-blue))';
- shortcutNameInput.style.border = '1px solid var(--color-border)';
- shortcutNameInput.style.borderRadius = '3px';
- shortcutNameInput.style.padding = '5px';
- shortcutNameInput.style.fontSize = 'smaller';
- shortcutNameInput.style.marginTop = '5px';
- stickyBox.appendChild(shortcutNameInput);
- const validateButton = document.createElement('button');
- validateButton.innerText = 'Add';
- validateButton.style.display = 'none';
- validateButton.style.backgroundColor = 'var(--color-button)';
- validateButton.style.color = 'var(--color-button-text)';
- validateButton.style.border = 'none';
- validateButton.style.borderRadius = '3px';
- validateButton.style.padding = '5px 10px';
- validateButton.style.fontSize = 'smaller';
- validateButton.style.marginTop = '5px';
- validateButton.style.cursor = 'pointer';
- validateButton.onclick = function () {
- const link = userInput.value.trim();
- const name = shortcutNameInput.value.trim();
- if (link && name) {
- const savedLinks = JSON.parse(localStorage.getItem('MioAniListShortcuts') || '[]');
- // Avoid duplicates
- if (!savedLinks.some(l => l.url === link)) {
- savedLinks.push({ name, url: link });
- localStorage.setItem('MioAniListShortcuts', JSON.stringify(savedLinks));
- appendLinkToContainer(name, link);
- userInput.value = '';
- shortcutNameInput.value = '';
- userInput.style.display = 'none';
- shortcutNameInput.style.display = 'none';
- validateButton.style.display = 'none';
- } else {
- alert('This link already exists in your shortcuts.');
- }
- } else {
- alert('Please enter both name and URL.');
- }
- };
- stickyBox.appendChild(validateButton);
- // Load saved links
- const savedLinks = JSON.parse(localStorage.getItem('MioAniListShortcuts') || '[]');
- for (const linkObj of savedLinks) {
- appendLinkToContainer(linkObj.name, linkObj.url);
- }
- document.body.appendChild(stickyBox);
- }
- // Function to add AniCalendar by KangieDanie link in Activity History
- // https://anilist.co/forum/thread/63096
- function addAniCalendarLink() {
- // Prevent adding multiple links
- if (document.querySelector('.ani-calendar-link')) return;
- let attempts = 0;
- const maxAttempts = 10; // 20 seconds max
- const interval = setInterval(() => {
- const headers = document.querySelectorAll('h2.section-header');
- let activityHistoryHeader = null;
- headers.forEach(header => {
- if (header.textContent.trim() === 'Activity History') {
- activityHistoryHeader = header;
- }
- });
- if (activityHistoryHeader) {
- // Prevent adding multiple links
- if (activityHistoryHeader.querySelector('.ani-calendar-link')) {
- clearInterval(interval);
- return;
- }
- const aniCalendarContainer = document.createElement('span');
- aniCalendarContainer.classList.add('ani-calendar-link');
- aniCalendarContainer.style.float = 'right';
- aniCalendarContainer.style.display = 'flex';
- aniCalendarContainer.style.alignItems = 'center';
- const aniCalendarLink = document.createElement('a');
- aniCalendarLink.href = 'https://ani-calendar.vercel.app/';
- aniCalendarLink.target = '_blank';
- aniCalendarLink.rel = 'noopener noreferrer';
- aniCalendarLink.textContent = 'AniCalendar';
- aniCalendarLink.style.fontSize = 'smaller';
- aniCalendarLink.style.marginLeft = '10px';
- aniCalendarLink.style.color = 'var(--color-blue)';
- aniCalendarLink.style.display = 'flex';
- aniCalendarLink.style.alignItems = 'center';
- aniCalendarLink.style.textDecoration = 'none';
- const calendarIcon = document.createElement('i');
- calendarIcon.className = 'fa fa-calendar';
- calendarIcon.style.marginRight = '5px';
- aniCalendarLink.prepend(calendarIcon);
- aniCalendarContainer.appendChild(aniCalendarLink);
- activityHistoryHeader.appendChild(aniCalendarContainer);
- clearInterval(interval);
- console.log('AniCalendar link added to Activity History.');
- } else {
- attempts++;
- console.log(`Activity History section header not found. Attempt ${attempts}/${maxAttempts}. Retrying in 2 seconds...`);
- if (attempts >= maxAttempts) {
- clearInterval(interval);
- console.warn('Failed to find Activity History section header after multiple attempts.');
- }
- }
- }, 2000);
- }
- // Function to add AniTools link in Social tab
- function addAniToolsLink() {
- const socialFilterGroup = document.querySelector('div.filter-group');
- if (socialFilterGroup) {
- // Prevent adding multiple links
- if (socialFilterGroup.querySelector('.ani-tools-link')) return;
- const aniToolsLink = document.createElement('a');
- aniToolsLink.href = 'https://anitools.koopz.rocks/';
- aniToolsLink.target = '_blank';
- aniToolsLink.rel = 'noopener noreferrer';
- aniToolsLink.textContent = 'AniTools';
- aniToolsLink.style.color = 'var(--color-blue)';
- aniToolsLink.style.display = 'flex';
- aniToolsLink.style.alignItems = 'center';
- aniToolsLink.style.textDecoration = 'none';
- const wrenchIcon = document.createElement('i');
- wrenchIcon.className = 'fa fa-tools';
- wrenchIcon.style.marginRight = '5px';
- aniToolsLink.prepend(wrenchIcon);
- const aniToolsContainer = document.createElement('span');
- aniToolsContainer.classList.add('ani-tools-link');
- aniToolsContainer.appendChild(aniToolsLink);
- socialFilterGroup.appendChild(aniToolsContainer);
- } else {
- console.log('Social filter group not found.');
- }
- }
- // Function to initialize features based on current URL
- function initializeFeatures() {
- const url = window.location.href;
- // Check if the page is an AniList user profile
- if (url.includes('/user/') && !url.includes('/social')) {
- addAniCalendarLink();
- }
- // Check if the page is the social tab of an AniList user profile
- if (url.includes('/user/') && url.includes('/social')) {
- addAniToolsLink();
- }
- // Check if the page is an AniList forum thread comment
- if (url.includes('/forum/thread/') && url.includes('/comment/')) {
- createStickyBoxLink();
- } else {
- const existingStickyBox = document.querySelector('.sticky-box');
- if (existingStickyBox) {
- existingStickyBox.remove();
- }
- }
- }
- // Function to handle URL changes
- function onUrlChange(callback) {
- let lastUrl = location.href;
- const observer = new MutationObserver(() => {
- const currentUrl = location.href;
- if (currentUrl !== lastUrl) {
- lastUrl = currentUrl;
- callback();
- }
- });
- observer.observe(document, { subtree: true, childList: true });
- window.addEventListener('popstate', () => {
- callback();
- });
- const pushState = history.pushState;
- const replaceState = history.replaceState;
- history.pushState = function () {
- pushState.apply(history, arguments);
- callback();
- };
- history.replaceState = function () {
- replaceState.apply(history, arguments);
- callback();
- };
- }
- // Initialize features on initial load
- window.addEventListener('load', () => {
- setTimeout(() => {
- initializeFeatures();
- }, 1000);
- });
- // Initialize features on URL changes
- onUrlChange(() => {
- setTimeout(() => {
- initializeFeatures();
- }, 1000);
- });
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址