shikiPlus

script add viewer and playeer on shikimori

// ==UserScript==
// @name         shikiPlus
// @author       chsa13
// @description  script add viewer and playeer on shikimori
// @namespace    http://shikimori.me/
// @version      1.7
// @match        *://shikimori.org/*
// @match        *://shikimori.one/*
// @match        *://shikimori.me/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=shikimori.me
// @license      MIT
// @copyright    Copyright © 2024 chsa13. All rights reserved.
// ==/UserScript==
let RonobeLibLink = "https://ranobelib.me/ru/"
let MangaLibLink = "https://test-front.mangalib.me/ru/"
let AnimeLibLink = "https://anilib.me/ru/anime/"
let LibSocialApiLink = 'https://api.lib.social/api'

function launchFullScreen(element) {
    if (element.requestFullScreen) {
        element.requestFullScreen();
    }
    else if (element.webkitRequestFullScreen) {
        element.webkitRequestFullScreen();
    }
    else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
    }
}

function ready(fn) {
    document.addEventListener('page:load', fn);
    document.addEventListener('turbolinks:load', fn);
    if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") fn();
    else document.addEventListener('DOMContentLoaded', fn);
}

async function sleep(timeMs) {
    await new Promise(resolve => setTimeout(resolve, timeMs));
}

async function GetResourceAsync(uri, config = {}) {
    return await new Promise((resolve, reject) => {
        $.ajax(Object.assign({
            url: uri,
            dataType: 'json',
            async: true,
            cache: false,
            success: function(res) {
                resolve(res);
            },
            error: function(xhr) {
                reject(xhr);
            }
        }, config));
    });
}

