Jut.su АвтоСкип+ (Skip Intro, Next Episode, Preview, Download)

Автоскип заставок, автопереход, предпросмотр серий и кнопка загрузки на Jut.su.

// ==UserScript==
// @name            Jut.su АвтоСкип+ (Skip Intro, Next Episode, Preview, Download)
// @name:en         Jut.su Auto+ (Skip Intro, Next Episode, Preview, Download)
// @namespace       http://tampermonkey.net/
// @version         3.1
// @description     Автоскип заставок, автопереход, предпросмотр серий и кнопка загрузки на Jut.su.
// @description:en  Automatically skip intros, auto switch episodes, show previews and add download button on Jut.su.
// @author          Rodion (integrator), Diorhc (preview), VakiKrin (download)
// @match           https://jut.su/*
// @license         MIT
// @grant           GM_registerMenuCommand
// @require         http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// ==/UserScript==


(function() {
    'use strict';

    const SETTINGS = {
        autoSkip: true,
        autoNext: true,
        previewEnabled: true,
        downloadButton: true
    };

    // Меню
    function registerMenu() {
        GM_registerMenuCommand(`Автоскип интро: ${SETTINGS.autoSkip ? '✅ ВКЛ' : '❌ ВЫКЛ'}`, () => toggleSetting('autoSkip'));
        GM_registerMenuCommand(`Автопереход: ${SETTINGS.autoNext ? '✅ ВКЛ' : '❌ ВЫКЛ'}`, () => toggleSetting('autoNext'));
        GM_registerMenuCommand(`Превью серий: ${SETTINGS.previewEnabled ? '✅ ВКЛ' : '❌ ВЫКЛ'}`, () => toggleSetting('previewEnabled'));
        GM_registerMenuCommand(`Кнопка загрузки: ${SETTINGS.downloadButton ? '✅ ВКЛ' : '❌ ВЫКЛ'}`, () => toggleSetting('downloadButton'));
    }

    function toggleSetting(key) {
        SETTINGS[key] = !SETTINGS[key];
        location.reload();
    }

    // Автоскип
function autoSkipAndNext() {
    const isVisible = elem => elem && elem.offsetParent !== null;
    let fullscreenTriggered = false;
    let skipTriggered = false;

    const loop = () => {
        const skipButton = document.querySelector("div[title='Нажмите, если лень смотреть опенинг']");
        const nextButton = document.querySelector("div[title='Перейти к следующему эпизоду']");
        const playButton = document.querySelector("button[title='Воспроизвести видео']");
        const video = document.querySelector('video');
        const fullscreenBtn = document.querySelector("button.vjs-fullscreen-control");

        // Нажать "Пропустить интро"
        if (SETTINGS.autoSkip && isVisible(skipButton)) {
            skipButton.click();
            skipTriggered = true;
            console.log('[JUTSU] Skip intro clicked');
        }

        // Нажать "Следующая серия"
        if (SETTINGS.autoNext && isVisible(nextButton)) {
            nextButton.click();
            console.log('[JUTSU] Next episode clicked');
        }

        // Нажать "Пуск", если видно кнопку
        if (isVisible(playButton)) {
            playButton.click();
            console.log('[JUTSU] Play button clicked');
        }

        // После скипа включить фуллскрин, если видео идёт
        if (skipTriggered && video && !fullscreenTriggered && !video.paused && fullscreenBtn && isVisible(fullscreenBtn)) {
            fullscreenBtn.click();
            fullscreenTriggered = true;
            console.log('[JUTSU] Fullscreen activated');
        }

        setTimeout(loop, 500);
    };

    loop();

    const video = document.querySelector('video');
    if (video && SETTINGS.autoNext) {
        video.addEventListener('ended', () => {
            const nextLink = document.querySelector('.vnright a');
            if (nextLink) window.location.href = nextLink.href;
        });
    }
}

    // Стили превью
    function injectPreviewStyle() {
        const style = document.createElement('style');
        style.textContent = `
            .prevbox {
                margin-top: 55px;
                margin-left: -163px;
                display: none;
                width: 200px;
                position: absolute;
                z-index: 9999;
                opacity: 0;
                transition: opacity 0.2s ease;
                box-shadow: 0 0 15px black;
                border-radius: 5px;
                border: 2px solid rgba(102, 107, 102, 0.8);
                text-align: center;
            }
            .prevbox > div {
                border-radius: 0 0 5px 5px;
                padding: 3px 14px;
                background-color: #363a37;
                border-top: 1px solid #505550;
            }
            .prevbox > img {
                border-radius: 5px;
                width: 200px;
                height: 112.5px;
                background: url(https://i.imgur.com/DLLjUig.png) center no-repeat rgb(54, 58, 55);
            }
        `;
        document.head.appendChild(style);
    }

    // Превью
    function enablePreviewTooltips() {
        const links = document.querySelectorAll(`#dle-content > div > div:nth-child(2) > a[href*='${window.location.pathname}']`);
        links.forEach((link, index) => {
            const box = document.createElement('div');
            box.className = 'prevbox';
            const img = document.createElement('img');
            const title = document.createElement('div');
            box.append(img, title);
            let t1, t2;

            link.addEventListener('mouseenter', () => {
                clearTimeout(t1); clearTimeout(t2);
                t1 = setTimeout(() => {
                    if (!localStorage[link.href]) {
                        fetch(link.href).then(res => res.arrayBuffer()).then(buffer => {
                            const html = new TextDecoder('windows-1251').decode(buffer);
                            const temp = document.createElement('div');
                            temp.innerHTML = html;
                            const imgUrl = temp.querySelector('meta[property="og:image"]').content;
                            const titleText = temp.querySelector('#dle-content div.video_plate_title h2').textContent;
                            img.src = imgUrl;
                            title.textContent = titleText;
                            localStorage[link.href] = imgUrl;
                            localStorage[link.href + '-title'] = titleText;
                        });
                    } else {
                        img.src = localStorage[link.href];
                        title.textContent = localStorage[link.href + '-title'];
                    }
                    link.insertAdjacentElement('afterend', box);
                    box.style.display = 'block';
                    box.style.opacity = '0';
                    t2 = setTimeout(() => box.style.opacity = '1', 300);
                }, 200);
            });

            link.addEventListener('mouseleave', () => {
                clearTimeout(t1); clearTimeout(t2);
                box.style.opacity = '0';
                setTimeout(() => box.style.display = 'none', 200);
            });
        });
    }

    // Download button (от VakiKrin)
    function waitForKeyElements(selector, callback) {
        const run = () => {
            const nodes = $(selector);
            if (nodes.length) {
                nodes.each((_, el) => {
                    const $el = $(el);
                    if (!$el.data('alreadyFound')) {
                        $el.data('alreadyFound', true);
                        callback($el);
                    }
                });
                return true;
            }
            return false;
        };

        const interval = setInterval(() => {
            if (run()) clearInterval(interval);
        }, 300);
    }

    function addDownloadButton($node) {
        const src = $node[0].src;
        const name = location.pathname.split("/")[1] + '.mp4';
        const container = document.querySelector('.videoContent');
        if (!container) return;

        const div = document.createElement('div');
        div.style.display = 'flex';
        div.style.justifyContent = 'center';
        div.style.alignItems = 'center';

        const a = document.createElement('a');
        a.href = src;
        a.className = 'short-btn';
        a.textContent = 'DOWNLOAD';
        a.onclick = e => {
            e.preventDefault();
            const link = document.createElement('a');
            link.href = src;
            link.download = name;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        };

        div.appendChild(a);
        container.appendChild(div);
    }

    // Init
    registerMenu();
    if (SETTINGS.autoSkip || SETTINGS.autoNext) autoSkipAndNext();
    if (SETTINGS.previewEnabled) {
        setTimeout(() => {
            injectPreviewStyle();
            enablePreviewTooltips();
        }, 1000);
    }
    if (SETTINGS.downloadButton) {
        waitForKeyElements('#my-player_html5_api > source[label="1080p"]', addDownloadButton);
    }
})();