Lib Family Switcher

Аутентичная кнопка перехода между сайтами lib-семейства

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Lib Family Switcher
// @namespace    http://tampermonkey.net/
// @version      2.2.0
// @description  Аутентичная кнопка перехода между сайтами lib-семейства
// @author       MayBeGod
// @match        *://mangalib.me/*
// @match        *://ranobelib.me/*
// @match        *://hentailib.me/*
// @match        *://v2.shlib.life/*
// @match        *://v5.animelib.org/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const style = document.createElement('style');
    style.innerHTML = `
        .lib-switcher-container {
            display: inline-flex !important;
            align-items: center !important;
            position: relative !important;
            margin-left: 8px !important;
            cursor: pointer !important;
            z-index: 1000 !important;
            vertical-align: middle;
        }
        .lib-switcher-icon {
            width: 16px;
            height: 16px;
            color: #777;
            transition: color 0.2s, transform 0.2s;
            pointer-events: none;
        }
        .lib-switcher-container:hover .lib-switcher-icon {
            color: #ff8e35;
        }
        .lib-switcher-container.active .lib-switcher-icon {
            transform: rotate(180deg);
        }
        .lib-dropdown-menu {
            display: none;
            position: absolute;
            top: calc(100% + 10px);
            left: 0;
            background: #232323;
            border-radius: 8px;
            padding: 8px 0;
            min-width: 200px;
            z-index: 9999999;
            box-shadow: 0 10px 30px rgba(0,0,0,0.7);
            border: 1px solid #333;
        }
        .lib-dropdown-menu.show {
            display: block;
        }
        .lib-dropdown-item {
            display: flex !important;
            align-items: center !important;
            padding: 12px 20px !important;
            color: #eee !important;
            text-decoration: none !important;
            font-size: 14px !important;
            font-family: sans-serif !important;
            transition: background 0.15s;
        }
        .lib-dropdown-item:hover {
            background: #303030 !important;
        }
        .lib-corner-icon {
            width: 20px;
            height: 20px;
            margin-right: 15px;
            flex-shrink: 0;
            transition: opacity 0.2s;
        }
        .lib-dropdown-item:hover .lib-corner-icon {
            opacity: 0.8;
        }
        .lib-dropdown-separator {
            height: 1px;
            background: #333;
            margin: 4px 0;
        }
    `;
    document.head.appendChild(style);

    function makeIcon(rectColor, letterColor, letter) {
        return `<svg class="lib-corner-icon" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
            <path d="M0 0 H20 V20 H18 V2 Z M0 0 V20 H2 V2 Z" fill="${rectColor}"/>
            <text x="50%" y="55%" dominant-baseline="middle" text-anchor="middle"
                  font-size="12" font-family="Arial, sans-serif" font-weight="bold" fill="${letterColor}">${letter}</text>
        </svg>`;
    }

    // Основные сайты (порядок = порядок в меню)
    const SITES = [
        {
            id: 'manga',
            name: 'MangaLIB',
            url: 'https://mangalib.me',
            test: h => h === 'mangalib.me',
            icon: makeIcon('#4caf50', '#fff', 'M'),
            old: { name: 'MangaLIB Старая', url: 'https://old.mangalib.me/', icon: makeIcon('#ff9800', '#fff', 'M') }
        },
        {
            id: 'slash',
            name: 'SlashLIB',
            url: 'https://v2.shlib.life/',
            test: h => h.includes('shlib.life'),
            icon: makeIcon('#e91e63', '#fff', 's')
        },
        {
            id: 'ranobe',
            name: 'RanobeLIB',
            url: 'https://ranobelib.me',
            test: h => h.includes('ranobelib.me'),
            icon: makeIcon('#2196f3', '#fff', 'R')
        },
        {
            id: 'hentai',
            name: 'HentaiLIB',
            url: 'https://hentailib.me',
            test: h => h.includes('hentailib.me'),
            icon: makeIcon('#f44336', '#fff', 'H')
        },
        {
            id: 'anime',
            name: 'AnimeLIB',
            url: 'https://v5.animelib.org/',
            test: h => h.includes('animelib.org') || (h.includes('animelib.me') && !h.startsWith('old.')),
            icon: makeIcon('#9c27b0', '#fff', 'A'),
            old: { name: 'AnimeLIB Старая', url: 'https://old.animelib.org/old', icon: makeIcon('#7b1fa2', '#fff', 'A') }
        },
    ];

    function getCurrentSite() {
        const h = location.hostname;
        return SITES.find(s => s.test(h)) || null;
    }

    // Расширенный список селекторов для поиска логотипа на разных сайтах
    const LOGO_SELECTORS = [
        'a[href="/ru"]',
        'a[href="/"]',
        '.header-logo',
        '.header__logo',
        '[class*="logo"] a',
        '[class*="Logo"] a',
        'header [class*="logo"]',
        'header [class*="Logo"]',
        'a.os_ag.lo_lq',
        'header a[href="/ru"]',
        'header a[href="/"]',
        'nav a[href="/"]',
        'nav a[href="/ru"]',
    ];

    function findLogoLink() {
        for (const sel of LOGO_SELECTORS) {
            const el = document.querySelector(sel);
            if (el) return el;
        }
        return null;
    }

    function buildMenuHTML(currentSite) {
        const mainItems = SITES
            .filter(s => s.id !== currentSite?.id)
            .map(s => `<a href="${s.url}" class="lib-dropdown-item">${s.icon} ${s.name}</a>`)
            .join('');

        const oldItem = currentSite?.old
            ? `<div class="lib-dropdown-separator"></div>
               <a href="${currentSite.old.url}" class="lib-dropdown-item">${currentSite.old.icon} ${currentSite.old.name}</a>`
            : '';

        return mainItems + oldItem;
    }

    function createSwitcher() {
        if (document.getElementById('lib-family-switcher')) return;

        const logoLink = findLogoLink();
        if (!logoLink) return;

        const currentSite = getCurrentSite();

        const container = document.createElement('div');
        container.id = 'lib-family-switcher';
        container.className = 'lib-switcher-container';
        container.innerHTML = `
            <svg class="lib-switcher-icon" aria-hidden="true" focusable="false" role="img"
                 xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
                <path fill="currentColor" d="M384 480c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0zM224 352c-6.7 0-13-2.8-17.6-7.7l-104-112c-6.5-7-8.2-17.2-4.4-25.9s12.5-14.4 22-14.4l208 0c9.5 0 18.2 5.7 22 14.4s2.1 18.9-4.4 25.9l-104 112c-4.5 4.9-10.9 7.7-17.6 7.7z"/>
            </svg>
            <div class="lib-dropdown-menu" id="switcher-menu">
                ${buildMenuHTML(currentSite)}
            </div>
        `;

        container.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            const menu = document.getElementById('switcher-menu');
            const isActive = menu.classList.toggle('show');
            container.classList.toggle('active', isActive);
        });

        container.querySelectorAll('.lib-dropdown-item').forEach(item => {
            item.addEventListener('click', e => e.stopPropagation());
        });

        document.addEventListener('click', () => {
            const menu = document.getElementById('switcher-menu');
            if (menu) {
                menu.classList.remove('show');
                container.classList.remove('active');
            }
        });

        logoLink.style.display = 'inline-flex';
        logoLink.style.alignItems = 'center';
        logoLink.appendChild(container);
    }

    const observer = new MutationObserver(createSwitcher);
    observer.observe(document.body, { childList: true, subtree: true });
    createSwitcher();
})();