async function ranobelib(hrefs, type) {
    let sets = document.createElement("div");
    sets.style.cssText = `
    margin-bottom: 10px;
    width: 100%;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    `;

    let sweatcher = document.createElement("div");
    sweatcher.style.cssText = `
    opacity: 1;
    display: flex;
    align-items: center;
    font-size: 20px;
    color: var(--color-text-primary, --font-main, #F8F8F2);
    white-space: nowrap;
    `;

    let sweatcherText = document.createElement("span");
    sweatcherText.textContent = "Выбрать версию:";
    sweatcherText.style.cssText = `
        margin-right: 10px;
        color: var(--color-text-primary, --font-main, #112233);
    `;

    let styleTag = document.createElement('style');
    styleTag.textContent = `
        @media (max-width: 768px) {
            .hide-on-mobile-text {
                display: none !important;
            }
        }
    `;

    document.head.appendChild(styleTag);

    sweatcherText.classList.add('hide-on-mobile-text');
    sweatcher.appendChild(sweatcherText);

    for (let i in hrefs) {
        let btm = document.createElement("div");
        btm.style.cssText = `
    cursor: pointer;
    margin-right: 10px;
    border-radius: 6px;
    justify-content: center;
    align-items: center;
    width: 35px;
    height: 35px;
    color: var(--color-text-primary, #F8F8F2);
    background-color: var(--color-background-button, #414141);
    display: flex;
    font-size: 16px;
    font-weight: 600;
    transition: all 0.3s ease;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
        `;

        btm.textContent = (String(Number(i) + 1));
        sweatcher.appendChild(btm);

        btm.addEventListener("click", async () => {
            if (type == "manga") {
                fr.src = MangaLibLink + hrefs[i] + "/read/v01/c01";
            } else if (type == "ranobe") {
                fr.src = RonobeLibLink + hrefs[i] + "/read/v01/c01";
            }
        });

        // Анимация для сенсорного касания
        btm.addEventListener("touchstart", () => {
            btm.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
            btm.style.color = "#FFF";
            btm.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
            btm.style.transform = "translateY(-2px)";
        });

        btm.addEventListener("touchend", async () => {
            btm.style.backgroundColor = "var(--color-background-button, #414141)";
            btm.style.color = "var(--color-text-primary, #F8F8F2)";
            btm.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
            btm.style.transform = "translateY(0)";
        });

        // Анимация при наведении мышкой
        btm.addEventListener("mouseover", () => {
            btm.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
            btm.style.color = "#FFF";
            btm.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
            btm.style.transform = "translateY(-2px)";
        });

        btm.addEventListener("mouseout", () => {
            btm.style.backgroundColor = "var(--color-background-button, #414141)";
            btm.style.color = "var(--color-text-primary, #F8F8F2)";
            btm.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
            btm.style.transform = "translateY(0)";
        });
    }

    if (hrefs.length >= 2) sets.appendChild(sweatcher);

    var fr = document.createElement("iframe");

    if (type == "manga") {
        fr.src = MangaLibLink + hrefs[0] + "/read/v01/c01";
    } else if (type == "ranobe") {
        fr.src = RonobeLibLink + hrefs[0] + "/read/v01/c01";
    }

    fr.setAttribute('allowFullScreen', 'allowfullscreen');
    fr.style.cssText = `
        width: 100%;
        height: unset;
        aspect-ratio: 1.36;
        min-height: 650px;
        border: none;
    `;

    let blackdiv = document.createElement("div");
    blackdiv.style.cssText = `
        position: absolute;
        background-color: black;
        width: 100%;
        height: unset;
        aspect-ratio: 1.36;
        min-height: 650px;
        border: none;
    `;

    let e = document.createElement("div");
    e.style.cssText = `
    display: flex;
    align-items: center;
    justify-content: flex-end;
    height: 40px;
    `;

    sets.appendChild(e);

    let g = document.createElement("div");
    g.style.cssText = `
    border-radius: 6px;
    text-align: center;
    font-size: 18px;
    padding: 0 20px;
    color: var(--color-text-primary, #F8F8F2);
    background-color: var(--color-background-button, #414141);
    cursor: pointer;
    transition: all 0.3s ease;
    white-space: nowrap;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    `;

    g.textContent = "Полноэкранный режим";
    e.appendChild(g);

    g.addEventListener("click", async () => {
        g.style.backgroundColor = "var(--color-background-button, #414141)";
        g.style.color = "var(--color-text-primary, #F8F8F2)";
        g.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
        g.style.transform = "translateY(0)";
        launchFullScreen(fr);
    });

    // Анимация для сенсорного касания
    g.addEventListener("touchstart", () => {
        g.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
        g.style.color = "#FFF";
        g.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
        g.style.transform = "translateY(-2px)";
    });

    g.addEventListener("touchend", async () => {
        g.style.backgroundColor = "var(--color-background-button, #414141)";
        g.style.color = "var(--color-text-primary, #F8F8F2)";
        g.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
        g.style.transform = "translateY(0)";
    });

    // Анимация при наведении мышкой
    g.addEventListener("mouseover", () => {
        g.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
        g.style.color = "#FFF";
        g.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
        g.style.transform = "translateY(-2px)";
    });

    g.addEventListener("mouseout", () => {
        g.style.backgroundColor = "var(--color-background-button, #414141)";
        g.style.color = "var(--color-text-primary, #F8F8F2)";
        g.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
        g.style.transform = "translateY(0)";
    });

    fr.onload = async function() {
        blackdiv.remove();
    };

    let container = document.querySelector('.b-db_entry');
    let aboutSection = container.querySelector('.c-about');
    let descriptionSection = container.querySelector('.c-description');
    let imageSection = container.querySelector('.c-image');

    // Проверка на мобильную версию
    if (window.innerWidth <= 768) {
        if (imageSection) {
            imageSection.appendChild(sets);
            imageSection.appendChild(blackdiv);
            imageSection.appendChild(fr);
        }
    } else if (aboutSection && descriptionSection) {
        container.insertBefore(sets, descriptionSection);
        container.insertBefore(blackdiv, descriptionSection);
        container.insertBefore(fr, descriptionSection);
    }
}



async function animelib(href) {
    var fr = document.createElement("iframe");
    fr.src = AnimeLibLink + href.split("?")[0] + "/watch";
    fr.setAttribute('allowFullScreen', 'allowfullscreen');
    fr.style.cssText = `
      width: 100%;
      height: unset;
      aspect-ratio: 1.36;
      min-height: 650px;
      border: none;
    `;

    let blackdiv = document.createElement("div");
    blackdiv.style.cssText = `
      position: absolute;
      background-color: black;
      width: 100%;
      height: unset;
      aspect-ratio: 1.36;
      min-height: 650px;
      border: none;
    `;

    // Находим контейнер
    let container = document.querySelector('.b-db_entry');
    let descriptionSection = container.querySelector('.c-description');

    // Проверяем, существует ли нужный элемент
    if (descriptionSection) {
        // Если это мобильное устройство
        if (window.innerWidth <= 768) {
            let cImageElement = container.querySelector('.c-image');
            if (cImageElement) {
                // Вставляем черный div и iframe после "c-image"
                cImageElement.appendChild(blackdiv);
                cImageElement.appendChild(fr);
            }
        } else {
            // Вставляем черный div перед описанием (десктопная версия)
            container.insertBefore(blackdiv, descriptionSection);
            // Вставляем iframe перед описанием (десктопная версия)
            container.insertBefore(fr, descriptionSection);
        }
    }

    fr.onload = async function() {
        blackdiv.remove();
    };
}


