HDrezka Improvement

HDrezka Improvement: cleanup, change content width, change player size, remove ads, remove blocks, restyle, subtitles (opensubtitles.com)

// ==UserScript==
// @name            HDrezka Improvement
// @name:en         HDrezka Improvement
// @name:uk         HDrezka Improvement
// @name:ru         HDrezka Improvement
// @description     HDrezka Improvement: cleanup, change content width, change player size, remove ads, remove blocks, restyle, subtitles (opensubtitles.com)
// @description:en  HDrezka Improvement: cleanup, change content width, change player size, remove ads, remove blocks, restyle, subtitles (opensubtitles.com)
// @description:uk  HDrezka Improvement: cleanup, change content width, change player size, remove ads, remove blocks, restyle, subtitles (opensubtitles.com)
// @description:ru  HDrezka Improvement: cleanup, change content width, change player size, remove ads, remove blocks, restyle, subtitles (opensubtitles.com)
// @author          rub4ek
// @namespace       http://tampermonkey.net/
// @version         2.0.4
// @include         http*://hdrezka*/*
// @include         http*://rezka*/*
// @include         http*://hdrezka.me/*
// @include         http*://hdrezka.co/*
// @include         http*://rezka.ag/*
// @include         http*://rezkify.com/*
// @include         http*://rezkery.com/*
// @include         http*://kinopub.me/*
// @icon            https://static.hdrezka.ac/templates/hdrezka/images/favicon.ico
// @grant           GM.info
// @grant           GM.addStyle
// @grant           GM.xmlHttpRequest
// @grant           GM.setValue
// @grant           GM.getValue
// @grant           GM.deleteValue
// @grant           GM.listValues
// @run-at          document-start
// @require         https://update.greasyfork.org/scripts/482037/1298684/R4%20Fonts.js
// @require         https://update.greasyfork.org/scripts/482042/1298685/R4%20Images.js
// @require         https://update.greasyfork.org/scripts/482597/1301960/R4%20Utils.js
// @require         https://update.greasyfork.org/scripts/482052/1302000/R4%20Settings.js
// @license         MIT
// ==/UserScript==


