您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
One‑click (and now fully automated) jump from RU anime sites → Shikimori → MyAnimeList. Fast, ad‑skipping, with UI‑lock overlay.
// ==UserScript== // @name MAL Turbo Jump // @namespace mal_jumper // @version 2.1 // @description One‑click (and now fully automated) jump from RU anime sites → Shikimori → MyAnimeList. Fast, ad‑skipping, with UI‑lock overlay. // @author Kotaytqee // @match https://animego.me/* // @match https://jut.su/* // @match https://duckduckgo.com/* // @match https://shikimori.one/* // @icon https://www.google.com/s2/favicons?sz=64&domain=myanimelist.net // @grant GM_openInTab // @run-at document-idle // @license MIT // ==/UserScript== (() => { 'use strict'; /*============================================================= | CONSTANTS & SHORTCUTS *===========================================================*/ const MAL_BLUE = '#2E51A2'; const SHIKI_FILTER = 'site:shikimori.one/animes'; // hop‑1 const MAL_FILTER = 'site:myanimelist.net'; // hop‑2 const log = (...m) => console.debug('[MAL]', ...m); /*============================================================= | STYLE & OVERLAY *===========================================================*/ function injectStyles() { if (document.getElementById('mal-styles')) return; const s = document.createElement('style'); s.id = 'mal-styles'; s.textContent = ` .mal-btn { background: ${MAL_BLUE}; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; font-size: 14px; font-family: inherit; cursor: pointer; transition: background-color 0.2s ease; } .mal-btn:hover { background-color: #294693; /* чуть темнее для эффекта hover */ } #mal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; z-index: 999999; color: #fff; font: 20px/1.4 sans-serif; pointer-events: all; } `; document.head.appendChild(s); } /** Show blocking overlay with msg; returns remover fn */ function showOverlay (msg='Подождите…') { injectStyles(); const o = document.createElement('div'); o.id = 'mal‑overlay'; o.textContent = `⏳ ${msg}`; document.body.appendChild(o); return () => o.remove(); } const buildURL = (filter, title) => `https://duckduckgo.com/?q=${encodeURIComponent(`${filter} ${title}`)}`; /*============================================================= | animego / jut.su (RU source sites) *===========================================================*/ const SOURCES = { 'animego.me': { anchor: () => document.querySelector('.anime-title > div'), title : () => document.querySelector('.anime-title h1')?.textContent?.trim() }, 'jut.su': { anchor: () => document.querySelector('h1.header_video'), title : () => { const t = document.querySelector('h1.header_video span[itemprop="name"]')?.textContent || ''; return t.replace(/Смотреть\s*/i,'').replace(/\s*\d+\s*серия/i,'').trim(); }, center:true } }; /** * Поиск прямой ссылки на MyAnimeList через публичный Shikimori API. * @param {string} title — название аниме для поиска * @returns {Promise<string|null>} — URL на myanimelist.net или null, если не найдено */ async function fetchMalByShikiApi(title) { try { // 1) Поиск anime-id по названию const searchUrl = `https://shikimori.one/api/animes?search=${encodeURIComponent(title)}`; const searchResp = await fetch(searchUrl, { headers: { 'User-Agent': 'MAL-Turbo-Jump/2.0' } }); if (!searchResp.ok) return null; const list = await searchResp.json(); if (!Array.isArray(list) || list.length === 0) return null; const animeId = list[0].id; // 2) Запрос подробной информации с external_links const infoUrl = `https://shikimori.one/api/animes/${animeId}`; const infoResp = await fetch(infoUrl, { headers: { 'User-Agent': 'MAL-Turbo-Jump/2.0' } }); if (!infoResp.ok) return null; const info = await infoResp.json(); // 3) Извлечение ссылки на MAL if (!Array.isArray(info.external_links)) return null; const malLinkObj = info.external_links.find(link => link.site.toLowerCase().includes('myanimelist') ); return malLinkObj ? malLinkObj.url : null; } catch (e) { console.error('fetchMalByShikiApi error:', e); return null; } } function enhanceSourceSite () { const key = Object.keys(SOURCES).find(k => location.hostname.endsWith(k)); if (!key) return; const cfg = SOURCES[key]; const anchor = cfg.anchor(); const title = cfg.title(); if (!anchor || !title) { log('title/anchor missing'); return; } injectStyles(); const btn = document.createElement('button'); btn.className = 'mal-btn'; btn.textContent = 'MAL'; btn.title = title; if (cfg.center) { btn.style.display = 'block'; btn.style.margin = '10px auto'; } // Вот тут вешаем новый, «надстройочный» сценарий: btn.onclick = async () => { const removeOverlay = showOverlay('Поиск через Shikimori API…'); try { const malUrl = await fetchMalByShikiApi(title); removeOverlay(); if (malUrl) { // Нашли прямой MAL-URL — открываем его GM_openInTab(malUrl, { active: true }); } else { // Не нашли — возвращаемся к старому сценарию через DuckDuckGo const remove2 = showOverlay('Перевод на MAL (фоллбэк)…'); GM_openInTab(buildURL(MAL_FILTER, title), { active: true }); setTimeout(remove2, 2000); } } catch (err) { removeOverlay(); console.error('Ошибка поиска по Shikimori API:', err); const remove2 = showOverlay('Перевод на MAL (фоллбэк)…'); GM_openInTab(buildURL(MAL_FILTER, title), { active: true }); setTimeout(remove2, 2000); } }; anchor.appendChild(btn); log('Button added on', key); } /*============================================================= | Shikimori → auto hop to MAL *===========================================================*/ function getJPTitle(){ const h1=document.querySelector('h1'); if(!h1) return null; const parts=h1.textContent.split('/'); return parts[1]?.trim()||null; } function handleShikimori(){ const jp=getJPTitle(); if(!jp){log('JP title missing');return;} injectStyles(); const h1=document.querySelector('h1'); const btn=document.createElement('button'); btn.className='mal‑btn'; btn.textContent='MAL'; btn.title=jp; btn.style.marginLeft='10px'; btn.onclick=()=>GM_openInTab(buildURL(MAL_FILTER,jp),{active:true}); h1.appendChild(btn); // auto‑redirect once per session if(!sessionStorage.getItem('mal_autohop')){ sessionStorage.setItem('mal_autohop','1'); showOverlay('Перенаправляем на MAL…'); location.replace(buildURL(MAL_FILTER,jp)); } log('Shikimori processed'); } /*============================================================= | DuckDuckGo (ad‑skip & fast redirect) *===========================================================*/ function ctxFromQuery(){ const q=new URLSearchParams(location.search).get('q')||''; if(q.includes(SHIKI_FILTER)) return {domain:'shikimori.one'}; if(q.includes(MAL_FILTER)) return {domain:'myanimelist.net'}; return null; } function tryRedirect(domain){ const items=[ ...document.querySelectorAll('li[data-layout="organic"]'), ...document.querySelectorAll('#links .result') ]; for(const it of items){ if(it.querySelector('.badge--ad')) continue; const a=it.querySelector('a[data-testid="result-title-a"],a.result__a'); if(a&&a.href.includes(domain)){ log('→',a.href); showOverlay('Загружаем…'); location.href=a.href; return true; } } return false; } async function handleDDG(){ const ctx=ctxFromQuery(); if(!ctx) return; log('DDG context',ctx.domain); if(tryRedirect(ctx.domain)) return; // immediate DOM pass const obsSel='ol.react-results--main,#links'; const ok=await new Promise(r=>{ const to=setTimeout(()=>r(false),4000); // shorter timeout const obs=new MutationObserver(()=>{ if(tryRedirect(ctx.domain)){clearTimeout(to);obs.disconnect();r(true);} }); obs.observe(document.documentElement,{childList:true,subtree:true}); }); if(!ok) log('No redirect found'); } /*============================================================= | ROUTER *===========================================================*/ if(location.hostname.endsWith('duckduckgo.com')) handleDDG(); else if(location.hostname.endsWith('shikimori.one')) handleShikimori(); else enhanceSourceSite(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址