您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Добавляет больше ссылок в раздел "На других сайтах"
当前为
// ==UserScript== // @name ShikiSearch+ // @icon https://www.google.com/s2/favicons?domain=shikimori.me // @namespace https://shikimori.one // @version 1.3 // @description Добавляет больше ссылок в раздел "На других сайтах" // @author LifeH // @match *://shikimori.org/* // @match *://shikimori.one/* // @match *://shikimori.me/* // @grant none // @license MIT // @require https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.6/Sortable.min.js // ==/UserScript== (function() { 'use strict'; const allowedPaths = ["/ranobe/", "/animes/", "/mangas/"]; let isEditing = false; let editingIndex = null; const defaultLinks = [ { title: "Anime-joy", icon: "anime-joy.online", link: "https://anime-joy.online/index.php?story={search}&do=search&subaction=search", searchMethod: "title", group: "animes", enabled: true, }, { title: "Anilibria", icon: "anilibria.tv", link: "https://www.anilibria.tv/release/{search}.html", searchMethod: "slug", group: "animes", enabled: true, }, { title: "Animego", icon: "animego.me", link: "https://animego.me/search/all?q={search}", searchMethod: "title", group: "animes", enabled: true, }, { title: "Anilib", icon: "anilib.me", link: "https://anilib.me/ru/catalog?q={search}", searchMethod: "title", group: "animes", enabled: true, }, { title: "Jut.su", icon: "jut.su", link: "https://jut.su/search/?searchid=1893616&text={search}&web=0#", searchMethod: "title", group: "animes", enabled: true, }, { title: "rutracker", icon: "rutracker.org", link: "https://rutracker.org/forum/tracker.php?nm={search}", searchMethod: "title", group: "animes", enabled: true, }, { title: "Yummy-anime", icon: "yummy-anime.ru", link: "https://yummy-anime.ru/search?word={search}", searchMethod: "title", group: "animes", enabled: false, }, { title: "Animevost", icon: "animevost.org", link: "https://animevost.org/index.php?do=search&subaction=search&search_start=0&full_search=0&result_from=1&story={search}", searchMethod: "title", group: "animes", enabled: false, }, { title: "Crunchyroll", icon: "crunchyroll.com", link: "https://www.crunchyroll.com/search?q={search}", searchMethod: "originalTitle", group: "animes", enabled: false, }, { title: "Amedia", icon: "amedia.lol", link: "https://amedia.lol/index.php?do=search&subaction=search&from_page=0&story={search}", searchMethod: "title", group: "animes", enabled: false, }, { title: "Rezka", icon: "rezka.ag", link: "https://rezka.ag/search/?do=search&subaction=search&q={search}", searchMethod: "title", group: "animes", enabled: false, }, { title: "Anime1", icon: "anime1.best", link: "https://anime1.best/index.php?do=search&subaction=search&search_start=0&full_search=0&result_from=1&story={search}", searchMethod: "title", group: "animes", enabled: false, }, ]; function getGroup() { const path = window.location.pathname; return allowedPaths.find((p) => path.startsWith(p))?.replace(/\//g, ""); } function getTitle() { let titleElement = document.querySelector(".head h1"); return titleElement ? titleElement.childNodes[0].textContent.trim() : null; } function getId() { const pathParts = window.location.pathname.split("/"); const idPart = pathParts[2] || ""; const match = idPart.match(/^[a-z]*(\d+)/); return match ? match[1] : null; } function getOriginalTitle() { const titleElement = document.querySelector(".head h1"); if (!titleElement) return null; const separator = titleElement.querySelector(".b-separator.inline"); if (!separator) return null; const originalTitle = separator.nextSibling?.textContent?.trim(); return originalTitle || null; } function getSlug() { let path = window.location.pathname; let match = path.match(/\/(animes|mangas|ranobe)\/z?(\d+)-(.+)/); return match ? match[3] : null; } function getLinks() { let links = JSON.parse(localStorage.getItem("userLinks")); if (!links) { links = defaultLinks; saveLinks(links); } return links; } function saveLinks(links) { localStorage.setItem("userLinks", JSON.stringify(links)); } function linkBuilder({ icon, link, searchMethod, group: linkGroup, title, enabled }) { if (!enabled) return; const group = getGroup(); if (linkGroup !== group) return; let parentBlock = document.querySelector(".subheadline.m8")?.parentElement; if (!parentBlock) return; let searchParam; if (searchMethod === "slug") { searchParam = getSlug(); } else if (searchMethod === "id") { searchParam = getId(); } else if (searchMethod === "originalTitle") { searchParam = getOriginalTitle(); } else { searchParam = getTitle(); } if (!searchParam) return; let url = link.replace("{search}", encodeURIComponent(searchParam)); let linkContainer = document.createElement('div'); linkContainer.className = 'b-external_link b-menu-line'; let anchor = document.createElement('a'); anchor.className = 'b-link'; anchor.href = url; anchor.textContent = title; anchor.target = '_blank'; if (icon) { let img = document.createElement('img'); img.src = `https://www.google.com/s2/favicons?domain=${icon}`; img.style.width = '19px'; img.style.height = '19px'; img.style.marginRight = '5px'; anchor.prepend(img); } linkContainer.appendChild(anchor); parentBlock.appendChild(linkContainer); } function init() { let links = getLinks(); links.forEach(linkBuilder); } function GUI() { const settingsBlock = document.querySelector('.block.edit-page.misc'); if (!settingsBlock) return; if (document.querySelector('.shikisearch-config')) return; let container = document.createElement('div'); container.className = 'shikisearch-config'; container.style.padding = '20px'; container.style.border = '1px solid #ccc'; container.style.marginTop = '20px'; container.style.background = '#f9f9f9'; container.style.borderRadius = '8px'; container.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)'; container.style.position = 'relative'; container.innerHTML = ` <h3 style="margin-bottom: 20px; text-align: center;">[ShikiSearch+] Config</h3> <div style="display: flex; flex-direction: column; gap: 10px;"> <input type="text" id="title" placeholder="Название" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc;"> <input type="text" id="icon" placeholder="Домен (например: shikimori.one)" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc;"> <input type="text" id="link" placeholder="Шаблон для ссылки поиска (используйте {search})" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc;"> <select id="searchMethod" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc;"> <option value="title">По названию</option> <option value="originalTitle">По названию (оригинал)</option> <option value="slug">По Slug</option> <option value="id">По ID</option> </select> <select id="group" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc;"> <option value="animes">Аниме</option> <option value="mangas">Манга</option> <option value="ranobe">Ранобэ</option> </select> <button id="addLink" style="padding: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">Добавить</button> </div> <div id="linksList" style="margin-top: 20px; display: flex; flex-direction: column; gap: 10px;"></div> <span class="tooltip" style="position: absolute; top: 10px; right: 10px; cursor: help;">? <span class="tooltiptext"> <strong>Информация:</strong><br> "По названию": Русское названия тайтла.<br> "По Slug": Использует часть ссылки.<br> </span> </span> `; settingsBlock.appendChild(container); let style = document.createElement('style'); style.textContent = ` .tooltip { position: relative; display: inline-block; cursor: help; font-size: 14px; color: #555; } .tooltip .tooltiptext { visibility: hidden; width: 250px; background-color: #555; color: #fff; text-align: left; border-radius: 6px; padding: 10px; position: absolute; z-index: 1000; top: 100%; right: 0; opacity: 0; transition: opacity 0.3s; font-size: 12px; white-space: normal; } .tooltip:hover .tooltiptext { visibility: visible; opacity: 1; } `; document.head.appendChild(style); document.getElementById('addLink').addEventListener('click', () => { let title = document.getElementById('title').value.trim(); let icon = document.getElementById('icon').value.trim(); let link = document.getElementById('link').value.trim(); let searchMethod = document.getElementById('searchMethod').value; let group = document.getElementById('group').value; if (!title || !link) { alert('Заполните название и ссылку!'); return; } let links = getLinks(); if (isEditing) { links[editingIndex] = { title, icon, link, searchMethod, group, enabled: true }; isEditing = false; editingIndex = null; document.getElementById('addLink').textContent = 'Добавить'; } else { links.push({ title, icon, link, searchMethod, group, enabled: true }); } saveLinks(links); updateLinksList(); clearForm(); }); updateLinksList(); } function updateLinksList() { let linksList = document.getElementById('linksList'); linksList.innerHTML = ''; let links = getLinks(); links.forEach((link, index) => { let card = document.createElement('div'); card.style.display = 'flex'; card.style.alignItems = 'center'; card.style.justifyContent = 'space-between'; card.style.padding = '10px'; card.style.border = '1px solid #ccc'; card.style.borderRadius = '8px'; card.style.background = '#fff'; card.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)'; card.style.cursor = 'grab'; card.setAttribute('data-index', index); card.setAttribute('draggable', 'true'); card.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', ''); e.target.style.opacity = '0.4'; }); card.addEventListener('dragend', (e) => { e.target.style.opacity = '1'; }); card.innerHTML = ` <div style="display: flex; align-items: center; gap: 10px;"> <img src="https://www.google.com/s2/favicons?domain=${link.icon}" style="width: 16px; height: 16px;"> <span>${link.title} (${link.group})</span> </div> <div style="display: flex; align-items: center; gap: 10px;"> <label class="toggle-switch"> <input type="checkbox" ${link.enabled ? 'checked' : ''} onchange="toggleLink(${index}, this.checked)"> <span class="slider"></span> </label> <button onclick="editLink(${index})" style="padding: 5px 10px; background-color: #FFC107; color: white; border: none; border-radius: 4px; cursor: pointer;">Редактировать</button> <button onclick="deleteLink(${index})" style="padding: 5px 10px; background-color: #F44336; color: white; border: none; border-radius: 4px; cursor: pointer;">Удалить</button> </div> `; linksList.appendChild(card); }); new Sortable(linksList, { animation: 150, onEnd: function (evt) { let links = getLinks(); let movedItem = links.splice(evt.oldIndex, 1)[0]; links.splice(evt.newIndex, 0, movedItem); saveLinks(links); updateLinksList(); } }); let style = document.createElement('style'); style.textContent = ` .toggle-switch { position: relative; display: inline-block; width: 40px; height: 20px; } .toggle-switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: 0.4s; border-radius: 20px; } .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: white; transition: 0.4s; border-radius: 50%; } input:checked + .slider { background-color: #4CAF50; } input:checked + .slider:before { transform: translateX(20px); } .sortable-chosen { background-color: #f0f0f0; } .sortable-ghost { opacity: 0.5; } `; document.head.appendChild(style); } function clearForm() { document.getElementById('title').value = ''; document.getElementById('icon').value = ''; document.getElementById('link').value = ''; document.getElementById('searchMethod').value = 'title'; document.getElementById('group').value = 'animes'; } window.deleteLink = function(index) { if (confirm('Вы уверены, что хотите удалить эту ссылку?')) { let links = getLinks(); links.splice(index, 1); saveLinks(links); updateLinksList(); } }; window.editLink = function(index) { let links = getLinks(); let link = links[index]; document.getElementById('title').value = link.title; document.getElementById('icon').value = link.icon; document.getElementById('link').value = link.link; document.getElementById('searchMethod').value = link.searchMethod; document.getElementById('group').value = link.group; isEditing = true; editingIndex = index; document.getElementById('addLink').textContent = 'Сохранить изменения'; }; window.toggleLink = function(index, enabled) { let links = getLinks(); links[index].enabled = enabled; saveLinks(links); }; function ready(fn) { document.addEventListener('page:load', fn); document.addEventListener('turbolinks:load', fn); if (document.readyState !== "loading") { fn(); } else { document.addEventListener('DOMContentLoaded', fn); } } ready(init); ready(GUI); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址