async function addBtn() {
    if (document.querySelector('.shikiPlus')) return
    let lic = false
    let btn = document.createElement("div")
    btn.classList.add("shikiPlus")
    let clickFunc = function() {
        1 == 1
    }
    let href = ""
    let type
    if (location.href.includes("/animes/")) {
        let id = document.querySelector('.b-user_rate').getAttribute('data-target_id')
        let title = document.querySelector("meta[property='og:title']").getAttribute('content')
        try {
            title = title.split(" ")[0]
        }
        catch {
            1 == 1
        }
        console.log(title)
        let response = await GetResourceAsync(LibSocialApiLink + "/anime?q=" + title)
        href = ""
        console.log(response)
        for (let i in response.data) {
            if (id == response.data[i].shikimori_href.split("/")[4]) {
                href = response.data[i].slug_url
            }
        }
        clickFunc = animelib
        console.log(href)
    }
    else if (location.href.includes("/mangas/")) {
        type = "manga"
        await a(type)
    }
    else if (location.href.includes("/ranobe/")) {
        type = "ranobe"
        await a(type)
    }
    async function a(type) {
        let as = []
        if (type =="ranobe") as = document.querySelectorAll(".ranobelib > a")
        if (type =="manga") as = document.querySelectorAll(".mangalib > a")
        href = []
        for (let i in as) {
            if (as[i].href) {
                i = (as[i].href.split("?")[0].replace("https://ranobelib.me/", "").replace("https://mangalib.me/", "").replace("ru/", "").replace("book/", "").replace("ranobes/", "").replace("ranobe/", "").replace("manga/", "").replace("mangas/", ""))
                console.log(i)
                let response = await GetResourceAsync(LibSocialApiLink + "/manga/" + i)
                lic = response.data.is_licensed
                href.push(response.data.slug_url)
            }
        }
        clickFunc = ranobelib
    }

    btn.style.cssText = `
    border-radius: 6px;
    opacity: 1;
    text-align: center;
    font-size: 18px;
    width: 100%;
    height: 40px;
    background-color: var(--color-background-button, #414141); /* Фон кнопки */
    color: var(--color-text-secondary, #E1E1E3); /* Цвет текста */
    cursor: pointer;
    transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease; /* Плавные переходы */
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Добавлена легкая тень */
`;

    btn.addEventListener("click", async () => {
        btn.remove();
        console.log(href);
        document.querySelector('.c-description').style.cssText = `
        margin-left:0;
        `
        clickFunc(href, type);
    });
    // Анимация для сенсорного касания
    btn.addEventListener("touchstart", () => {
        btn.style.backgroundColor = "var(--color-surface-hover, #5F9EA0)";
        btn.style.color = "var(--color-text-primary, #F8F8F2)";
        btn.style.transform = "translateY(-2px)";
        btn.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
    });

    btn.addEventListener("touchend", async () => {
        btn.style.backgroundColor = "var(--color-background-button, #414141)";
        btn.style.color = "var(--color-text-secondary, #E1E1E3)";
        btn.style.transform = "translateY(0)";
        btn.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
    });

    // Анимация при наведении мышкой
    btn.addEventListener("mouseover", () => {
        btn.style.backgroundColor = "var(--color-surface-hover, #5F9EA0)"; /* Цвет при наведении */
        btn.style.color = "var(--color-text-primary, #F8F8F2)"; /* Цвет текста при наведении */
        btn.style.transform = "translateY(-2px)"; /* Легкий подъем */
        btn.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)"; /* Увеличение тени */
    });

    btn.addEventListener("mouseout", () => {
        btn.style.backgroundColor = "var(--color-background-button, #414141)"; /* Возвращаем оригинальный цвет */
        btn.style.color = "var(--color-text-secondary, #E1E1E3)";
        btn.style.transform = "translateY(0)"; /* Возвращаем в исходное положение */
        btn.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)"; /* Восстанавливаем исходную тень */
    });

    if (!type) btn.textContent = "Смотреть"
    else btn.textContent = "Читать"
    if (!lic && (href || href.length)) document.querySelectorAll('.c-image').forEach(e => e.appendChild(btn))
}
ready(addBtn)