您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds Anilist anime/manga link to their MyAnimeList page
// ==UserScript== // @name Link MyAnimeList to AniList // @namespace https://greasyfork.org/en/users/1195345-necodes // @author NECOdes // @description Adds Anilist anime/manga link to their MyAnimeList page // @version 0.0.2 // @match https://myanimelist.net/anime/* // @match https://myanimelist.net/manga/* // @grant GM_xmlhttpRequest // @connect graphql.anilist.co // @license MIT // ==/UserScript== 'use strict'; (async function() { const match = window.location.pathname.match(/\/(anime|manga)\/(\d+)/); if (!match) return; const type = match[1] === 'anime' ? 'ANIME' : 'MANGA'; const malId = parseInt(match[2], 10); const anilistLogo = 'https://raw.githubusercontent.com/NECOtype/userscripts/8b9a59a9ebdf048838f2a5a9fffeb9228569e46d/assets/anilist-icon.png'; const query = ` query ($malId: Int, $type: MediaType) { Media(idMal: $malId, type: $type) { siteUrl } } `; const variables = { malId, type }; // GM_xmlhttpRequest Promise to use with async/await const gmFetch = (options) => { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ ...options, onload: (response) => { if (response.status >= 200 && response.status < 3000) { resolve(response); } else { reject(new Error(`Request failed with status ${response.status}: ${response.statusText}`)); } }, onerror: (error) => reject(error), ontimeout: () => reject(new Error('Request timed out.')), }); }); }; try { const response = await gmFetch({ method: 'POST', url: 'https://graphql.anilist.co', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, data: JSON.stringify({ query, variables }), }) const json = JSON.parse(response.responseText); const anilistUrl = json?.data?.Media?.siteUrl; if (!anilistUrl) { console.warn('Anilist URL not found for this entry.') return; }; const isDarkMode = document.documentElement.classList.contains('dark-mode'); // Creates and appends the Anilist link to the external_links container const createAnilistLink = (container) => { // prevents duplicate links if (container.querySelector('.anilist-button')) { return true; } const secondChild = container.children[1]; const newButton = document.createElement('a'); newButton.href = anilistUrl; newButton.target = '_blank'; newButton.classList.add('link', 'ga-click', 'anilist-button'); newButton.style.backgroundColor = isDarkMode ? '#1e2630' : '#fefefe'; newButton.style.color = isDarkMode ? '#fefefe' : '#1e2630'; newButton.style.borderRadius = '4px'; newButton.style.display = 'flex'; newButton.style.justifyContent = 'center'; newButton.style.fontFamily = 'inherit'; newButton.style.fontSize = 'inherit'; newButton.style.padding = '6px 0'; newButton.style.marginBlock = '4px 0'; newButton.style.textDecoration = 'none'; newButton.style.textAlign = 'center'; newButton.style.width = '100%'; const newImg = document.createElement('img'); newImg.src = anilistLogo; newImg.classList.add('link_icon'); newImg.alt = 'anilist icon'; newImg.style.width = '16px'; newImg.style.paddingInline = '3px'; const newDiv = document.createElement('div'); newDiv.textContent = 'View on Anilist'; newDiv.classList.add('caption'); newButton.appendChild(newImg); newButton.appendChild(newDiv); container.insertBefore(newButton, secondChild) return true; } const observer = new MutationObserver((mutations, obs) => { const container = document.querySelector('.leftside'); if (container) { if (createAnilistLink(container)) { obs.disconnect(); } } }) observer.observe(document.body, { childList: true, subtree: true }); } catch (err) { console.error('Anilist API request failed: ', err); } })();