(function () {
    "use strict";

    /* ------------------------------------------------- */
    /* --------------GLOBAL----------------------------- */
    /* ------------------------------------------------- */

    const r4 = {};

    /* ------------------------------------------------- */
    /* --------------VERSION---------------------------- */
    /* ------------------------------------------------- */

    r4.version = GM.info.script.version;
    r4.useragent = `hdrezka-improvement userscript v${r4.version}`;

    /* ------------------------------------------------- */
    /* --------------DEBUG------------------------------ */
    /* ------------------------------------------------- */

    // unsafeWindow.r4 = r4;

    /* ------------------------------------------------- */
    /* --------------GLOBAL-STYLES---------------------- */
    /* ------------------------------------------------- */

    GM.addStyle(`

    /* css */

    /* Body background */
    /* Need it to fix background for not authenticated users */
    body.active-brand #wrapper {
        background-color: #efefef !important;
    }
    .b-seriesupdate__block_list_item {
        background-color: transparent !important;
    }

    /* Padding for content */
    .glory,
    .b-wrapper {
        padding-left: 30px !important;
        padding-right: 30px !important;
    }
    .glory {
        width: 960px !important;
        display: none;
    }
    .b-footer {
        width: auto !important;
    }
    .b-search__form.focused,
    .search-results {
        width: calc(100% - 60px);
        left: 30px;
    }
    .b-content__inline_items {
        width: auto;
        padding-right: 16px;
        box-sizing: border-box;
    }

    /* Remove extra right padding for content page */
    .b-content__columns {
        padding-right: 0 !important;
    }

    /* Remove extra right padding on main content listing */
    .b-content__inline_inner_mainprobar {
        padding-right: 0 !important;
    }
    .b-content__inline_inner_mainprobar .b-content__inline_item {
        margin-left: 16px !important;
    }

    /* Style status (HDrezka tracker block) */
    .b-post__status_wrapper {
        width: auto !important;
        margin: 0px 10px 0px 13px !important;
    }

    /* Style and resize rating block */
    .b-post__rating_table {
        width: 100% !important;
    }
    .b-post__rating_table td > * {
        float: right !important;
    }
    .b-post__rating_table .label {
        display: none !important;
    }

    /* Hide last episode info */
    .b-post__lastepisodeout {
        display: none !important;
    }

    /* Hide support block */
    .b-post__support_holder {
        display: none !important;
    }
    .b-post__support_holder_report .append {
        display: none !important;
    }
    .b-post__wait_status {
        display: none !important;
    }

    /* Hide share label */
    .b-post__social_holder_wrapper .share-label {
        display: none !important;
    }

    /* Hide mixedtext */
    .b-post__mixedtext {
        text-indent: -9999px !important;
        padding: 0 !important;
        height: 0;
    }

    /* !css */

    `);

    /* ------------------------------------------------- */
    /* --------------PLAYER----------------------------- */
    /* ------------------------------------------------- */

    function initPlayer() {
        GM.addStyle(`

        /* css */

        /* Style player */

        .b-container .b-player {
            padding-top: 0 !important;
        }
        @media screen {
            .b-container .b-player {
                padding-top: 0 !important;
            }
        }
        .b-player #cdnplayer-container {
            height: auto !important;
        }
        .b-player #cdnplayer {
            resize: vertical;
            overflow: auto;
            width: 100% !important;
            min-height: 200px !important;
        }
        .b-player #cdnplayer-preloader {
            height: 100%;
            width: 100%;
        }
        .b-player #cdnplayer-preloader.loading.transparent {
            background: transparent !important;
        }
        .b-player .b-simple_seasons__list {
            padding: 10px;
        }
        #oframecdnplayer > pjsdiv[style*="width: 100%; height: 100%;"] {
            /* Somehow after scale it is mess with z-index in safari after scale */
            /* This fixes the issue with controls hovered by the poster */
            z-index: -1 !important;
        }
        #pjsfrrscdnplayer {
            /* Somehow after scale it is mess with z-index in safari after scale */
            /* This fixes the issue with scroll in subtitles and volume scroll */
            z-index: -1 !important;
        }
        /* !css */

        `);

        async function CDNPlayerApi(method, value) {

            // Function that will be executed either in userscipt scope or in page scope
            function call() {
                if (typeof CDNPlayer === "undefined") {
                    console.debug(`CDNPlayer is undefined in page scope.`);
                    return;
                }
                const result = CDNPlayer.api(method, value);
                if (result === undefined) {
                    if (value === undefined) {
                        console.debug(`CDNPlayer.api(${JSON.stringify(method)})`);
                    } else {
                        console.debug(`CDNPlayer.api(${JSON.stringify(method)}, ${JSON.stringify(value)})`);
                    }
                } else {
                    if (value === undefined) {
                        console.debug(`CDNPlayer.api(${JSON.stringify(method)}): ${result}`);
                    } else {
                        console.debug(`CDNPlayer.api(${JSON.stringify(method)}, ${JSON.stringify(value)}): ${result}`);
                    }
                }
                return result;
            }

            // In Safari there is no access to page scope from userscript.
            if (typeof CDNPlayer === "undefined") {

                // Trying to execute on page scope with locatiion hack
                return await r4.utils.executeLocation(
                    // Function to execute
                    call,
                    // Variables used in function
                    {method, value}
                );
            }

            // Otherwise call it in userscript scope
            return call();
        }

        function fit() {
            if (!elements.container || !elements.player) {
                return;
            }

            if (state.fullscreen || state.expanded) {
                return;
            }

            const initial = {
                width: elements.container.offsetWidth,
                height: elements.container.offsetHeight,
            };

            if (state.resized === false && state.size?.width && state.size?.height) {
                initial.width = state.size.width;
                initial.height = state.size.height;

                state.resized = true;
                state.resizing = true;
            }

            const expected = {
                width: elements.player.offsetWidth,
            };
            const resized = {
                width: null,
                height: null,
            };

            initial.ratio = initial.width / initial.height;
            resized.width = expected.width;
            resized.height = expected.width / initial.ratio;

            if (state.resizing && resized.height < state.min.height) {
                resized.height = state.min.height;
            }

            if (!state.resizing && resized.width === initial.width && resized.height === initial.height) {
                return;
            }

            state.resizing = false;

            resize(resized);
        }

        function resize(size) {
            if (!elements.container || !elements.cdnplayer) {
                return;
            }

            if (!size?.width || !size?.height) {
                return;
            }

            elements.container.style.width = `${size.width}px`;
            elements.cdnplayer.style.height = `${size.height}px`;

            console.log(`Player resized to ${size.width | 0}x${size.height | 0}`);
        }

        function scale() {
            if (!elements.oframecdnplayer) return;

            const presantage = {
                width: 100 / state.scale,
                height: 100 / state.scale,
                left: (100 - (100 / state.scale)) / 2,
                top: (100 - (100 / state.scale)) / 2,
            }

            const transform = `scale(${state.scale})`;

            if (elements.oframecdnplayer.style.transform === transform) {
                return;
            }

            elements.oframecdnplayer.style.width = `${presantage.width}%`;
            elements.oframecdnplayer.style.height = `${presantage.height}%`;
            elements.oframecdnplayer.style.left = `${presantage.left}%`;
            elements.oframecdnplayer.style.top = `${presantage.top}%`;
            elements.oframecdnplayer.style.transform = transform;

            console.log(`Player scaled to ${state.scale * 100}%`);
        }

        function title() {
            const titleItem = document.querySelector(".b-b-post__title");
            return titleItem?.innerText;
        }

        function orig_title() {
            const titleItem = document.querySelector(".b-post__origtitle");
            return titleItem?.innerText;
        }

        function season() {
            const seasonItem = document.querySelector(".b-simple_season__item.active");
            return seasonItem && seasonItem.innerText.split(" ")[1];
        }

        function episode() {
            const episodeItem = document.querySelector(".b-simple_episode__item.active");
            return episodeItem && episodeItem.innerText.split(" ")[1];
        }

        function preloader(value) {
            elements.preloader.style.display = value ? "block" : "none";
            elements.preloader.classList.toggle("loading", value);
            elements.preloader.classList.toggle("transparent", value);
        }

        async function start() {
            sof.tv.buildCDNPlayer();
            await vast();
            return await play();
        }

        async function vast() {
            await CDNPlayerApi("update:vast", state.vast);
        }

        async function play() {
            return await CDNPlayerApi("play");
        }

        async function toggle() {
            if (state.playing === true) {
                return await pause();
            }
            return await play();
        }

        async function togglefullscreen() {
            if (state.fullscreen) {
                return await exitfullscreen();
            } else {
                return await enterfullscreen();
            }
        }

        async function volume(level) {
            const volume = await CDNPlayerApi("volume", level);
            return parseFloat(volume || 0);
        }

        function sibling(direction) {
            const activeEpisode = elements.player.querySelector(".b-simple_episode__item.active");
            if (activeEpisode?.[direction]) {
                activeEpisode[direction].click();
                setTimeout(start, 1000);
            } else {
                const activeSeason = elements.player.querySelector(".b-simple_season__item.active");
                if (activeSeason?.[direction]) {
                    activeSeason[direction].click();
                    setTimeout(start, 1000);
                }
            }
        }

        async function adjust(seconds) {
            const current = await CDNPlayerApi("time");
            const duration = await CDNPlayerApi("duration");

            if (current !== undefined && duration !== undefined) {
                const time = parseFloat(seconds + current).toFixed(3);
                return await seek(time < duration ? time : duration - 0.5);
            }
        }

        async function startadjusting(seconds) {
            wake();
            if (state.adjusting != false) {
                return;
            }
            state.adjusting = true;
            await adjust(seconds);
            setTimeout(() => {
                if (!state.interval) {
                    state.interval = setInterval(async () => {
                        if (state.adjusting == true) {
                            await adjust(seconds);
                        } else {
                            clearInterval(state.interval);
                            state.interval = null;
                        }
                    }, 30);
                }
            }, 1000);
        }

        function stopadjusting() {
            state.adjusting = false;
        }

        function wake() {
            elements.oframecdnplayer?.dispatchEvent(new Event("mousemove"));
            elements.oframecdnplayer?.dispatchEvent(new Event("mouseup"));
        }

        const next = () => sibling("nextElementSibling");
        const prev = () => sibling("previousElementSibling");
        const seek = async (seconds) => await CDNPlayerApi("seek", seconds);
        const subtitle = async (url) => await CDNPlayerApi("subtitle", url);
        const pause = async () => await CDNPlayerApi("pause");
        const stop = async () => await CDNPlayerApi("stop");
        const enterfullscreen = async () => await CDNPlayerApi("fullscreen");
        const exitfullscreen = async () => await CDNPlayerApi("exitfullscreen");
        const poster = async (poster) => await CDNPlayerApi("poster", poster);
        const mute = async () => await CDNPlayerApi(await CDNPlayerApi("muted") ? "unmute" : "mute");

        const elements = {
            player: null,
            container: null,
            cdnplayer: null,
            oframecdnplayer: null,
            pjsfrrscdnplayer: null,
            video: null,
        };

        const state = {
            playing: false,         // Player is playing now
            adjusting: false,       // Player is adjusting now (rewind or forward)
            fullscreen: false,      // Player is in fullscreen mode
            expanded: false,        // Player is expanded to full page
            collapsed: false,       // Player was already collapsed, used to prevent ferther collapses if auto expand is enabled
            resized: false,         // Player was already resized to fit the container, used to prevent ferther resizes
            vast: false,            // Player should show ads
            size: {},               // Player size
            min: {},                // Player min size
            scale: 1,               // Player scale
            interval: null,
        };

        function find(mutationsList, observer) {
            // Check for elements
            elements.player = document.querySelector("#player");
            elements.container = elements.player?.querySelector("#cdnplayer-container");
            if (elements.container && !state.size.width && !state.size.height) {
                state.size = {
                    width: elements.container.offsetWidth,
                    height: elements.container.offsetHeight,
                }
            }
            elements.cdnplayer = elements.container?.querySelector("#cdnplayer");
            elements.preloader = elements.container?.querySelector("#cdnplayer-preloader");
            elements.oframecdnplayer = elements.cdnplayer?.querySelector("#oframecdnplayer");
            elements.pjsfrrscdnplayer = elements.oframecdnplayer?.querySelector("#pjsfrrscdnplayer");
            elements.video = elements.oframecdnplayer?.querySelector("video");

            // Check if all elements are found
            const allElementsFound = Object.values(elements).every(element => !!element);

            // If all elements are found, disconnect the observer
            if (allElementsFound) {
                observer?.disconnect();
            }

        }

        // In case of scipt loaded before player loaded
        new MutationObserver(find).observe(document, { childList: true, subtree: true });

        // In case of script loaded after player loaded
        r4.settings?.afterStart(find);

        function ready() {
            return new Promise((resolve) => {
                function check() {
                    // Check if all elements are found
                    if (Object.values(elements).every(element => !!element) ) {
                        // If all elements are found, resolve the promise
                        resolve();
                    } else {
                        // Otherwise check again in 100ms
                        setTimeout(check, 100);
                    }
                }

                check();
            });
        }

        window.addEventListener("message", (event) => {
            switch (event.data?.event) {
                case "volume":
                    break;
                case "time":
                    state.time = event.data.time;
                    state.size = {
                        width: elements?.video?.videoWidth || state.size.width,
                        height: elements?.video?.videoHeight || state.size.height,
                    };
                    fit();
                    scale();
                    break;
                case "init":
                    find();
                    fit();
                    scale();
                    vast();
                    poster("hc-poster");
                    break;
                case "inited":
                    find();
                    fit();
                    scale();
                    vast();
                    poster("hc-poster");
                    elements.cdnplayer.oncontextmenu = undefined;
                    break;
                case "duration":
                    break;
                case "start":
                    break;
                case "started":
                    break;
                case "new":
                    find();
                    fit();
                    scale();
                    vast();
                    state.resized = false;
                    break;
                case "quality":
                    find();
                    fit();
                    scale();
                    state.resized = false;
                    break;
                case "play":
                    break;
                case "resumed":
                    state.playing = true;
                    document.body.classList.add("hc-playing");
                    document.body.classList.remove("hc-paused");
                    break;
                case "buffering":
                    break;
                case "waiting":
                    break;
                case "buffered":
                    find();
                    break;
                case "pause":
                    break;
                case "paused":
                    state.playing = false;
                    state.time = event.data.time;
                    document.body.classList.add("hc-paused");
                    document.body.classList.remove("hc-playing");
                    break;
                case "seek":
                    break;
                case "rewound":
                    break;
                case "fullscreen":
                    state.fullscreen = true;
                    break;
                case "exitfullscreen":
                    state.fullscreen = false;
                    fit();
                    scale();
                    break;
                case "fragment":
                    break;
                case "ui":
                    break;
                default:
                    if (event.data?.event?.startsWith("vast")) {
                        vast();
                    }
                    break;
            }
        });

        return {
            elements,
            state,
            preloader,
            start,
            play,
            pause,
            stop,
            next,
            prev,
            toggle,
            enterfullscreen,
            exitfullscreen,
            togglefullscreen,
            poster,
            fit,
            scale,
            mute,
            volume,
            vast,
            seek,
            adjust,
            startadjusting,
            stopadjusting,
            wake,
            subtitle,
            season,
            episode,
            orig_title,
            title,
            ready,
        };
    }

    /* ------------------------------------------------- */
    /* --------------CONTENT-SIZE----------------------- */
    /* ------------------------------------------------- */

    function initContentSizeTumbler() {
        GM.addStyle(`

        /* css */

        /* Content Size Tumbler */
        .r4-tumbler-content-size .r4-tumbler-point:nth-child(1) {
            border-width: 8px;
        }
        .r4-tumbler-content-size .r4-tumbler-point:nth-child(2) {
            border-width: 7px;
        }
        .r4-tumbler-content-size .r4-tumbler-point:nth-child(3) {
            border-width: 6px;
        }
        .r4-tumbler-content-size .r4-tumbler-point:nth-child(4) {
            border-width: 5px;
        }
        .r4-tumbler-content-size .r4-tumbler-point:nth-child(5) {
            border-width: 4px;
        }

        /* Content Sizes */

        /* Mobile */

        body.hc-content-size-mobile {
            min-width: 580px;
        }
        @media screen {
            body.hc-content-size-mobile {
                min-width: 580px;
            }
        }
        body.hc-content-size-mobile .glory,
        body.hc-content-size-mobile .b-footer__left,
        body.hc-content-size-mobile .glory,
        body.hc-content-size-mobile .b-wrapper {
            width: auto !important;
            min-width: 580px;
            max-width: 580px;
        }
        body.hc-content-size-mobile .b-translators__block,
        body.hc-content-size-mobile div:has(>.b-player),
        body.hc-content-size-mobile .b-post__social_holder_wrapper {
            margin-left: -30px;
            margin-right: -30px;
        }
        body.hc-content-size-mobile.hc-player-cover:not(.hc-playing) .hc-player-top-bar {
            padding: 10px;
        }
        body.hc-content-size-mobile.hc-player-cover.hc-hide-info .hc-player-top-bar-heading {
            width: calc(100% - 70px - 10px);
        }
        body.hc-content-size-mobile.hc-player-cover.hc-hide-info:not(.hc-playing) .hc-player-top-bar-cover {
            width: 70px;
        }
        body.hc-content-size-mobile .b-tophead-right {
            width: auto;
        }
        body.hc-content-size-mobile .b-tophead__subscribe-dropdown-inner {
            display: none;
        }
        body.hc-content-size-mobile .b-theme__switcher > .tumbler__wrapper {
            margin-left: 0;
        }
        body.hc-content-size-mobile .b-topnav__item {
            margin-right: 10px;
        }
        body.hc-content-size-mobile .i-sprt.dropdwn {
            display: none;
        }
        body.hc-content-size-mobile .b-search__form:not(.focused) {
            width: 25px;
            right: 30px
        }
        body.hc-content-size-mobile .b-tophead__logo {
            scale: 0.5;
            left: 45%;
        }
        body.hc-content-size-mobile .b-footer__menu_item {
            padding-right: 20px;
        }
        body.hc-content-size-mobile .b-content__filters_types {
            margin-top: 20px;
            float: left;
        }
        body.hc-content-size-mobile .b-favorites_content__sidebar {
            float: none;
        }
        body.hc-content-size-mobile .b-newest_slider_wrapper {
            display: none;
        }
        body.hc-content-size-mobile .b-collections__newest {
            display: none;
        }

        /* 1150px */

        body.hc-content-size-wide .glory,
        body.hc-content-size-wide .b-newest_slider_wrapper,
        body.hc-content-size-wide .b-wrapper {
            width: auto !important;
            min-width: 960px;
            max-width: 1150px;
        }

        /* 1340px */

        body.hc-content-size-ultrawide .glory,
        body.hc-content-size-ultrawide .b-newest_slider_wrapper,
        body.hc-content-size-ultrawide .b-wrapper {
            width: auto !important;
            min-width: 960px;
            max-width: 1340px;
        }

        /* 1530px */

        body.hc-content-size-ultraultrawide .glory,
        body.hc-content-size-ultraultrawide .b-newest_slider_wrapper,
        body.hc-content-size-ultraultrawide .b-wrapper {
            width: auto !important;
            min-width: 960px;
            max-width: 1530px;
        }

        /* 100% */

        body.hc-content-size-full .glory,
        body.hc-content-size-full .b-newest_slider_wrapper,
        body.hc-content-size-full .b-wrapper {
            width: auto !important;
            min-width: 960px;
        }

        /* Newest Slider */

        .b-newest_slider_wrapper {
            margin: auto
        }

        /* !css */

        `);

        window.addEventListener("resize", () => r4.player.fit());

        r4.settings.afterStart(() => {
            const viewport = document.querySelector("meta[name=viewport]");
            viewport.setAttribute('content', 'width=640');
        });

        function isCssApplied(element, property, value) {
            const styles = window.getComputedStyle(element);
            return styles.getPropertyValue(property) === value;
        }

        async function cssReady(element, property, value) {
            return new Promise((resolve) => {
                function check() {
                    if (isCssApplied(element, property, value)) {
                        console.log(`CSS is ready for ${element}`);
                        resolve();
                    } else {
                        console.log(`CSS is not ready for ${element}`);
                        setTimeout(check, 100);
                    }
                }

                check();
            });
        }

        r4.settings?.createTumblerSetting({
            name: "content-size",
            label: "Максимальная ширина",
            submenu: "Интерфейс",
            classes: [],
            options: [
                {
                    value: "hc-content-size-mobile",
                    class: "hc-content-size-mobile",
                    text: "580 px - Мобильный",
                    end: async () => {
                        r4.player.state.resized = false;
                        r4.player.state.scale = 1.5;
                        r4.player.state.min.height = 360;
                        await r4.player.ready();
                        await cssReady(document.querySelector(".b-wrapper"), "max-width", "580px");
                        r4.player.fit();
                        r4.player.scale();
                    },
                },
                {
                    value: "hc-content-size-default",
                    text: "960 px - Оригинальный",
                    default: true,
                    end: async () => {
                        r4.player.state.resized = false;
                        r4.player.state.scale = 1;
                        r4.player.state.min.height = 0;
                        await r4.player.ready();
                        await cssReady(document.querySelector(".b-wrapper"), "max-width", "580px");
                        r4.player.fit();
                        r4.player.scale();
                    },
                },
                {
                    value: "hc-content-size-wide",
                    class: "hc-content-size-wide",
                    text: "1150 px",
                    end: async () => {
                        r4.player.state.resized = false;
                        r4.player.state.scale = 1;
                        r4.player.state.min.height = 0;
                        await r4.player.ready();
                        await cssReady(document.querySelector(".b-wrapper"), "max-width", "1150px");
                        r4.player.fit();
                        r4.player.scale();
                    },
                },
                {
                    value: "hc-content-size-ultrawide",
                    class: "hc-content-size-ultrawide",
                    text: "1340 px",
                    end: async () => {
                        r4.player.state.resized = false;
                        r4.player.state.scale = 1;
                        r4.player.state.min.height = 0;
                        await r4.player.ready();
                        await cssReady(document.querySelector(".b-wrapper"), "max-width", "1340px");
                        r4.player.fit();
                        r4.player.scale();
                    },
                },
                {
                    value: "hc-content-size-ultraultrawide",
                    class: "hc-content-size-ultraultrawide",
                    text: "1530 px",
                    end: async () => {
                        r4.player.state.resized = false;
                        r4.player.state.scale = 1;
                        r4.player.state.min.height = 0;
                        await r4.player.ready();
                        await cssReady(document.querySelector(".b-wrapper"), "max-width", "1530px");
                        r4.player.fit();
                        r4.player.scale();
                    },
                },
                {
                    value: "hc-content-size-full",
                    class: "hc-content-size-full",
                    text: "100%",
                    end: async () => {
                        r4.player.state.resized = false;
                        r4.player.state.scale = 1;
                        r4.player.state.min.height = 0;
                        await r4.player.ready();
                        r4.player.fit();
                        r4.player.scale();
                    },
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------NAVBAR-LINKS----------------------- */
    /* ------------------------------------------------- */

    function initNavbarLinks() {

        r4.settings?.createTumblerSetting({
            name: "navbar-links",
            label: "Ссылки в панели навигации",
            submenu: "Интерфейс",
            classes: [],
            options: [
                {
                    value: "hc-navbar-links-default",
                    text: "Выкл",
                    end: () => setNavbarLinksDefaultFilter(null),
                },
                {
                    value: "hc-navbar-links-last",
                    class: "hc-navbar-links-last",
                    text: "Последние поступления",
                    end: () => setNavbarLinksDefaultFilter("last"),
                },
                {
                    value: "hc-navbar-links-popular",
                    class: "hc-navbar-links-popular",
                    text: "Популярные",
                    end: () => setNavbarLinksDefaultFilter("popular"),
                },
                {
                    value: "hc-navbar-links-soon",
                    class: "hc-navbar-links-soon",
                    text: "В ожидании",
                    end: () => setNavbarLinksDefaultFilter("soon"),
                },
                {
                    value: "hc-navbar-links-watching",
                    class: "hc-navbar-links-watching",
                    text: "Сейчас смотрят",
                    end: () => setNavbarLinksDefaultFilter("watching"),
                },
            ],
        });

        function setNavbarLinksDefaultFilter(filter) {
            function replace(elem) {
                const url = new URL(elem.href);
                url.search = filter ? new URLSearchParams({ filter }).toString() : "";
                elem.href = url;
            }

            const navbar = document.querySelector(".b-topnav");
            if (navbar) {
                navbar.querySelectorAll(".b-topnav__item-link").forEach(replace);
                navbar.querySelectorAll(".b-topnav__sub_inner .left a").forEach(replace);
            }
        }
    }

    /* ------------------------------------------------- */
    /* --------------PLAYER-SUBTITLES------------------- */
    /* ------------------------------------------------- */
    function initPlayerSubtitles(options = {}) {

        GM.addStyle(`

        /* css */

        /* Subtitles */

        .hc-subtitles-list-wrapper {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 100px;
            max-height: calc(100% - 110px);
            box-sizing: border-box !important;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            z-index: 1;
            width: 400px !important;
            right: 0;
            left: auto;
        }

        .hc-subtitles-list-container,
        .hc-subtitles-list-params {
            box-sizing: border-box;
            overflow: hidden;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            background: rgba(23, 35, 34, .7);
            border-radius: 2.3px;
        }

        .hc-subtitles-list-container {
            height: 100%;
            min-height: 120px;
        }

        .hc-subtitles-list-params {
            min-height: 34px;
            margin-bottom: 10px;
        }

        .hc-subtitles-list-error {
            padding: 20px;
            margin-bottom: 5px;
            box-sizing: border-box;
            border: 2px solid red;
            bottom: 0;
            max-height: 100%;
            font-size: 12px;
            background: rgba(23, 35, 34, .5);
            border-radius: 2.3px;
            left: 0;
            right: 0;
        }

        .hc-subtitles-list {
            bottom: 0;
        }

        /* Scrollbars */

        .hc-subtitles-list-wrapper {
            margin: 0 5px 0 10px;
        }

        .hc-subtitles-list-container,
        .hc-subtitles-list-params,
        .hc-subtitles-list-error {
            margin-right: 5px;
            position: relative;
        }

        .hc-subtitles-list-wrapper,
        .hc-subtitles-list-wrapper * {
            scrollbar-width: thin;
            scrollbar-color: rgba(23, 35, 34, .7) rgba(23, 35, 34, .5);
        }

        .hc-subtitles-list-wrapper::-webkit-scrollbar,
        .hc-subtitles-list-wrapper *::-webkit-scrollbar {
            width: 20px;
        }

        .hc-subtitles-list-wrapper::-webkit-scrollbar-track,
        .hc-subtitles-list-wrapper *::-webkit-scrollbar-track {
            background-color: transparent;
        }

        .hc-subtitles-list-wrapper::-webkit-scrollbar-thumb,
        .hc-subtitles-list-wrapper *::-webkit-scrollbar-thumb {
            background-color: rgba(23, 35, 34, .7);
            border-radius: 20px;
            border: 5px solid transparent;
            background-clip: padding-box;
        }

        /* Subtitles params */

        .hc-subtitles-list-param .hc-subtitles-list-param-title {
            float: left;
            font-size: 12px;
            position: relative;
            padding: 10px 15px;
            margin-right: 90px;
            overflow-wrap: break-word;
        }

        .hc-subtitles-list-param .hc-subtitles-list-param-input {
            float: right;
            background: rgba(43, 55, 54, .7);
            border: 0;
            width: 20px;
            color: white;
            text-align: center;
            margin: -2px 0px;
            border-radius: 3px;
            margin: 7px 15px;
        }

        .hc-subtitles-list-param.hc-subtitles-list-param-shift .hc-subtitles-list-param-input::-webkit-outer-spin-button,
        .hc-subtitles-list-param.hc-subtitles-list-param-shift .hc-subtitles-list-param-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }

        .hc-subtitles-list-param.hc-subtitles-list-param-shift .hc-subtitles-list-param-input {
            -moz-appearance: textfield;
        }

        /* Subtitles head */

        .hc-subtitles-list-container .hc-subtitles-list-head {
            font-size: 12px;
            border-bottom: 1px solid rgba(100, 100, 100, 0.7);
        }

        .hc-subtitles-list-container .hc-subtitles-list-head .hc-subtitles-item-title {
            position: relative;
            padding: 10px 15px;
            margin-right: 100px;
            overflow-wrap: break-word;
        }

        .hc-subtitles-list-container .hc-subtitles-list-head .hc-subtitles-list-params-button {
            font-size: 10px;
            line-height: 20px;
            float: right;
            padding: 7px 15px;
            text-align: center;
            cursor: pointer;
        }

        /* Subtitles loader */

        .hc-subtitles-list-container .hc-subtitles-list-loader {
            content: "";
            background-size: 48px 48px;
            background-repeat: no-repeat;
            background-image: url(${r4.images.loader});
            display: block;
            position: absolute;
            top: calc(50% + 17px);
            left: 50%;
            width: 48px;
            height: 48px;
            margin-top: -24px;
            margin-left: -24px;
            animation: spin 1s infinite linear;
            filter: invert(100%);
        }

        /* Subtitles list */

        .hc-subtitles-list .hc-subtitles-item {
            position: relative;
            display: inline-block;
            cursor: pointer;
            pointer-events: all;
            width: 100%;
            box-sizing: border-box;
            transition: opacity 0.1s linear 0s, background 0.1s linear 0s, transform 0.1s linear 0s;
            font-size: 12px;
        }

        .hc-subtitles-list .hc-subtitles-item:hover {
            background: rgba(0, 173, 239, .7);
        }

        .hc-subtitles-list .hc-subtitles-item.active {
            color: rgba(0, 173, 239, .7);
        }

        .hc-subtitles-list .hc-subtitles-item .hc-subtitles-item-title {
            position: relative;
            padding: 10px 15px;
            margin-right: 40px;
            overflow-wrap: break-word;
        }

        .hc-subtitles-list .hc-subtitles-item .hc-subtitles-item-lang {
            position: relative;
            padding: 7px 15px 7px 0;
            float: right;
            width: 25px;
            text-align: center;
        }

        /* Subtitles settings */

        .hc-setting-opensubtitles-key .r4-setting-text-value {
            display: block;
        }

        .hc-setting-opensubtitles-key .hc-opensubtitles-login,
        .hc-setting-opensubtitles-key .hc-opensubtitles-logout {
            float: right;
        }

        .hc-setting-opensubtitles-key .hc-opensubtitles-login {
            width: 100%;
            display: flex;
        }

        body.hs-opensubtitles-logged-in .hc-opensubtitles-login,
        body:not(.hs-opensubtitles-logged-in) .hc-opensubtitles-logout {
            display: none;
        }

        .hc-setting-opensubtitles-key .hc-opensubtitles-input {
            border: 0;
            border-radius: 20px;
            background: #222d33;
            background-color: #000;
            color: #fff;
            margin: 4px 0;
            width: 70px;
            font-size: 12px;
            padding: 3px 10px;
            margin-right: 10px;
            flex: auto
        }

        body.hc-style.b-theme__template__night .hc-setting-opensubtitles-key .hc-opensubtitles-input {
            background-color: #222d33;
        }

        .hc-setting-opensubtitles-key .hc-opensubtitles-button {
            height: 30px;
            background-color: #000;
            border: #1d92b2;
            border-radius: 30px;
            font-size: 12px;
            color: #fff;
            padding: 3px 10px;
        }

        .hc-setting-opensubtitles-key .hc-opensubtitles-login .hc-opensubtitles-button {
            width: 52px;
        }

        .hc-setting-opensubtitles-key .hc-opensubtitles-logout .hc-opensubtitles-button {
            width: 60px;
        }

        body.hc-style.b-theme__template__night .hc-setting-opensubtitles-key .hc-opensubtitles-button {
            background-color: #222d33;
        }

        .hc-setting-opensubtitles-error {
            padding-top: 5px;
            padding-bottom: 5px;
            float: left;
            color: red;
        }

        /* !css */

        `);

        const HELP_LINK = `<a href="https://www.opensubtitles.com">opensubtitles.com</a>`;
        const HELP_TOOLTIP =
            /* html */
            `
            <!-- html -->
            <span class="r4-tooltip" style="float: right; margin-right: -5px;">
                <span class="r4-tooltip-icon">i</span>
                <div class="tooltiptext">

                    <div>Настройка аккаунта</div>
                    <ol style="list-style: auto; margin-left: 15px;">
                        <li style="margin-top: 5px;">Перейти на сайт ${HELP_LINK}</li>
                        <li style="margin-top: 5px;">Зарегистрироваться</li>
                        <li style="margin-top: 5px;">Подтвердить регистрацию</li>
                        <li style="margin-top: 5px;">Ввести имя/пароль от созданного аккаунта</li>
                    </ol>

                    <div style="margin-top: 5px;">Использование</div>
                    <ol style="list-style: auto; margin-left: 15px;">
                        <li style="margin-top: 5px;">Настройка "Дополнительные элементы управления плеером" должна быть включена</li>
                        <li style="margin-top: 5px;">
                            Для поиска субтитров нажать кнопку расположенную
                            в правом нижнем углу плеера
                        </li>
                        <li style="margin-top: 5px;">
                            Выбрать в списке подходящие субтитры
                        </li>
                        <li style="margin-top: 5px;">
                            После нажатия на пункт списка плеер загрузит и отобразит выбрананые субтитры
                        </li>
                        <li style="margin-top: 5px;">
                            При рассинхранизации есть 2 способа синхронизировать видео и субтитры
                            <ul style="list-style: circle; margin-left: 15px;">
                                <li style="margin-top: 5px;">В настройках плеера (максимум ±5 секунд)</li>
                                <li style="margin-top: 5px;">В списке найденых субтитров перед выбором выставить значение в колонке "Сдвиг" (в секундах)</li>
                            </ul>
                        </li>
                    </ol>


                    <div style="margin-top: 15px;">
                        <small>
                            Способы увеличения количества загрузок:
                            <br>
                            <a href="https://www.opensubtitles.com/en/users/vip">opensubtitles.com/en/users/vip</a>
                        </small>
                    </div>
                </div>
            </span>
            <!-- !html -->
        `;

        const elements = {
            settingWrapper: null,
            subtitlesListWrapper: null,
            subtitlesListError: null,
            subtitlesListParams: null,
            subtitlesListContainer: null,
            subtitlesListLoader: null,
            subtitlesList: null,
        }

        const state = {
            opened: false,
            data: {
                download: {},
            }
        }

        function createSettingWrapper() {
            elements.settingWrapper = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="r4-setting hc-setting-opensubtitles-key">
                    <span class="r4-setting-text-value hc-setting-opensubtitles-error"></span>
                    <div class="r4-setting-text-block">
                        <span class="r4-setting-text-value">${HELP_LINK}</span>
                        <span class="r4-setting-text-value hc-settings-text-profile"></span>
                        <span class="r4-setting-text-value hc-settings-text-download"></span>
                    </div>
                    ${HELP_TOOLTIP}
                    <form class="hc-opensubtitles-login">
                        <input class="hc-opensubtitles-input" name="username" placeholder="Username" type="text">
                        <input class="hc-opensubtitles-input" name="password" placeholder="Password" type="password">
                        <input class="hc-opensubtitles-button" type="submit" value="Вход">
                    </form>
                    <form class="hc-opensubtitles-logout">
                        <input class="hc-opensubtitles-button" type="submit" value="Выход">
                    </form>
                </div>
                <!-- !html -->
                `
            );

            elements.settingWrapper.querySelector("form.hc-opensubtitles-login").addEventListener("submit", login);
            elements.settingWrapper.querySelector("form.hc-opensubtitles-logout").addEventListener("submit", logout);

            r4.settings?.afterStart(async () => {
                const key = await r4.settings.getSetting("hs-opensubtitles-key");
                if (key) {
                    document.body.classList.add("hs-opensubtitles-logged-in");
                    loadProfile(key);
                }
            });

            return elements.settingWrapper;
        }

        function login(event) {
            event.preventDefault();
            clearError();
            const formData = new FormData(event.target);
            GM.xmlHttpRequest({
                method: "POST",
                url: "https://api.opensubtitles.com/api/v1/login",
                data: JSON.stringify({
                    username: formData.get('username'),
                    password: formData.get('password'),
                }),
                headers: {
                    "Api-Key": options?.key,
                    "Content-Type": "application/json",
                    "User-Agent": r4.useragent,
                },
                onload(response) {
                    console.debug(`Response ${response.status} for ${response.finalUrl}`, {response});
                    if (response.status !== 200) {
                        showError(parseOpensubtitlesError(response));
                        return;
                    }
                    const responseJSON = JSON.parse(response.responseText);
                    r4.settings.setSetting("hs-opensubtitles-key", responseJSON.token);
                    document.body.classList.add("hs-opensubtitles-logged-in");
                    loadProfile(responseJSON.token);
                },
                onerror(e) {
                    console.debug("Error:", {e});
                    showError("Something went wrong");
                },
            });
        }

        function logout(event) {
            event.preventDefault();
            r4.settings.setSetting("hs-opensubtitles-key", "");
            document.body.classList.remove("hs-opensubtitles-logged-in");
            state.data.download = {
                allowed_downloads: null,
                remaining_downloads: null,
                reset_time_utc: null,
            }
            clearUserData();
            clearDownloadData();
            clearError();
        }

        function createRemainingTime(time_utc) {
            const diff = (new Date(time_utc) - new Date()) / 1000;
            const hours = Math.floor(diff / (60 * 60));
            const minutes = `0${Math.floor((diff % (60 * 60)) / 60)}`;
            const seconds = `0${Math.floor(diff % 60)}`;
            return `${hours}:${minutes.slice(minutes.length - 2)}:${seconds.slice(seconds.length - 2)}`;
        }

        function showDownloadData() {
            clearDownloadData();
            const downloadSpan = elements.settingWrapper.querySelector(".hc-settings-text-download");
            if (state.data.download.allowed_downloads) {
                const allowed_downloads = state.data.download.allowed_downloads;
                downloadSpan.innerHTML += `<p>Разрешено загрузок в день: ${allowed_downloads}</p>`;
            }
            if (state.data.download.remaining_downloads) {
                let remaining_downloads = state.data.download.remaining_downloads;
                if (remaining_downloads < 0) {
                    remaining_downloads = 0;
                }
                downloadSpan.innerHTML += `<p>Осталось загрузок: ${remaining_downloads}</p>`;
            }
            if (state.data.download.reset_time_utc) {
                const remaining = createRemainingTime(state.data.download.reset_time_utc);
                if (remaining.startsWith("-")) {
                    state.data.download = {
                        allowed_downloads: state.data.download.allowed_downloads,
                        remaining_downloads: null,
                        reset_time_utc: null,
                    };
                } else {
                    downloadSpan.innerHTML += `<p>Сброс счетчика через ${remaining}</p>`;
                }
            }
        }

        function clearDownloadData() {
            const downloadSpan = elements.settingWrapper.querySelector(".hc-settings-text-download");
            downloadSpan.innerHTML = "";
        }

        function showError(text) {
            const textErrorSpan = elements.settingWrapper.querySelector(".hc-setting-opensubtitles-error");
            textErrorSpan.innerHTML = text;
        }

        function clearError() {
            const textErrorSpan = elements.settingWrapper.querySelector(".hc-setting-opensubtitles-error");
            textErrorSpan.innerHTML = "";
        }

        function clearUserData() {
            const profileSpan = elements.settingWrapper.querySelector(".hc-settings-text-profile");
            profileSpan.innerHTML = "";
            clearDownloadData();
        }

        function showUserData(id) {
            const profileSpan = elements.settingWrapper.querySelector(".hc-settings-text-profile");
            profileSpan.innerHTML = `Идентификатор пользователя: ${id}`;
            showDownloadData();
        }

        function loadProfile(key) {
            GM.xmlHttpRequest({
                method: "GET",
                url: "https://api.opensubtitles.com/api/v1/infos/user",
                headers: {
                    "Api-Key": options?.key,
                    "Authorization": `Bearer ${key || ""}`,
                    "User-Agent": r4.useragent,
                    "Content-Type": "application/json",
                },
                onload(response) {
                    console.debug(`Response ${response.status} for ${response.finalUrl}`, {response});
                    if (response.status !== 200) {
                        showError(parseOpensubtitlesError(response));
                        return;
                    }
                    const responseJSON = JSON.parse(response.responseText);
                    state.data.download = {
                        allowed_downloads: responseJSON.data.allowed_downloads,
                        remaining_downloads: responseJSON.data.remaining_downloads,
                        reset_time_utc: responseJSON.data.reset_time_utc,
                    };
                    showUserData(responseJSON.data.user_id);
                },
                onerror(e) {
                    console.debug("Error:", {e});
                    showError("Something went wrong");
                },
            });
        }

        function parseOpensubtitlesError(response) {
            localStorage.setItem("hc-opensubtitles-error-status", response.status);
            localStorage.setItem("hc-opensubtitles-error-text", response.responseText);
            try {
                const responseJSON = JSON.parse(response.responseText);
                if (responseJSON.message) {
                    return responseJSON.message;
                }
                if (responseJSON.errors) {
                    return responseJSON.errors.join("<br>");
                }
                return responseJSON;
            } catch (e) {
                return response.responseText;
            }
        }

        function showSubtitlesListError(innerHTML) {
            elements.subtitlesListError.classList.remove("hidden");
            elements.subtitlesListError.innerHTML = innerHTML;
        }

        function hideSubtitlesListError() {
            elements.subtitlesListError.classList.add("hidden");
        }

        function getImdbId(imdbUrl) {
            showSubtitlesListLoader();
            return new Promise((resolve) => {
                GM.xmlHttpRequest({
                    method: "POST",
                    headers: {
                        "Referer": location.href,
                        "User-Agent": r4.useragent,
                    },
                    url: imdbUrl,
                    onload(response) {
                        console.debug(`Response ${response.status} for ${response.finalUrl}`, {response});
                        hideSubtitlesListLoader();
                        if (response.status !== 200) {
                            resolve();
                            return;
                        }
                        const pageConstPattern = /<meta property="imdb:pageConst" content="tt(?<id>[^"]*)"[\/]{0,1}>/;
                        const pageConstResult = pageConstPattern.exec(response.responseText);
                        if (!pageConstResult?.groups?.id) {
                            console.debug("Can't find id on imdb");
                            resolve();
                            return;
                        }
                        resolve(pageConstResult.groups.id);
                        hideSubtitlesListError();
                    },
                    onerror(e) {
                        console.debug("Error:", {e});
                        hideSubtitlesListLoader();
                        resolve();
                    },
                });
            });
        }

        async function searchSubtitles(params, key) {
            return new Promise((resolve) => {
                showSubtitlesListLoader();
                GM.xmlHttpRequest({
                    method: "GET",
                    url: `https://api.opensubtitles.com/api/v1/subtitles?${new URLSearchParams(params)}`,
                    headers: {
                        "Api-Key": options?.key,
                        "Authorization": `Bearer ${key || ""}`,
                        "User-Agent": r4.useragent,
                    },
                    onload(response) {
                        console.debug(`Response ${response.status} for ${response.finalUrl}`, {response});
                        hideSubtitlesListLoader();
                        if (response.status !== 200) {
                            showSubtitlesListError(parseOpensubtitlesError(response));
                            resolve();
                            return;
                        }
                        const responseJSON = JSON.parse(response.responseText);
                        if (responseJSON.total_count === 0) {
                            showSubtitlesListError("No subtitles found");
                            resolve();
                            return;
                        }
                        resolve(responseJSON);
                        hideSubtitlesListError();
                    },
                    onerror(e) {
                        console.debug("Error:", {e});
                        showSubtitlesListError("Something went wrong");
                        hideSubtitlesListLoader();
                        resolve();
                    },
                });
            });
        }

        async function loadSubtitlesLink(data, key) {
            return new Promise((resolve) => {
                showSubtitlesListLoader();
                GM.xmlHttpRequest({
                    method: "POST",
                    url: "https://api.opensubtitles.com/api/v1/download",
                    data: JSON.stringify(data),
                    headers: {
                        "Api-Key": options?.key,
                        "Authorization": `Bearer ${key || ""}`,
                        "User-Agent": r4.useragent,
                        "Content-Type": "application/json",
                    },
                    onload(response) {
                        console.debug(`Response ${response.status} for ${response.finalUrl}`, {response});
                        hideSubtitlesListLoader();
                        if (response.status !== 200) {
                            showSubtitlesListError(parseOpensubtitlesError(response));
                            resolve();
                            return;
                        }
                        const responseJSON = JSON.parse(response.responseText);
                        state.data.download = {
                            allowed_downloads: responseJSON.remaining + responseJSON.requests,
                            remaining_downloads: responseJSON.remaining,
                            reset_time_utc: responseJSON.reset_time_utc,
                        };
                        resolve(responseJSON.link);
                        hideSubtitlesListError();
                    },
                    onerror(e) {
                        console.debug("Error:", {e});
                        showSubtitlesListError("Something went wrong");
                        hideSubtitlesListLoader();
                        resolve();
                    },
                });
            });
        }

        function pageSubtitles(data, key) {
            for (const item of data || []) {
                for (const file of item.attributes.files) {
                    const playerSubtitlesItem = r4.utils.fromHTML(
                        /* html */
                        `
                        <!-- html -->
                        <li class="hc-subtitles-item">
                            <div class="hc-subtitles-item-lang">${item.attributes.language}</div>
                            <div class="hc-subtitles-item-title">${file.file_name || item.attributes.release}</div>
                        </li>
                        <!-- !html -->
                        `
                    );

                    playerSubtitlesItem.addEventListener("click", async (event) => {
                        Array.from(playerSubtitlesItem.parentElement.children).forEach((elem) => {
                            elem.classList.remove("active");
                        });
                        playerSubtitlesItem.classList.add("active");
                        const shift = elements.subtitlesListParams.querySelector(
                            ".hc-subtitles-list-param-shift .hc-subtitles-list-param-input"
                        ).value;
                        const link = await loadSubtitlesLink({
                            file_id: file.file_id,
                            timeshift: shift,
                        }, key);
                        if (link) {
                            await r4.player.subtitle(link);
                            closeSubtitles();
                        }
                    });

                    elements.subtitlesList.appendChild(playerSubtitlesItem);
                }
            }
        }

        async function findSubtitles(url) {
            const params = {}
            const id = await getImdbId(url);
            if (id) {
                console.debug(`Search subtitles by imdb id: ${id}`);
                params.imdb_id = id;
            } else {
                const query = r4.player.orig_title() || r4.player.title();
                console.debug(`Search subtitles by query: ${query}`);
                params.query = query;
            }
            params.languages = "en,uk,ru";
            params.page = 1;
            params.season_number = r4.player.season();
            params.episode_number = r4.player.episode();

            const key = await r4.settings.getSetting("hs-opensubtitles-key");

            let data = await searchSubtitles(params, key);
            pageSubtitles(data?.data, key);
            if (data?.total_pages > 1) {
                for (let page = 2; page <= data.total_pages; page++) {
                    params.page = page;
                    data = await searchSubtitles(params, key);
                    pageSubtitles(data?.data, key);
                }
            }
        }

        function openSubtitles() {
            const imdbLink = document.querySelector(".b-post__info_rates.imdb a");
            if (!imdbLink) return;
            if (!r4.player.elements.video) return;

            elements.subtitlesListWrapper.classList.remove("hidden");

            if (Array.from(elements.subtitlesList.querySelectorAll(".hc-subtitles-item")).length === 0) {
                findSubtitles(imdbLink.href);
            }

            state.opened = true;

            const interval = setInterval(() => {
                if (state.opened) {
                    r4.player.elements.oframecdnplayer.dispatchEvent(new Event("mousemove"));
                } else {
                    clearInterval(interval);
                }
            }, 1000);
        }

        function closeSubtitles() {
            if (!r4.player.elements.video) return;
            elements.subtitlesListWrapper.classList.add("hidden");
            state.opened = false;
        }

        function clearSubtitles() {
            elements.subtitlesList.querySelectorAll(".hc-subtitles-item").forEach((elem) => {
                elem.remove();
            });
            closeSubtitles();
        }

        function toggleSubtitles() {
            if (elements.subtitlesListWrapper.classList.contains("hidden")) {
                openSubtitles();
            } else {
                closeSubtitles();
            }
        }

        function showSubtitlesListLoader() {
            elements.subtitlesListLoader.classList.remove("hidden");
        }

        function hideSubtitlesListLoader() {
            elements.subtitlesListLoader.classList.add("hidden");
        }

        window.addEventListener("message", (event) => {
            switch (event.data?.event) {
                case "inited":
                    r4.player.elements.oframecdnplayer?.appendChild(elements.subtitlesListWrapper);
                    break;
            }
        });

        r4.settings?.addElementSetting(createSettingWrapper(), {
            submenu: "Субтитры",
        });

        r4.settings?.afterStart(() => {
            elements.subtitlesListWrapper = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="hc-subtitles-list-wrapper hidden">
                    <div class="hc-subtitles-list-error hidden"></div>
                    <div class="hc-subtitles-list-params hidden">
                        <div class="hc-subtitles-list-param hc-subtitles-list-param-shift">
                            <input class="hc-subtitles-list-param-input" type="number" value="0">
                            <div class="hc-subtitles-list-param-title">Сдвиг</div>
                        </div>
                    </div>
                    <div class="hc-subtitles-list-container">
                        <div class="hc-subtitles-list-head">
                            <div class="hc-subtitles-list-params-button">Параметры загрузки</div>
                            <div class="hc-subtitles-item-title">Название</div>
                        </div>
                        <ul class="hc-subtitles-list"></ul>
                        <div class="hc-subtitles-list-loader hidden"></div>
                    </div>
                </div>
                <!-- !html -->
                `
            )
            elements.subtitlesListError = elements.subtitlesListWrapper.querySelector(".hc-subtitles-list-error");
            elements.subtitlesListParams = elements.subtitlesListWrapper.querySelector(".hc-subtitles-list-params");
            elements.subtitlesListContainer = elements.subtitlesListWrapper.querySelector(".hc-subtitles-list-container");
            elements.subtitlesListLoader = elements.subtitlesListContainer.querySelector(".hc-subtitles-list-loader");
            elements.subtitlesList = elements.subtitlesListContainer.querySelector(".hc-subtitles-list");

            elements.subtitlesListWrapper.querySelector(".hc-subtitles-list-params-button").addEventListener("click", () => {
                elements.subtitlesListParams.classList.toggle("hidden");
            });
        });

        setInterval(() => {
            showDownloadData();
        }, 1000);

        return {
            toggle: toggleSubtitles,
            clear: clearSubtitles,
        };
    }

    /* ------------------------------------------------- */
    /* --------------PLAYER-EXTRA-CONTROLS-------------- */
    /* ------------------------------------------------- */

    function initPlayerExtraControls() {
        GM.addStyle(`

        /* css */

        body.hc-player-full-page {
            height: 100%;
            overflow: hidden;
        }

        body.hc-player-full-page .b-player {
            display: flex;
            flex-direction: column;
            position: fixed !important;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            width: 100% !important;
            height: 100% !important;
            z-index: 1000;
        }

        body.hc-player-full-page #cdnplayer-container {
            width: 100% !important;
            height: 100% !important;
        }

        body.hc-player-full-page #cdnplayer {
            width: 100% !important;
            height: 100% !important;
        }

        body.hc-player-full-page .b-post__status_wrapper {
            display: none !important;
        }

        body.hc-player-full-page .b-simple_seasons__list {
            margin: 0;
        }

        body.hc-player-full-page .b-simple_seasons__list {
            display: none !important;
        }

        body.hc-player-full-page .b-simple_episodes__list {
            display: none !important;
        }

        body.hc-player-full-page footer {
            display: none !important;
        }

        .hc-player-top-bar {
            display: none;
            box-sizing: border-box !important;
            position: absolute;
            width: 100%;
            top: 0;
            left: 0;
            padding: 10px;
            background: linear-gradient(
                to bottom,
                rgba(0, 0, 0, .6) 0%,
                rgba(0, 0, 0, .1) 70%,
                rgba(0, 0, 0, 0) 100%
            );
            pointer-events: none;
            z-index: 1;
            transition: all .5s ease-out;
        }


        body.hc-player-cover:not(.hc-playing) .hc-player-top-bar {
            padding: 30px;
            transition: all .5s ease-in;
        }

        .hc-player-top-bar-enabled .hc-player-top-bar {
            display: block;
        }

        .hc-player-top-bar:hover {
            display: block !important;
            visibility: visible !important;
        }

        .hc-player-top-bar-heading {
            display: inline-block;
            margin-bottom: 20px;
            width: calc(100% - 200px - 10px);
        }

        .hc-player-top-bar-cover {
            float: left;
            margin-right: 10px;
            width: 43px;
            border-radius: 3px;
            transition: all .5s ease-out;
        }

        body.hc-player-cover.hc-hide-info:not(.hc-playing) .hc-player-top-bar-cover {
            width: 200px;
            border-radius: 7px;
            transition: all .5s ease-in;
        }

        .hc-player-top-bar-title {
            display: inline-block;
            cursor: pointer;
            position: relative;
            text-align: left;
            line-height: 20px;
            font-size: 20px;
            font-weight: bold;
            pointer-events: all;
            padding-left: 10px;
            user-select: none;
        }

        body.hc-player-full-page .hc-player-top-bar-title {
            padding-left: 30px;
        }

        .hc-player-top-bar-origtitle {
            display: inline-block;
            position: relative;
            text-align: left;
            line-height: 14px;
            font-size: 14px;
            pointer-events: all;
            padding-left: 10px;
            user-select: none;
            padding-top: 5px;
            opacity: 70%;
        }

        body.hc-player-full-page .hc-player-top-bar-origtitle {
            padding-left: 30px;
        }

        .hc-player-top-bar-episode {
            display: inline-block;
            position: relative;
            text-align: left;
            line-height: 14px;
            font-size: 12px;
            pointer-events: all;
            padding-left: 10px;
            user-select: none;
            padding-top: 5px;
            opacity: 50%;
        }

        body.hc-player-full-page .hc-player-top-bar-episode {
            padding-left: 30px;
        }

        body.hc-player-full-page .hc-player-top-bar-title:before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 20px;
            height: 20px;
            margin-right: 10px;
            background-size: 20px 20px;
            background-repeat: no-repeat;
            background-image: url(${r4.images.arrow});
            filter: invert(100%) sepia(95%) saturate(21%) hue-rotate(280deg) brightness(106%) contrast(106%);
            transform: rotate(-90deg);
        }

        .hc-player-control {
            display: none;
            content: '';
            position: relative;
            float: left;
            cursor: pointer;
            pointer-events: all;
            z-index: 2;
            border-radius: 2.3px;
            background: rgba(23, 35, 34, .7);
            transition: opacity 0.1s linear 0s, background 0.1s linear 0s, transform 0.1s linear 0s;
            cursor: point;
        }

        .hc-player-control:hover {
            background: rgba(0, 173, 239, .7);
        }

        .hc-player-extra-controls-enabled .hc-player-control {
            display: block;
        }

        .hc-player-extra-controls-enabled .hc-player-extra-controls-hidden {
            display: none !important;
        }

        .hc-player-controls-left {
            position: absolute;
            bottom: 56px;
            left: 10px;
        }

        .hc-player-controls-left .hc-player-control {
            margin-right: 10px;
        }

        .hc-player-controls-right {
            position: absolute;
            bottom: 56px;
            right: 10px;
        }

        .hc-player-controls-right .hc-player-control {
            margin-left: 10px;
        }

        .hc-player-control-prev,
        .hc-player-control-next,
        .hc-player-control-replay,
        .hc-player-control-forward {
            width: 28px;
            height: 35px;
        }

        .hc-player-control-expand,
        .hc-player-control-pip,
        .hc-player-control-subtitles {
            width: 41px;
            height: 35px;
        }

        body:not(.hs-opensubtitles-logged-in) .hc-player-control-subtitles {
            display: none;
        }

        .hc-player-control-icon {
            content: '';
            position: absolute;
            background-repeat: no-repeat;
            filter: invert(100%);
        }

        .hc-player-control-prev-icon {
            top: 10px;
            left: 7px;
            width: 15px;
            height: 15px;
            background-size: 15px 15px;
            background-image: url(${r4.images.next});
            transform: rotate(180deg);
        }

        .hc-player-control-next-icon {
            top: 10px;
            left: 7px;
            width: 15px;
            height: 15px;
            background-size: 15px 15px;
            background-image: url(${r4.images.next});
        }

        .hc-player-control-replay-icon {
            top: 10px;
            left: 7px;
            width: 15px;
            height: 15px;
            background-size: 15px 15px;
            background-image: url(${r4.images.replay});
        }

        .hc-player-control-forward-icon {
            top: 10px;
            left: 7px;
            width: 15px;
            height: 15px;
            background-size: 15px 15px;
            background-image: url(${r4.images.forward});
        }

        .hc-player-control-expand-icon {
            top: 8px;
            right: 11px;
            width: 20px;
            height: 20px;
            background-size: 20px 20px;
            background-image: url(${r4.images.expand});
        }

        .hc-player-control-pip-icon {
            top: 8px;
            right: 11px;
            width: 20px;
            height: 20px;
            background-size: 20px 20px;
            background-image: url(${r4.images.pip});
        }

        .hc-player-control-subtitles-icon {
            top: 8px;
            right: 11px;
            width: 20px;
            height: 20px;
            background-size: 20px 20px;
            background-image: url(${r4.images.subtitles});
        }

        body.hc-player-full-page .hc-player-control-expand-icon {
            background-image: url(${r4.images.collapse}) !important;
            transform: rotate(-90deg);
        }

        body.hc-player-full-page .b-footer {
            margin-top: 0 !important;
        }

        .hc-player-control-large-next,
        .hc-player-control-large-prev {
            position: absolute;
            width: 100%;
            height: 200%;
            top: -50%;
            background: #00000000;
            border-radius: 50%;
            transition: background-color 0.5s ease;
            display: none;
        }

        .hc-player-extra-controls-enabled.hc-player-triple-click-enabled .hc-player-control-large-next,
        .hc-player-extra-controls-enabled.hc-player-triple-click-enabled .hc-player-control-large-prev {
            display: block;
        }

        .hc-player-control-large-next {
            right: -75%;
        }

        .hc-player-control-large-prev {
            left: -75%;
        }

        .hc-player-control-large-prev.active:before,
        .hc-player-control-large-next.active:before {
            content: '';
            background-repeat: no-repeat;
            background-size: 30px 30px;
            background-position: center;
            height: 100%;
            width: 100%;
            position: absolute;
            filter: invert(100%) sepia(95%) saturate(21%) hue-rotate(280deg) brightness(106%) contrast(106%);
            opacity: .5;
        }

        .hc-player-control-large-prev.active:before {
            margin-left: calc(75% / 2);
        }

        .hc-player-control-large-next.active:before {
            margin-left: calc(-75% / 2);
        }

        .hc-player-control-large-prev.replay:before {
            background-image: url(${r4.images.replay});
        }

        .hc-player-control-large-next.forward:before {
            background-image: url(${r4.images.forward});
        }

        .hc-player-control-large-prev.prev:before {
            background-image: url(${r4.images.next});
            transform: rotate(180deg);
        }

        .hc-player-control-large-next.next:before {
            background-image: url(${r4.images.next});
        }

        .hc-player-control-large-prev.active,
        .hc-player-control-large-next.active {
            background: #00000070;
        }

        #oframecdnplayer > pjsdiv {
            z-index: 1;
        }

        #oframecdnplayer > pjsdiv[style*="width: 100%; height: 100%;"] {
            z-index: 0;
        }

        /* !css */

        `);

        const config = {
            multiClick: {
                delay: 500,
                timeout: 350,
            }
        }

        const elements = {
            topBar: null,
            controlsLeft: null,
            controlsRight: null,
            controlsLargePrev: null,
            controlsLargeNext: null,
        };

        r4.settings?.afterStart(() => {

            elements.controlsLeft = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="hc-player-controls-left">
                    <div class="hc-player-control hc-player-control-prev">
                        <div class="hc-player-control-icon hc-player-control-prev-icon"></div>
                    </div>
                    <div class="hc-player-control hc-player-control-next">
                        <div class="hc-player-control-icon hc-player-control-next-icon"></div>
                    </div>
                    <div class="hc-player-control hc-player-control-replay">
                        <div class="hc-player-control-icon hc-player-control-replay-icon"></div>
                    </div>
                    <div class="hc-player-control hc-player-control-forward">
                        <div class="hc-player-control-icon hc-player-control-forward-icon"></div>
                    </div>
                </div>
                <!-- !html -->
                `
            );

            elements.controlsRight = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="hc-player-controls-right">
                    <div class="hc-player-control hc-player-control-subtitles">
                        <div class="hc-player-control-icon hc-player-control-subtitles-icon"></div>
                    </div>
                    <div class="hc-player-control hc-player-control-pip">
                        <div class="hc-player-control-icon hc-player-control-pip-icon"></div>
                    </div>
                    <div class="hc-player-control hc-player-control-expand">
                        <div class="hc-player-control-icon hc-player-control-expand-icon"></div>
                    </div>
                </div>
                <!-- !html -->
                `
            );

            elements.controlsLeft.querySelectorAll(".hc-player-control").forEach(playerControlFreeze);
            elements.controlsRight.querySelectorAll(".hc-player-control").forEach(playerControlFreeze);

            elements.controlsLeft.querySelector(".hc-player-control-prev").addEventListener("click", r4.player.prev);
            elements.controlsLeft.querySelector(".hc-player-control-next").addEventListener("click", r4.player.next);
            elements.controlsLeft.querySelector(".hc-player-control-replay").addEventListener("mousedown", () => r4.player.startadjusting(-5));
            elements.controlsLeft.querySelector(".hc-player-control-replay").addEventListener("mouseup", r4.player.stopadjusting);
            elements.controlsLeft.querySelector(".hc-player-control-forward").addEventListener("mousedown", () => r4.player.startadjusting(5));
            elements.controlsLeft.querySelector(".hc-player-control-forward").addEventListener("mouseup", r4.player.stopadjusting);

            elements.controlsRight.querySelector(".hc-player-control-subtitles").addEventListener("click", () => {
                r4.subtitles.toggle();
            });
            elements.controlsRight.querySelector(".hc-player-control-expand").addEventListener("click", toggle);

            const cover = document.querySelector(".b-sidecover img");

            elements.topBar = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="hc-player-top-bar">
                    <div class="hc-player-top-bar-heading">
                        <div><span class="hc-player-top-bar-title"></span></div>
                        <div><span class="hc-player-top-bar-origtitle"></span></div>
                        <div><span class="hc-player-top-bar-episode"></span></div>
                    </div>
                    <img class="hc-player-top-bar-cover" src="${cover?.src || ''}"></div>
                </div>
                <!-- !html -->
                `
            );

            elements.topBar.querySelector(".hc-player-top-bar-title").addEventListener("click", toggle);

            elements.controlsLargePrev = createControlLarge(
                "hc-player-control-large-prev",
                r4.player.toggle,
                r4.player.togglefullscreen,
                (event) => playerControlLargeAction(event, "prev", r4.player.prev),
                (event) => playerControlLargeAction(event, "replay", () => r4.player.adjust(-5)),
            );

            elements.controlsLargeNext = createControlLarge(
                "hc-player-control-large-next",
                r4.player.toggle,
                r4.player.togglefullscreen,
                (event) => playerControlLargeAction(event, "prev", r4.player.next),
                (event) => playerControlLargeAction(event, "forward", () => r4.player.adjust(5)),
            );
        });

        function appendElements() {
            if (r4.player.elements.oframecdnplayer) {
                r4.player.elements.oframecdnplayer.appendChild(elements.topBar);
                r4.player.elements.oframecdnplayer.appendChild(elements.controlsLeft);
                r4.player.elements.oframecdnplayer.appendChild(elements.controlsRight);
                r4.player.elements.oframecdnplayer.appendChild(elements.controlsLargePrev);
                r4.player.elements.oframecdnplayer.appendChild(elements.controlsLargeNext);
                initPIPControl(r4.player.elements.oframecdnplayer);
                if (!document.querySelector(".b-simple_episodes__list")) {
                    r4.player.elements.oframecdnplayer.querySelector(".hc-player-control-prev").classList.add("hidden");
                    r4.player.elements.oframecdnplayer.querySelector(".hc-player-control-next").classList.add("hidden");
                    r4.player.elements.oframecdnplayer.querySelector(".hc-player-control-large-prev").classList.add("hidden");
                    r4.player.elements.oframecdnplayer.querySelector(".hc-player-control-large-prev").classList.add("hidden");
                }
            }
        }

        function collapse() {
            document.body.classList.remove("hc-player-full-page");
            r4.player.state.expanded = false;
            r4.player.state.collapsed = true;
            r4.player.fit();
        }

        function expand() {
            document.body.classList.add("hc-player-full-page");
            r4.player.state.expanded = true;
        }

        function toggle() {
            if (r4.player.state.fullscreen == false) {
                if (r4.player.state.expanded == true) {
                    collapse();
                } else if (r4.player.state.expanded == false) {
                    expand();
                }
            } else {
                r4.player.exitfullscreen();
            }
        }

        function setTitle() {
            if (!elements.topBar) return;
            const postTitle = document.querySelector(".b-post__title h1");
            if (!postTitle) return;
            elements.topBar.querySelector(".hc-player-top-bar-title").innerText = postTitle.innerText;
        }

        function setOrigTitle() {
            if (!elements.topBar) return;
            const postOrigTitle = document.querySelector(".b-post__origtitle");
            if (!postOrigTitle) return;
            elements.topBar.querySelector(".hc-player-top-bar-origtitle").innerText = postOrigTitle.innerText;
        }

        function setSeasonAndEpisode() {
            if (!elements.topBar) return;
            const season = r4.player.season();
            const episode = r4.player.episode();
            if (!(season && episode)) return;
            elements.topBar.querySelector(".hc-player-top-bar-episode").innerText = `Сезон ${season} - Серия ${episode}`;
        }

        function initPIPControl(player) {
            const playerControlPIP = elements.controlsRight.querySelector(".hc-player-control-pip")
            playerControlPIP.classList.add("hidden");
            Array.from(player.querySelectorAll('pjsdiv[style*="top: 20px;"]')).forEach((elem) => {
                if (!elem) return;

                const pip = elem.querySelector('pjsdiv[style*="top: -17.5px; left: -17.5px;"]');
                if (!pip) return;

                new MutationObserver(() => {
                    if (elem.style.display === "none") {
                        playerControlPIP.classList.add("hidden");
                        elem.classList.remove("hc-player-extra-controls-hidden");
                    } else {
                        playerControlPIP.classList.remove("hidden");
                        elem.classList.add("hc-player-extra-controls-hidden");
                    }
                }).observe(elem, {
                    attributes: true,
                    attributeFilter: ["style"],
                });

                playerControlPIP.addEventListener("click", () => {
                    pip.click();
                });
            });
        }

        function playerControlFreeze(elem) {
            let mouseon = false;

            elem.addEventListener("mouseenter", () => {
                mouseon = true;
                const interval = setInterval(() => {
                    if (mouseon) {
                        r4.player.elements.oframecdnplayer.dispatchEvent(new Event("mousemove"));
                    } else {
                        clearInterval(interval);
                    }
                }, 1000);
            });

            elem.addEventListener("mouseleave", () => {
                mouseon = false;
            });
        }

        function createControlLarge(className, singleClick, doubleClick, tripleClick, multiClick) {
            const playerControlLarge = document.createElement("div");
            playerControlLarge.classList.add(className);

            let clicks = 0;
            let timer;

            playerControlLarge.addEventListener("click", (event) => {
                clearTimeout(timer);
                clicks++;
                if (clicks < 4) {
                    timer = setTimeout(() => {
                        if (clicks == 1) singleClick(event);
                        else if (clicks == 2) doubleClick(event);
                        else if (clicks == 3) tripleClick(event);
                        clicks = 0;
                    }, config.multiClick.timeout);
                } else {
                    multiClick(event);
                    timer = setTimeout(() => {
                        clicks = 0;
                    }, config.multiClick.timeout);
                }
            });

            return playerControlLarge;
        }

        function playerControlLargeAction(event, actionClass, callback) {
            event.target.classList.add("active");
            event.target.classList.add(actionClass);
            setTimeout(() => {
                event.target.classList.remove("active");
                event.target.classList.remove(actionClass);
                callback();
            }, config.multiClick.delay);
        }

        window.addEventListener("message", (event) => {
            switch (event.data?.event) {
                case "init":
                    appendElements();
                    setTitle();
                    setOrigTitle();
                    setSeasonAndEpisode();
                    break;
                case "new":
                    setSeasonAndEpisode();
                    r4.subtitles.clear();
                    break;
                case "play":
                    if (!r4.player.state.collapsed && document.body.classList.contains("hc-player-full-page-enabled")) {
                        expand();
                    }
                    break;
                case "ui":
                    elements.topBar.classList.toggle("hidden", !event.data.data);
                    elements.controlsLeft.classList.toggle("hidden", !event.data.data);
                    elements.controlsRight.classList.toggle("hidden", !event.data.data);
                    break;
            }
        });

        document.addEventListener("keydown", (e) => {
            switch (e.code) {
                case "Escape":
                    if (r4.player.state.fullscreen == false) {
                        collapse();
                    }
                    break;
            }
        });

        r4.settings?.createTumblerSetting({
            name: "player-top-bar",
            label: "Дополнительная панель с заголовком",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-player-top-bar-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-player-top-bar-enabled",
                    class: "hc-player-top-bar-enabled",
                    text: "Вкл",
                    default: true,
                },
            ],
        });
        r4.settings?.createTumblerSetting({
            name: "player-extra-controls",
            label: "Дополнительные элементы управления",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-player-extra-controls-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-player-extra-controls-enabled",
                    class: "hc-player-extra-controls-enabled",
                    text: "Вкл",
                    default: true,
                },
            ],
        });
        r4.settings?.createTumblerSetting({
            name: "player-triple-click",
            label: "Переключение серий тройным кликом",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-player-triple-click-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-player-triple-click-enabled",
                    class: "hc-player-triple-click-enabled",
                    text: "Вкл",
                },
            ],
        });
        r4.settings?.createTumblerSetting({
            name: "player-full-page",
            label: "Автоматическое разворачивание",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-player-full-page-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-player-full-page-enabled",
                    class: "hc-player-full-page-enabled",
                    text: "Вкл",
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------PLAYER-AUTO-PLAY-NEXT-------------- */
    /* ------------------------------------------------- */

    function initAutoPlayNext() {
        window.addEventListener("message", (event) => {
            switch (event.data?.event) {
                case "ended":
                    if (document.body.classList.contains("hc-auto-play-next-enabled")) {
                        r4.player.next();
                    }
                    break;
                case "time":
                    if (
                        event.data.data != 0 &&
                        event.data.data >= event.data.duration - 1 &&
                        document.body.classList.contains("hc-auto-play-next-disabled")
                    ) {
                        r4.player.stop();
                    }
                    break;
            }
        });

        r4.settings?.createTumblerSetting({
            name: "auto-play-next",
            label: "Автопереключение серий",
            submenu: "Плеер",
            classes: [],
            options: [
                {
                    value: "hc-auto-play-next-default",
                    text: "Как в настройках профиля (серии или выкл)",
                },
                {
                    value: "hc-auto-play-next-enabled",
                    class: "hc-auto-play-next-enabled",
                    text: "Быстрое переключение (серии и сезоны)",
                },
                {
                    value: "hc-auto-play-next-disabled",
                    class: "hc-auto-play-next-disabled",
                    text: "Выкл",
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------HIDE-ADS--------------------------- */
    /* ------------------------------------------------- */

    function initHideAds() {
        GM.addStyle(`

        /* css */

        /* Hide some ads containers */

        body.hc-hide-ads .b-content__main > .b-post__mixedtext + div[style][id],
        body.hc-hide-ads .b-content__main > .b-post__rating_table + div[style][id],
        body.hc-hide-ads .b-content__main > div > .b-player > .b-player__network_issues_holder + div[style]:not([class]),
        body.hc-hide-ads .b-content__main > div > .b-player > a[target='_blank'],
        body.hc-hide-ads .b-content__main + div[id],
        body.hc-hide-ads .b-content__inline > .b-content__inline_inner > .b-content__inline_items + div[id],
        body.hc-hide-ads .b-wrapper .nopadd,
        body.hc-hide-ads .b-seriesupdate__block_list > .b-seriesupdate__block_list_item[data-url=''],
        body.hc-hide-ads > div[style*='position: fixed;'],
        body.hc-hide-ads > ins,
        body.hc-hide-ads .b-post__rating_table + ins,
        body.hc-hide-ads .ad-branding {
            display: none !important;
        }

        /* Active brand fixes */
        body.hc-hide-ads.active-brand,
        body.hc-hide-ads.active-brand.pp {
            padding-top: 0 !important;
        }
        @media screen {
            body.hc-hide-ads.active-brand,
            body.hc-hide-ads.active-brand.pp {
                padding-top: 0 !important;
            }
        }
        body.hc-hide-ads.active-brand #wrapper {
            width: auto !important;
        }

        /* !css */

        `);

        r4.settings?.createTumblerSetting({
            name: "hide-ads",
            label: "Скрытие рекламных блоков",
            submenu: "Интерфейс",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-hide-ads-disabled",
                    text: "Выкл",
                    end: () => {
                        r4.player.fit();
                    }
                },
                {
                    value: "hc-hide-ads",
                    class: "hc-hide-ads",
                    text: "Вкл",
                    default: true,
                    end: () => {
                        r4.player.fit();
                    }
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------HIDE-PLAYER-ADS-------------------- */
    /* ------------------------------------------------- */

    function initHidePlayerAds() {
        r4.settings?.createTumblerSetting({
            name: "hide-player-ads",
            label: "Отключение рекламных роликов",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-player-hide-ads-disabled",
                    text: "Выкл",
                    start() {
                        r4.player.state.vast = 1;
                        r4.player.vast();
                    },
                },
                {
                    value: "hc-player-hide-ads",
                    class: "hc-player-hide-ads",
                    text: "Вкл",
                    default: true,
                    start() {
                        r4.player.state.vast = 0;
                        r4.player.vast();
                    },
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------STYLE-IMPROVEMENTS----------------- */
    /* ------------------------------------------------- */

    function initStyleImprovements() {
        GM.addStyle(`

        /* css */

        /* Top Nav */

        body.hc-style .b-topnav__sub_inner a {
            color: #000 !important;
        }

        body.hc-style.b-theme__template__night .b-topnav__sub_inner a {
            color: #fff !important;
        }

        /* Сontent item */

        body.hc-style .b-content__inline_item .b-content__inline_item-link {
            font-weight: normal;
        }

        body.hc-style .b-content__inline_item .b-content__inline_item-link a,
        body.hc-style .b-content__inline_item .b-content__inline_item-link a:visited {
            color: #000;
        }

        body.hc-style.b-theme__template__night .b-content__inline_item .b-content__inline_item-link a,
        body.hc-style.b-theme__template__night .b-content__inline_item .b-content__inline_item-link a:visited {
            color: #fff;
        }

        body.hc-style .b-content__inline_item .cat {
            position: relative;
            top: unset;
            bottom: 0;
            right: 0;
            border-radius: 0;
            width: 100%;
        }

        body.hc-style.b-theme__template__night .b-content__inline_item .cat {
            background-color: #060f13 !important;
        }

        body.hc-style .b-content__inline_item .cat .entity {
            display: inline-block !important;
            margin-right: -8px;
            position: absolute;
            left: 0;
            right: 0;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        body.hc-style .b-content__inline_item:hover .cat .entity,
        body.hc-style .b-content__inline_item.active .cat .entity {
            display: none !important;
            margin-right: -10px;
            position: absolute;
            left: 0;
            right: 0;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        body.hc-style .b-content__inline_item .info {
            background-color: #222d33;
            color: #fff;
            border-radius: 0 !important;
            box-sizing: border-box;
            width: 100%;
            margin-bottom: 26px;
            font-weight: normal;
        }

        body.hc-style .b-content__inline_item .trailer {
            display: none !important;
            left: 0;
        }

        body.hc-style .b-content__inline_item-cover {
            padding: 0;
            border: 0;
        }

        body.hc-style .b-content__inline_item-cover img {
            width: 100%;
            height: auto;
        }

        /* Slider */

        body.hc-style.b-theme__template__night .b-newest_slider {
            border-color: #fff;
            color: #fff;
        }

        body.hc-style.b-theme__template__night .b-newest_slider .b-newest_slider__title span {
            border-color: #fff;
            color: #fff;
        }

        body.hc-style .b-newest_slider .b-content__inline_item .cat {
            display: block;
        }

        /* Сontent page */

        body.hc-style .b-post .b-post__partcontent a,
        body.hc-style .b-post__info a,
        body.hc-style .b-post__info .persons-list-holder .person-name-item a {
            color: #000 !important;
            border-color: #000;
        }

        body.hc-style.b-theme__template__night .b-post .b-post__partcontent a,
        body.hc-style.b-theme__template__night .b-post__info a,
        body.hc-style.b-theme__template__night .b-post__info .persons-list-holder .person-name-item a {
            color: #fff !important;
            border-color: #fff;
        }

        body.hc-style .b-sidecover {
            background: none;
            border: none;
            padding: 0;
            overflow: hidden;
            border-radius: 4px;
        }

        body.hc-style .b-post .b-sidetitle,
        body.hc-style .b-post .b-post__mtitle {
            font-size: 16px;
            font-weight: bold;
            line-height: 18px;
            overflow: hidden;
            padding: 10px 18px;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        body.hc-style .b-post .b-post__actions .btn,
        body.hc-style .b-post .b-sidetitle,
        body.hc-style .b-post .b-post__schedule_block_title,
        body.hc-style .b-post .b-post__schedule_more,
        body.hc-style .b-post .b-post__mtitle {
            background: #ddd;
        }
        body.hc-style .b-post .b-post__actions .btn,
        body.hc-style .b-post .b-sidetitle,
        body.hc-style .b-post .b-post__schedule_block_title .title,
        body.hc-style .b-post .b-post__schedule_more .title,
        body.hc-style .b-post .b-post__mtitle {
            color: #000;
        }
        body.hc-style.b-theme__template__night .b-post .b-post__actions .btn,
        body.hc-style.b-theme__template__night .b-post .b-sidetitle,
        body.hc-style.b-theme__template__night .b-post .b-post__schedule_block_title,
        body.hc-style.b-theme__template__night .b-post .b-post__schedule_more,
        body.hc-style.b-theme__template__night .b-post .b-post__mtitle {
            background: #192125;
        }
        body.hc-style.b-theme__template__night .b-post .b-post__actions .btn,
        body.hc-style.b-theme__template__night .b-post .b-sidetitle,
        body.hc-style.b-theme__template__night .b-post .b-post__schedule_block_title .title,
        body.hc-style.b-theme__template__night .b-post .b-post__schedule_more .title,
        body.hc-style.b-theme__template__night .b-post .b-post__mtitle {
            color: #fff;
        }
        body.hc-style .b-post .b-post__schedule .b-sidetitle {
            display: none;
        }
        body.hc-style .b-post .b-post__partcontent {
            margin-top: 0;
        }
        body.hc-style .b-post .b-post__actions .btn {
            border: 0;
            border-radius: 0;
        }
        body.hc-style .b-post .b-post__social_holder {
            background: #1f1f1f;
        }

        /* Rating stars */

        body.hc-style .b-content__bubble_rating .b-rating > .current,
        body.hc-style .b-post__rating .b-post__rating_layer_current {
            filter: grayscale(100%) !important;
        }
        body.hc-style.b-theme__template__night .b-content__bubble_rating .b-rating > .current,
        body.hc-style.b-theme__template__night .b-post__rating .b-post__rating_layer_current {
            filter: grayscale(100%) brightness(200%) !important;
        }

        body.hc-style .b-content__bubble_rating b {
            color: #000;
        }
        body.hc-style.b-theme__template__night .b-content__bubble_rating b {
            color: #fff;
        }

        body.hc-style .b-post__rating .num {
            color: inherit !important;;
        }

        /* Breadcrumbs */

        body.hc-style .b-content__crumbs a {
            color: #444;
        }

        body.hc-style.b-theme__template__night .b-content__crumbs a {
            color: #fff;
        }

        /* Comments */

        body.hc-style .comments-form {
            background: none;
        }

        body.hc-style .b-comment__like_it > i {
            display: none;
        }

        body.hc-style .b-comment__likes_count {
            margin: 0 !important;
        }

        body.hc-style .b-comment__quoteuser,
        body.hc-style .b-comment__like_it,
        body.hc-style.b-theme__template__night .b-comment__quoteuser,
        body.hc-style.b-theme__template__night .b-comment__like_it {
            color: #888;
            border-color: #888;
        }

        body.hc-style .b-comment .message > .text {
            color: #000;
        }

        body.hc-style.b-theme__template__night .b-comment .message > .text {
            color: #fff;
        }

        /* Content bubble */

        body.hc-style .b-content__bubble_content a {
            color: #000;
        }

        body.hc-style.b-theme__template__night .b-content__bubble_content a {
            color: #fff;
        }

        /* Player translation, season, episode styles */

        body.hc-style .b-translators__block {
            background: #000;
            padding: 5px 10px 10px 10px;
        }

        body.hc-style .b-rgstats__help,
        body.hc-style .b-translators__title {
            padding-top: 10px;
        }

        body.hc-style .b-simple_seasons__list {
            margin: -10px 0 0 0;
            padding: 5px 10px 10px 10px;
        }

        body.hc-style .b-simple_episodes__list {
            margin: 0;
            padding: 5px 10px 10px 10px;
        }

        body.hc-style .b-translator__item,
        body.hc-style .b-simple_episode__item,
        body.hc-style .b-simple_season__item {
            border-radius: 2.3px;
            background: rgba(23, 35, 34, .7);
            transition: opacity 0.1s linear 0s, background 0.1s linear 0s, transform 0.1s linear 0s;
            margin: 5px 5px 0 0;
            text-align: center;
        }

        body.hc-style .b-translator__item:hover,
        body.hc-style .b-simple_episode__item:hover,
        body.hc-style .b-simple_season__item:hover {
            background: rgba(0, 173, 239, .7);
        }

        body.hc-style .b-translator__item.active,
        body.hc-style .b-simple_episode__item.active,
        body.hc-style .b-simple_season__item.active {
            background: rgba(89, 105, 102, .7) !important;
        }

        body.hc-style .hc-toggle-translators-button {
            margin-top: 10px;
        }

        /* Misc */

        body.hc-style .b-newest_slider__title {
            padding-bottom: 20px;
        }

        /* !css */

        `);

        r4.settings?.createTumblerSetting({
            name: "styles",
            label: "Декоративные изменения",
            submenu: "Интерфейс",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-style-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-style",
                    class: "hc-style",
                    text: "Вкл",
                    default: true,
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------FONTS------------------------------ */
    /* ------------------------------------------------- */

    function initFonts() {
        function addFont(fontName, fontClass, fontData) {
            Object.keys(fontData).forEach((weight) => {
                const value = fontData[weight];

                GM.addStyle(`

                /* css */

                @font-face {
                    font-family: ${fontName};
                    src: url(data:font/truetype;base64,${value}) format('truetype');
                    font-weight: ${weight};
                    font-style: normal;
                }

                /* !css */

                `);
            });

            GM.addStyle(`

            /* css */

            body.${fontClass} {
                font-family: ${fontName}, sans-serif !important;
            }

            /* !css */

            `);
        }
        r4.settings?.createTumblerSetting({
            name: "font",
            label: "Шрифт",
            submenu: "Интерфейс",
            classes: [],
            options: [
                {
                    value: "hc-font-default",
                    text: "Стандартный",
                },
                {
                    value: "hc-font-averta-cy",
                    class: "hc-font-averta-cy",
                    text: "Averta-CY",
                    start() {
                        addFont("Averta-CY", "hc-font-averta-cy", r4.fonts["Averta-CY"]);
                    },
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------PLAYER-COVER----------------------- */
    /* ------------------------------------------------- */

    function initPlayerCover() {
        r4.settings?.afterEnd(() => {
            const img = document.querySelector(".b-sidecover img")?.src;
            if (!img) return;

            GM.addStyle(`

            /* css */

            body.hc-player-cover #cdnplayer [style*='hc-poster'] {
                background-image: url('${img}') !important;
                background-size: 100% auto !important;
                background-position: center !important;
                background-repeat: no-repeat !important;
                filter: blur(30px);
                z-index: -1;
            }

            body.hc-player-cover #cdnplayer [style*='hc-poster']::before {
                content: '';
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: linear-gradient(
                    to left,
                    rgba(0,0,0,.8) 0%,
                    rgba(0,0,0,.5) 35%,
                    rgba(0,0,0,.1) 50%,
                    rgba(0,0,0,.5) 65%,
                    rgba(0,0,0,.8) 100%
                );
            }

            /* !css */

            `);
        });

        r4.settings?.createTumblerSetting({
            name: "player-cover",
            label: "Отображение обложки",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-player-cover-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-player-cover",
                    class: "hc-player-cover",
                    text: "Вкл",
                    default: true,
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------HIDE-INFO-------------------------- */
    /* ------------------------------------------------- */

    function initHideInfo() {
        GM.addStyle(`

        /* css */

        /* Content hide info (button) */

        .hc-hide-info-button {
            content: '';
            width: 25px;
            height: 25px;
            margin-right: 5px;
            background-size: 25px 25px;
            background-repeat: no-repeat;
            background-image: url(${r4.images.arrow});
            cursor: pointer;
            z-index: 2;
            position: absolute;
            right: 10px;
            top: 15px;
        }
        .b-post__title {
            position: relative;
        }
        .b-translators__title {
            margin-right: 40px;
        }
        body.hc-hide-info .hc-hide-info-button {
            transform: rotate(180deg);
        }

        /* for light theme make arrow white only when info hidden */
        body:not(.b-theme__template__night).hc-hide-info .hc-hide-info-button,
        /* for dark theme always make arrow white */
        body.b-theme__template__night .hc-hide-info-button {
            filter: invert(100%) sepia(95%) saturate(21%) hue-rotate(280deg) brightness(106%) contrast(106%);
        }

        body.hc-hide-info.hc-hide-title .hc-hide-info-button {
            margin-top: -15px;
        }


        /* Content hide info (hidden styles) */

        body.hc-hide-info .b-post__title [itemprop="name"],
        body.hc-hide-info .b-post__origtitle,
        body.hc-hide-info .b-post__infotable,
        body.hc-hide-info .b-post__description,
        body.hc-hide-info .b-post__infolast {
            display: none !important;
        }

        /* Hide Ukraie block info */

        .b-player-block-strip,
        .b-player-block-inform,
        .b-player-block-inform2 {
            top: 0 !important;
            margin: 0 0 10px 0 !important;
        }

        body.hc-hide-info .b-player-block-strip,
        body.hc-hide-info .b-player-block-inform,
        body.hc-hide-info .b-player-block-inform2 {
            display: none !important;
        }

        /* !css */

        `);

        r4.settings?.afterEnd(() => {
            const title = document.querySelector(".b-post__title");
            if (!title) return;

            if (title.querySelector(".hc-hide-info-button")) return;

            const button = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="hc-hide-info-button pull-right"></div>
                <!-- !html -->
                `
            );

            button.addEventListener("click", () => {
                document.body.classList.toggle("hc-hide-info");
            });
            title.insertBefore(button, title.firstChild);
        });

        r4.settings?.createTumblerSetting({
            name: "hide-info",
            label: "Описание",
            submenu: "Автоматическое сворачивание",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-hide-info-disabled",
                    text: "Выкл",
                    start() {
                        document.body.classList.remove("hc-hide-info");
                    },
                },
                {
                    value: "hc-hide-info",
                    class: "hc-hide-info",
                    text: "Вкл",
                    start() {
                        document.body.classList.add("hc-hide-info");
                    },
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------HIDE-COMMENTS---------------------- */
    /* ------------------------------------------------- */

    function initHideComments() {
        GM.addStyle(`

        /* css */

        body.hc-comments-hide #hd-comments-list,
        body.hc-comments-hide #hd-comments-navigation {
            display: none;
        }

        .hc-comments-title {
            margin-bottom: 13px;
            overflow: hidden;
        }

        .hc-comments-title .title {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            float: left;
        }

        .hc-act {
            color: #878586;
            cursor: pointer;
            float: right;
            font-size: 12px;
            font-weight: normal;
        }

        .hc-act:hover {
            text-decoration: underline;
        }

        .hc-act-show {
            display: none;
        }

        .hc-act-hide {
            display: block;
        }

        body.hc-comments-hide .hc-act-show {
            display: block;
        }

        body.hc-comments-hide .hc-act-hide {
            display: none;
        }

        body.hc-comments-hide .b-content__crumbs {
            margin-top: 30px;
        }

        /* !css */

        `);

        r4.settings?.afterEnd(() => {
            const addCommentTitle = document.querySelector("#addcomment-title");
            if (addCommentTitle) {
                addCommentTitle.innerText = "Твой отзыв";
            }

            const commentsList = document.querySelector("#hd-comments-list");
            if (!commentsList) return;

            const commentsTitle = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="b-sidetitle hc-comments-title">
                    <div class="title">Отзывы</div>
                    <div class="hc-act hc-act-show">развернуть</div>
                    <div class="hc-act hc-act-hide">свернуть</div>
                </div>
                <!-- !html -->
                `
            );

            commentsTitle.addEventListener("click", () => {
                document.body.classList.toggle("hc-comments-hide");
            });

            document.querySelector("#comments-list-button").addEventListener("click", () => {
                document.body.classList.remove("hc-comments-hide");
            });

            commentsList.parentNode.insertBefore(commentsTitle, commentsList);
        });

        r4.settings?.createTumblerSetting({
            name: "comments-hide",
            label: "Отзывы",
            submenu: "Автоматическое сворачивание",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-comments-hide-disabled",
                    text: "Выкл",
                    start() {
                        document.body.classList.remove("hc-comments-hide");
                    },
                },
                {
                    value: "hc-comments-hide-enabled",
                    class: "hc-comments-hide-enabled",
                    text: "Вкл",
                    start() {
                        document.body.classList.add("hc-comments-hide");
                    },
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------HIDE-MORE-------------------------- */
    /* ------------------------------------------------- */

    function initHideMore() {
        GM.addStyle(`

        /* css */

        .hc-more-title {;
            cursor: pointer;
            margin-top: 20px;
        }

        .hc-more-title .title {
            float: left;
        }

        body.hc-more-hide .hc-more-title {
            margin-bottom: 20px;
        }

        body.hc-more-hide .hc-more-holder {
            display: none;
        }

        .hc-more-hide-act {
            color: #878586;
            cursor: pointer;
            float: right;
            font-size: 12px;
            font-weight: normal;
        }

        .hc-more-hide-act:hover {
            text-decoration: underline;
        }

        .hc-more-hide-act-show {
            display: none;
        }

        .hc-more-hide-act-hide {
            display: block;
        }

        body.hc-more-hide .hc-more-hide-act-show {
            display: block;
        }

        body.hc-more-hide .hc-more-hide-act-hide {
            display: none;
        }

        /* !css */

        `);

        r4.settings?.afterEnd(() => {
            document.querySelectorAll(".b-content__main > .b-sidelist__holder").forEach((holder) => {
                if (!holder.querySelector(".b-content__inline_item")) return
                if (!holder.previousElementSibling.classList.contains("b-sidetitle")) return

                holder.classList.add("hc-more-holder");

                const title = r4.utils.fromHTML(
                    /* html */
                    `
                    <!-- html -->
                    <div class="b-sidetitle hc-more-title">
                        <div class="title">Смотреть еще</div>
                        <div class="hc-more-hide-act hc-more-hide-act-show">развернуть</div>
                        <div class="hc-more-hide-act hc-more-hide-act-hide">свернуть</div>
                    </div>
                    <!-- !html -->
                    `
                );

                holder.previousElementSibling.replaceWith(title);

                title.addEventListener("click", () => {
                    document.body.classList.toggle("hc-more-hide");
                });
            });
        });

        r4.settings?.createTumblerSetting({
            name: "more-hide",
            label: "Смотреть еще",
            submenu: "Автоматическое сворачивание",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-more-hide-disabled",
                    text: "Выкл",
                    start() {
                        document.body.classList.remove("hc-more-hide");
                    },
                },
                {
                    value: "hc-more-hide",
                    class: "hc-more-hide",
                    text: "Вкл",
                    start() {
                        document.body.classList.add("hc-more-hide");
                    },
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------TRANSLATORS------------------------ */
    /* ------------------------------------------------- */

    function initHideTranslators() {
        GM.addStyle(`

        /* css */

        /* Content hide translators */

        .hc-translators-hide-enabled .b-translator__item.active {
            cursor: pointer;
        }
        .hc-translators-hide-enabled .hc-toggle-translators-button {
            content: '';
            float: left;
            width: 20px;
            height: 20px;
            margin-right: 3px;
            margin-top: 8px;
            margin-left: 5px;
            background-size: 20px 20px;
            background-repeat: no-repeat;
            background-image: url(${r4.images.arrow});
            filter: invert(100%) sepia(95%) saturate(21%) hue-rotate(280deg) brightness(106%) contrast(106%);
            transform: rotate(90deg);
            cursor: pointer;
        }
        .hc-translators-hide-enabled .hc-show-translators .hc-toggle-translators-button {
            transform: rotate(-90deg);
        }
        .hc-translators-hide-enabled .b-translator__item:not(.active):not(.hc-toggle-translators-button) {
            display: none;
        }
        .hc-translators-hide-enabled .b-translators__title {
            display: none;
        }
        .hc-translators-hide-enabled .hc-show-translators .b-translator__item:not(.active):not(.hc-toggle-translators-button) {
            display: block;
        }
        .hc-translators-hide-enabled .hc-show-translators .b-translators__title {
            display: block;
        }

        /* !css */

        `);

        r4.settings?.afterEnd(() => {
            function toggle() {
                document.querySelector(".b-translators__block").classList.toggle("hc-show-translators");
            }

            const translators = document.querySelector(".b-translators__block");
            if (!translators) return;

            const translatorsList = translators.querySelector(".b-translators__list");
            if (!translatorsList) return;

            const toggler = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <li class="hc-toggle-translators-button"></li>
                <!-- !html -->
                `
            );
            toggler.addEventListener("click", toggle);
            translatorsList.appendChild(toggler);

            translatorsList.querySelectorAll(".b-translator__item").forEach((button) => {
                button.addEventListener("click", function () {
                    if (this.classList.contains("active")) {
                        toggle();
                    }
                });
            });
        });

        r4.settings?.createTumblerSetting({
            name: "translators",
            label: "Список переводов",
            submenu: "Автоматическое сворачивание",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-translators-hide-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-translators-hide-enabled",
                    class: "hc-translators-hide-enabled",
                    text: "Вкл",
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------IMDB-RATING------------------------ */
    /* ------------------------------------------------- */

    function initIMDbRating() {
        GM.addStyle(`

        /* css */

        /* Rating */

        .b-content__inline_item-link > .rating {
            display: none;
        }

        body.hc-imdb .b-content__inline_item-link > .rating {
            display: block;
        }

        .b-content__inline_item-link > .rating {
            position: relative;
            line-height: 15px;
            font-size: 11px;
            font-weight: normal;
            margin-top: 3px;
        }
        .b-content__inline_item-link > .rating .rating-votes {
            font-size: 9px;
        }
        .b-content__inline_item-link > .rating .rating-value {
            padding-left: 29px;
            background-size: auto 24px;
            background-position: left -6px;
            background-repeat: no-repeat;
            background-image: url(${r4.images.imdb});
            color: black;
            filter: invert(69%) sepia(0%) saturate(576%) hue-rotate(139deg) brightness(88%) contrast(98%);  /* https://codepen.io/sosuke/pen/Pjoqqp */
        }
        .b-content__inline_item-link > .rating .rating-value.low {
            filter: invert(30%) sepia(53%) saturate(2254%) hue-rotate(337deg) brightness(97%) contrast(95%);
        }
        .b-content__inline_item-link > .rating .rating-value.medium {
            filter: invert(66%) sepia(77%) saturate(1448%) hue-rotate(347deg) brightness(99%) contrast(91%);
        }
        .b-content__inline_item-link > .rating .rating-value.high {
            filter: invert(68%) sepia(79%) saturate(5115%) hue-rotate(105deg) brightness(99%) contrast(99%);
        }

        /* !css */

        `);

        function setWithExpiry(key, value, ttl) {
            const now = new Date();

            // `item` is an object which contains the original value
            // as well as the time when it's supposed to expire
            const item = {
                value,
                expiry: now.getTime() + ttl,
            };
            localStorage.setItem(key, JSON.stringify(item));
        }

        function getWithExpiry(key) {
            const itemStr = localStorage.getItem(key);
            // if the item doesn't exist, return null
            if (!itemStr) {
                return null;
            }
            const item = JSON.parse(itemStr);
            const now = new Date();
            // compare the expiry time of the item with the current time
            if (now.getTime() > item.expiry) {
                // If the item is expired, delete the item from storage
                // and return null
                localStorage.removeItem(key);
                return null;
            }
            return item.value;
        }

        function getRating(id) {
            return new Promise((resolve, reject) => {
                console.debug(`IMDB Rating: request quick content for id=${id}.`);
                GM.xmlHttpRequest({
                    method: "POST",
                    url: location.origin + "/engine/ajax/quick_content.php",
                    data: `id=${id}&is_touch=1`,
                    headers: {
                        "Content-Type": "application/x-www-form-urlencoded",
                        "User-Agent": r4.useragent,
                    },
                    onload(response) {
                        console.debug(`Response ${response.status} for ${response.finalUrl}`, {response});
                        // One week ttl in ms
                        const ttl = 7 * 24 * 60 * 60 * 1000;
                        if (response.status !== 200) {
                            console.debug(
                                `IMDB Rating: request quick content for id=${id} failed with ${response.status} status code.`
                            );
                            // Isn't 200 status code
                            reject();
                            return
                        }
                        // Is 200 status code
                        // Find IMDb block
                        const ratingPattern =
                            /<span class="imdb">IMDb: <b>(?<rating>.*)<\/b> <i>\((?<votes>.*)\)<\/i>\<\/span>/;
                        const ratingResult = ratingPattern.exec(response.responseText);
                        if (!ratingResult?.groups?.rating) {
                            // IMDb block not found
                            // Save empty rating to storage to not make new request in next page load
                            // Resolve with empty rating
                            const data = { rating: "", votes: "", id };
                            setWithExpiry(id, data, ttl);
                            resolve(data);
                            console.debug(
                                `IMDB Rating: request quick content for id=${id} success, but no correct data found.`
                            );
                            return;
                        }
                        // IMDb block found
                        // Get actual rating
                        const rating = ratingResult.groups.rating;
                        // Get actual votes count
                        const votes = ratingResult.groups.votes;
                        // Save real rating to Storage
                        // Resolve with real rating
                        const data = {
                            rating,
                            votes,
                            id,
                        };
                        setWithExpiry(id, data, ttl);
                        resolve(data);
                        console.debug(`IMDB Rating: request quick content for id=${id} success.`);
                    },
                    onerror(e) {
                        console.debug(`IMDB Rating: request quick content for id=${id} failed.`);
                        console.debug("Error:", {e});
                        // Request failed
                        reject();
                    },
                });
            });
        }

        function showRating(ratingObject) {
            if (
                ratingObject &&
                ratingObject.id !== null &&
                ratingObject.rating !== null &&
                ratingObject.rating !== ""
            ) {
                // Got rating
                // Find related elements to append rating
                document
                    .querySelectorAll(`[data-id="${ratingObject.id}"] .b-content__inline_item-link`)
                    .forEach((contentItemLinkElement) => {
                        // Check rating wasn't already appended
                        if (!(contentItemLinkElement && !contentItemLinkElement.querySelector(".rating"))) {
                            return;
                        }
                        // Append rating block
                        const rating = ratingObject.rating;
                        let votes;
                        try {
                            votes = parseInt(ratingObject.votes.replace(/\s/g, ""));
                        } catch (e) {
                            console.debug("Error:", {e});
                            votes = 0;
                        }
                        let level;
                        if (votes >= 1000) {
                            if (rating < 5) {
                                level = "low";
                            } else if (rating < 7) {
                                level = "medium";
                            } else {
                                level = "high";
                            }
                        }
                        contentItemLinkElement.innerHTML +=
                        /* html */
                        `
                            <!-- html -->
                            <span class="rating">
                                <span class="rating-value ${level}"><b>${rating}</b></span>
                                <span> / </span>
                                <span class="rating-votes">${parseInt(votes / 1000)}k</span>
                            </span>
                            <!-- !html -->
                        `;
                    });
            }
        }

        async function getAndShowRating(contentItemElement, callback = () => {}, retries = 0) {
            const id = contentItemElement.dataset.id;
            let ratingObject = getWithExpiry(id);
            if (
                ratingObject !== null &&
                ratingObject.id != null &&
                ratingObject.rating != null &&
                ratingObject.votes != null
            ) {
                // Found vaid saved rating in storage
                // Show rating from storage
                showRating(ratingObject);
                callback();
            } else {
                // Rating not found in storage
                // Request rating and then show
                try {
                    ratingObject = await getRating(id)
                    showRating(ratingObject);
                    callback();
                }
                catch (e) {
                    if (retries <= 3) {
                        retries++;
                        setTimeout(() => {
                            getAndShowRating(contentItemElement, callback, retries);
                        }, 1000);
                    } else {
                        callback();
                    }
                }
            }
        }

        async function getAndShowRatings(contentItemElements) {
            if (contentItemElements.length) {
                await getAndShowRating(contentItemElements.shift(), () => {
                    getAndShowRatings(contentItemElements);
                });
            }
        }

        r4.settings?.createTumblerSetting({
            name: "imdb",
            label: "Рейтинг IMDb",
            submenu: "Интерфейс",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-imdb-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-imdb",
                    class: "hc-imdb",
                    text: "Вкл",
                    end: () => getAndShowRatings(Array.from(document.querySelectorAll(".b-content__inline_item"))),
                },
            ],
        });
    }

    /* ------------------------------------------------- */
    /* --------------HOTKEYS---------------------------- */
    /* ------------------------------------------------- */

    function initHotkeys() {
        const HELP_TOOLTIP =
            /* html */
            `
            <!-- html -->
            <span class="r4-tooltip" style="float: right;">
                <span class="r4-tooltip-icon">i</span>
                <div class="tooltiptext">
                    <div>Список горячих клавиш</div>
                    <ul style="margin-top: 15px;">
                        <li style="margin-top: 5px;">ПРОБЕЛ - Плей/Пауза</li>
                        <li style="margin-top: 5px;">F - Полноэкранный режим</li>
                        <li style="margin-top: 5px;">N - Следующий эпизод</li>
                        <li style="margin-top: 5px;">P - Предыдущий эпизод</li>
                    </ul>
                    <div style="margin-top: 15px;">
                        <small>
                            В отличии от оригинальных работают с
                            разу полсле загрузки страницы.
                            В том числе когда плеер не в фокусе
                            или был не в фокусе на момент перевода
                            в полноэкранный режим.
                        </small>
                    </div>
                </div>
            </span>
            <!-- !html -->
        `;

        function setupHotkeys() {
            function hotkeysEnabled() {
                return document.body.classList.contains("hc-hotkeys-enabled");
            }

            function anyActiveInput() {
                const inputs = document.querySelectorAll("input,textarea");
                return Array.from(inputs).includes(document.activeElement);
            }

            function dispatchKeyboardEvent(type, code) {
                const event = new KeyboardEvent(type, { code: code });
                document.dispatchEvent(event);
            }

            function sleep(ms) {
                return new Promise((resolve) => setTimeout(resolve, ms));
            }

            document.addEventListener("keyup", async (e) => {
                if (!hotkeysEnabled()) {
                    return;
                }
                if (anyActiveInput()) {
                    return;
                }
                switch (e.code) {
                    case "KeyF":
                        r4.player.wake();
                        r4.player.enterfullscreen();
                        e.preventDefault();
                        break;
                }
            });

            document.addEventListener("keydown", (e) => {
                if (!hotkeysEnabled()) {
                    return;
                }
                if (anyActiveInput()) {
                    return;
                }
                switch (e.code) {
                    case "KeyN":
                        r4.player.next();
                        e.preventDefault();
                        break;
                    case "KeyP":
                        r4.player.prev();
                        e.preventDefault();
                        break;
                    case "Space":
                        r4.player.wake();
                        r4.player.toggle();
                        e.preventDefault();
                        break;
                    case "ArrowLeft":
                        r4.player.wake();
                        break;
                    case "ArrowRight":
                        r4.player.wake();
                        break;
                }
            });
        }

        r4.settings?.createTumblerSetting({
            name: "hotkeys",
            label: "Улучшеные горячие клавиши",
            submenu: "Плеер",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-hotkeys-disabled",
                    text: "Выкл",
                },
                {
                    end: setupHotkeys,
                    value: "hc-hotkeys-enabled",
                    class: "hc-hotkeys-enabled",
                    text: "Вкл",
                    default: true,
                },
            ],
        }, (tumblerSetting) => {
            tumblerSetting.appendChild(r4.utils.fromHTML(HELP_TOOLTIP));
            return tumblerSetting;
        });
    }

    /* ------------------------------------------------- */
    /* --------------VOLUME-SCROLL---------------------- */
    /* ------------------------------------------------- */

    // function initVolumeScroll() {
    //     r4.settings?.createTumblerSetting({
    //         name: "volume-scroll",
    //         label: "Регулировка громкости колесом мыши",
    //         submenu: "Плеер",
    //         classes: ["r4-on-of-tumbler"],
    //         options: [
    //             {
    //                 value: "hc-volume-scroll-disabled",
    //                 text: "Выкл",
    //                 default: true,
    //                 reload: true,
    //             },
    //             {
    //                 value: "hc-volume-scroll-enabled",
    //                 class: "hc-volume-scroll-enabled",
    //                 text: "Вкл",
    //                 reload: true,
    //                 end: () => {
    //                     const hoverElem = r4.player.elements.container;

    //                     if (!hoverElem) return;

    //                     hoverElem.addEventListener("wheel", async (event) => {
    //                         const delta = 0.01;
    //                         const prev = await r4.player.volume();
    //                         var level = prev;

    //                         if (event.deltaY > 0 && level + delta <= 1) {
    //                             level += delta;
    //                         } else if (event.deltaY < 0 && level - delta >= 0) {
    //                             level -= delta;
    //                         }

    //                         level = parseFloat(level).toFixed(2);

    //                         if (prev != level) {
    //                             await r4.player.volume(level);
    //                         }

    //                         event.preventDefault();
    //                         event.stopPropagation();
    //                         event.stopImmediatePropagation();
    //                     });
    //                 },
    //             },
    //         ],
    //     });
    // }

    /* ------------------------------------------------- */
    /* --------------HIDE-COUNTRY----------------------- */
    /* ------------------------------------------------- */

    function initHideCountry() {
        GM.addStyle(`

        /* css */

        .hc-russia {
            display: block;
            width: 100%;
            height: 320px;
            background-color: black;
            background-image: url(${r4.images.russia});
            background-size: auto 260px;
            background-repeat: no-repeat;
            background-position: center;
        }

        body:not(.b-theme__template__night) .hc-russia {
            filter: invert(94%);
        }

        .hc-hode-countries-couner-item {
            position: relative;
            text-align: center;
        }

        .hc-hode-countries-couner-item > .b-content__inline_item-cover {
            box-sizing: border-box;
            height: 100%;
        }

        .hc-hode-countries-couner-item .hc-hode-countries-couner {
            border: 5px solid red;
            border-radius: 50%;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;width: 50%;
            min-width: 70px;
            aspect-ratio : 1 / 1;
            opacity: 50%
        }

        .hc-hode-countries-couner-item .hc-hode-countries-couner > div {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }

        body:not(.b-theme__template__night) .hc-hode-countries-couner-item  .hc-hode-countries-couner > div {
            color: black;
        }

        .hc-hode-countries-couner-item  .hc-hode-countries-couner > div > span {
            display: block;
            font-size: 30px;
            margin: 10px;
        }

        body:not(.hc-hide-countries-hide) .hc-hode-countries-couner-item {
            display: none !important;
        }

        /* !css */

        `);

        r4.settings?.createTumblerSetting({
            name: "hide-countries-mode",
            label: "Режим",
            submenu: "Фильтр по стране",
            classes: [],
            options: [
                {
                    value: "hc-hide-countries-disabled",
                    text: "Выкл",
                },
                {
                    value: "hc-hide-countries-dim",
                    class: "hc-hide-countries-dim",
                    text: "Затемнять",
                    default: true,
                },
                {
                    value: "hc-hide-countries-hide",
                    class: "hc-hide-countries-hide",
                    text: "Скрыть",
                },
            ],
        });

        r4.settings?.createTumblerSetting({
            name: "hide-countries-invert",
            label: "Инверсия",
            submenu: "Фильтр по стране",
            classes: ["r4-on-of-tumbler"],
            options: [
                {
                    value: "hc-hide-countries-invert-disabled",
                    text: "Выкл",
                    end: () =>  makeHiddenCounters(),
                },
                {
                    value: "hc-hide-countries-invert-enabled",
                    class: "hc-hide-countries-invert-enabled",
                    text: "Вкл",
                    end: () => makeHiddenCounters(),
                },
            ],
        });

        const DEFAULT_COUNTRIES = ["Россия", "СССР"];

        function logCountryItem(elem, country) {
            const title = elem.querySelector(".b-content__inline_item-link a").textContent.trim();
            const year = elem
                .querySelector(".b-content__inline_item-link div")
                .textContent.trim()
                .split(",")[0]
                .trim()
                .split("-")[0]
                .trim();
            console.debug(`Mark "${title}, ${year}" as "${country}" content`);
        }

        function showTerroristBanner() {
            const newest = document.querySelector(".b-collections__newest");
            if (!newest) {
                return;
            }
            const russia = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <a class="hc-russia" href="https://twitter.com/search?q=%23russiaisaterrorisstate" target="_blank"></a>
                <!-- !html -->
                `
            );
            newest.parentElement.insertBefore(russia, newest);
        }

        function slug(word) {
            switch (word) {
                case "Россия":
                    return "russian";
                case "СССР":
                    return "ussr";
                default:
                    return r4.utils.slugify(r4.utils.transliterate(word));
            }
        }

        function countHiddenItems(countries, containerClass) {
            let counter = 0;

            countries.forEach((country) => {
                const countrySlug = slug(country);
                counter += document.querySelectorAll(
                    `.hc-hide-${countrySlug} .${containerClass} .b-content__inline_item.hc-content-${countrySlug}`
                ).length;
            });

            return counter;
        }

        function makeHiddenCounter(countries, containerClass) {
            const counterItemPrev = document.querySelector(`.${containerClass} .hc-hode-countries-couner-item`);
            if (counterItemPrev) counterItemPrev.remove();

            let hiddenCounter = countHiddenItems(countries, containerClass);

            const contentItems = document.querySelectorAll(`.${containerClass} .b-content__inline_item`);
            const contentCounter = contentItems.length;
            const lastItem = contentItems[contentCounter - 1];

            if (Array.from(document.body.classList).includes("hc-hide-countries-invert-enabled")) {
                hiddenCounter = contentCounter - hiddenCounter;
            }

            if (hiddenCounter === 0) return;

            lastItem.style.display = "block"; // Temporary undo possible display:none to get height and width

            const lastCover = lastItem.querySelector(".b-content__inline_item-cover");
            const width = lastCover.offsetWidth;
            const height = lastCover.offsetHeight;

            const counterItem = r4.utils.fromHTML(
                /* html */
                `
                <!-- html -->
                <div class="b-content__inline_item hc-hode-countries-couner-item" style="width:${width}px;height:${height}px;">
                    <div class="b-content__inline_item-cover">
                        <div class="hc-hode-countries-couner">
                            <div>
                                Скрыто
                                <span>${hiddenCounter}</span>
                            </div>
                        </div>
                    </div>
                </div>
                <!-- !html -->
                `
            );

            counterItem.addEventListener("click", (event) => {
                document.body.classList.remove("hc-hide-countries-hide");
                document.body.classList.add("hc-hide-countries-dim");
            });

            lastItem.style.display = "";

            lastItem.parentNode.insertBefore(counterItem, lastItem.nextSibling);
        }

        async function makeHiddenCounters() {
            const countries = await getEnabledCountries();
            makeHiddenCounter(countries, "b-content__inline_items");
            makeHiddenCounter(countries, "b-sidelist");
        }

        async function getEnabledCountries() {
            const value = await r4.settings.getSetting("hide-country-list");
            return (value || "").split(",").filter((str) => str.trim() !== "");
        }

        async function saveEnabledCountries(countries) {
            const value = countries.filter((str) => str.trim() !== "").join(",");
            await r4.settings.setSetting("hide-country-list", value);
        }

        async function addEnabledCountry(countrySlug) {
            const countries = await getEnabledCountries();
            if (!countries.includes(countrySlug)) {
                countries.push(countrySlug);
                await saveEnabledCountries(countries);
            }
        }

        async function removeEnabledCountry(countrySlug) {
            const countries = await getEnabledCountries();
            const index = countries.indexOf(countrySlug);
            if (index !== -1) {
                countries.splice(index, 1);
                await saveEnabledCountries(countries);
            }
        }

        function handleCountry(country) {
            const countrySlug = slug(country);

            GM.addStyle(`

            /* css */

            body.hc-hide-countries-dim:not(.hc-hide-countries-invert-enabled).hc-hide-${countrySlug} .hc-content-${countrySlug},
            body.hc-hide-countries-dim.hc-hide-countries-invert-enabled:not(.hc-hide-${countrySlug}) .hc-content-${countrySlug} {
                filter: brightness(30%);
            }

            body.hc-hide-countries-dim:not(.hc-hide-countries-invert-enabled).hc-hide-${countrySlug} .hc-content-${countrySlug} .b-content__inline_item-cover img,
            body.hc-hide-countries-dim.hc-hide-countries-invert-enabled:not(.hc-hide-${countrySlug}) .hc-content-${countrySlug} .b-content__inline_item-cover img {
                filter: grayscale(1) brightness(20%);
            }

            body.hc-hide-countries-hide:not(.hc-hide-countries-invert-enabled).hc-hide-${countrySlug} .hc-content-${countrySlug},
            body.hc-hide-countries-hide.hc-hide-countries-invert-enabled:not(.hc-hide-${countrySlug}) .hc-content-${countrySlug} {
                display: none;
            }

            /* !css */
            `);

            r4.settings?.createTumblerSetting({
                name: `hide-${countrySlug}`,
                label: country == "Россия" ? "Россия (страна-оккупант, страна-террорист)" : country,
                submenu: "Фильтр по стране",
                classes: ["r4-on-of-tumbler"],
                options: [
                    {
                        text: "Выкл",
                        end: async () => {
                            await removeEnabledCountry(country);
                            await makeHiddenCounters();
                        },
                    },
                    {
                        value: `hc-hide-${countrySlug}`,
                        class: `hc-hide-${countrySlug}`,
                        text: "Вкл",
                        end: async () => {
                            await addEnabledCountry(country);
                            await makeHiddenCounters();
                        },
                    },
                ],
            });
        }

        r4.settings?.afterEnd(async () => {
            // Start countries list with default countries
            let countries = DEFAULT_COUNTRIES;

            // Not specified country
            const NOT_SPECIFIED_COUNTRY = "Страна не указана";

            // Get enabled countries
            const enabledCountries = await getEnabledCountries();

            // Remove NOT_SPECIFIED_COUNTRY to add it at the end
            delete enabledCountries[enabledCountries.indexOf(NOT_SPECIFIED_COUNTRY)];

            // Add enabled countries if they are not already in countries
            countries = countries.concat(enabledCountries.filter((item) => !countries.includes(item)));

            document.querySelectorAll(".b-content__inline_item .b-content__inline_item-link div").forEach((elem) => {
                let country;

                // Exclude slider
                if (elem.closest(".b-newest_slider__list")) return;

                const parts = elem.textContent.split(",");

                // Generate country name for content item
                country = parts.length === 3 ? parts[1].trim() : NOT_SPECIFIED_COUNTRY;

                // Generate country slug
                const countrySlug = slug(country);

                // Mark country content item with class
                const contentElem = elem.closest(".b-content__inline_item");
                contentElem.classList.add(`hc-content-${countrySlug}`);

                // logCountryItem(contentElem, country);

                // Add found countries if they are not already not in countries
                if (!countries.includes(country) && country !== NOT_SPECIFIED_COUNTRY) {
                    countries.push(country);
                }
            });

            // Add NOT_SPECIFIED_COUNTRY
            countries.push(NOT_SPECIFIED_COUNTRY);

            // Process countries
            countries.forEach(handleCountry);

            showTerroristBanner();
        });
    }

    /* ------------------------------------------------- */
    /* --------------SETTINGS--------------------------- */
    /* ------------------------------------------------- */

    function initSettings() {
        GM.addStyle(`
        /* css */

        /* Night theme */

        body.b-theme__template__night .r4-tumbler {
            background: #222d33;
        }

        body.b-theme__template__night .r4-settings > ul {
            background: #060f13;
        }

        body.b-theme__template__night .r4-settings > ul:after {
            border-bottom-color: #060f13;
        }

        body.b-theme__template__night .r4-tooltip .tooltiptext {
            background: #060f13;
        }

        body.b-theme__template__night .r4-tooltip .tooltiptext:after {
            border-right-color: #060f13;
        }

        /* Resize header (to fit settings tumbler) */

        @media screen and (max-width: 590px) {
            .head-right a,
            .show-login,
            .show-search {
                width: 30px;
            }
        }

        .logo-box {
            background-size: 100px;
        }
        @media screen and (max-width: 760px) {
            .logo-box {
                width: 70px;
            }
        }

        .head-fixed-inner {
            padding: 0 90px;
        }

        .show-login span {
            display: none;
        }

        .show-login i {
            font-size: 18px;
        }

        /* Tumbler Settings */

        .r4-tumbler-settings {
            margin-top: 5px;
            margin-left: 10px;
        }

        /* !css */
        `);

        r4.settings?.afterStart(() => {
            if (r4.settings?.tumbler) {
                document.querySelector(".b-tophead-left")?.appendChild(r4.settings.tumbler);
            }
        });
    }

    function missingSettingHandler(name) {
        // This script previously stored settings in localStorage
        // This function migrates them to GM.config

        const SETTINGS_NAME = "hc-settings";

        function migrateLocalStorageSetting(name, value) {
            if (value == "") {
                value = null;
            }
            GM.setValue(name, value);
            deleteLocalStorageSetting(name);
            console.debug(`Migrated setting ${name}: ${JSON.stringify(value)}`);
            return value;
        }

        function getLocalStorageSetting(name) {
            const settingsStr = localStorage.getItem(SETTINGS_NAME);
            const settings = settingsStr ? JSON.parse(settingsStr) : {};
            return settings[name];
        }

        function deleteLocalStorageSetting(name) {
            const settingsStr = localStorage.getItem(SETTINGS_NAME);
            const settings = settingsStr ? JSON.parse(settingsStr) : {};
            delete settings[name];
            localStorage.setItem(SETTINGS_NAME, JSON.stringify(settings));
        }

        let value = getLocalStorageSetting(name);
        if (value !== undefined) {
            return migrateLocalStorageSetting(name, value);
        }

        return value;
    }

    /* ------------------------------------------------- */
    /* --------------INITIALIZATION--------------------- */
    /* ------------------------------------------------- */

    r4.utils = R4Utils();
    r4.fonts = R4Fonts();
    r4.images = R4Images();
    r4.settings = R4Settings({
        script_homepage: "https://greasyfork.org/en/scripts/425494",
        version_text: "Версия",
        update_text: "Обновить",
        feedback_text: "Отзывы и предложения",
        missingSettingHandler,
    });
    r4.player = initPlayer();

    initSettings();
    initContentSizeTumbler();
    initNavbarLinks();
    initFonts();
    initStyleImprovements();
    initHideAds();
    initIMDbRating();
    initAutoPlayNext();
    initHidePlayerAds();
    initPlayerCover();
    initPlayerExtraControls();
    // initVolumeScroll();
    initHideInfo();
    initHideComments();
    initHideMore();
    initHideTranslators();
    initHotkeys();
    initHideCountry();

    r4.subtitles = initPlayerSubtitles({
        key: "I4RUSehE2lQ5jLgNjteb3gaW31PbJfso",
    });

})();