Enable Picture-in-picture (PiP) & more for Weverse.io

Enable Picture-in-picture (PiP), Auto translate artists' posts on weverse.io

目前为 2023-11-26 提交的版本。查看 最新版本

// ==UserScript==
// @name        Enable Picture-in-picture (PiP) & more for Weverse.io
// @namespace   Weverse Enhancements
// @match       *://weverse.io/*/live/*
// @include     *://weverse.io/*/live*
// @include     *://weverse.io*
// @grant       GM_getValue
// @grant       GM_setValue
// @version     4.0
// @author      jho / @jhooo_o
// @run-at      document-end
// @description Enable Picture-in-picture (PiP), Auto translate artists' posts on weverse.io
// @license     MIT
// @icon		https://cdn-v2pstatic.weverse.io/wev_web_fe/assets/1.0.0/icons/logo192.png
// ==/UserScript==

let auto_translate_status = GM_getValue('storage_translator', false);
const pip_btn_icon = `
<span class="pzp-pc-ui-button__tooltip">Toggle Picture-in-picture</span>
<span focusable="false" class="pzp-ui-icon pzp-pc-pip-button__icon pzp-pc-viewmode-button__icon" >
<svg class="pzp-ui-icon__svg" width="36" height="36" viewBox="0 0 36 36">
  <g id="Layer_1" data-name="Layer 1" focusable="false">
    <path fill="currentColor" d="M26.8,11.77c-.13-.24-.32-.44-.57-.57-.24-.13-.49-.2-1.16-.2H10.92c-.67,0-.91,.07-1.16,.2-.24,.13-.44,.32-.57,.57-.13,.24-.2,.49-.2,1.16v9.49c0,.67,.07,.91,.2,1.16,.13,.24,.33,.44,.57,.57,.24,.13,.49,.2,3.21,.2h14.15c-1.39,0-1.14-.07-.9-.2,.24-.13,.44-.32,.57-.57,.13-.24,.2-.49,.2-1.16V12.92c0-.67-.07-.91-.2-1.16Zm-1.8,9.53c0,.55-.45,1-1,1h-6.94c-.55,0-1-.45-1-1v-3.5c0-.55,.45-1,1-1h6.94c.55,0,1,.45,1,1v3.5Z" style="fill-rule: evenodd;"/></g>
</svg>
</span>
`;

const trans_button_active = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 38 38'%3E%3Ccircle fill='%2363D5A9' cx='27.3' cy='9.9' r='4.2'/%3E%3Cpath d='M32.9,28.3l-1.9-4c0,0,0,0,0,0l-3.8-8.1c-1.1,0-2.1-0.3-3-0.8l-3.7,7.9c-0.6-0.1-1.3-0.3-2-0.6c-1-0.4-2-1-2.7-1.5l0,0 c-0.1,0-0.1-0.1-0.2-0.1c1.1-1.1,1.9-2.4,2.5-3.9c0.5-1.3,0.8-2.6,0.9-4H22c-0.3-0.6-0.6-1.2-0.8-1.8h-6v-2c0-0.5-0.4-0.9-0.9-0.9 c-0.5,0-0.9,0.4-0.9,0.9v2h-7c-0.5,0-0.9,0.4-0.9,0.9c0,0.5,0.4,0.9,0.9,0.9h7.9l0,0l0,0h3c-0.1,1.1-0.4,2.2-0.8,3.3 c-0.5,1.3-1.3,2.4-2.2,3.4c-1.1-1.1-1.9-2.4-2.4-3.9c-0.2-0.5-0.7-0.7-1.2-0.6c-0.5,0.2-0.7,0.7-0.6,1.2c0.6,1.7,1.5,3.2,2.8,4.5 c-0.7,0.5-1.5,1-2.3,1.3c-1.3,0.5-2.7,0.8-4.2,0.8c-0.5,0-0.9,0.4-0.9,0.9c0,0.5,0.4,0.9,0.9,0.9c1.7,0,3.3-0.3,4.9-1 c1.1-0.4,2.1-1,3-1.8c0.2,0.1,0.3,0.3,0.5,0.4c0.8,0.6,1.9,1.2,3.1,1.7c0.6,0.3,1.2,0.5,1.9,0.6l-1.6,3.4c-0.2,0.5,0,1,0.4,1.2 s1,0,1.2-0.4l1.6-3.5h8.1l1.6,3.5c0.2,0.5,0.8,0.7,1.2,0.4S33.1,28.8,32.9,28.3z M22.4,23.8l3.2-6.9l3.2,6.9H22.4z'/%3E%3C/svg%3E%0A")`;
const trans_button_not_active = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 38 38'%3E%3Ccircle fill='%23d5639a' cx='27.3' cy='9.9' r='4.2'/%3E%3Cpath d='M32.9,28.3l-1.9-4c0,0,0,0,0,0l-3.8-8.1c-1.1,0-2.1-0.3-3-0.8l-3.7,7.9c-0.6-0.1-1.3-0.3-2-0.6c-1-0.4-2-1-2.7-1.5l0,0 c-0.1,0-0.1-0.1-0.2-0.1c1.1-1.1,1.9-2.4,2.5-3.9c0.5-1.3,0.8-2.6,0.9-4H22c-0.3-0.6-0.6-1.2-0.8-1.8h-6v-2c0-0.5-0.4-0.9-0.9-0.9 c-0.5,0-0.9,0.4-0.9,0.9v2h-7c-0.5,0-0.9,0.4-0.9,0.9c0,0.5,0.4,0.9,0.9,0.9h7.9l0,0l0,0h3c-0.1,1.1-0.4,2.2-0.8,3.3 c-0.5,1.3-1.3,2.4-2.2,3.4c-1.1-1.1-1.9-2.4-2.4-3.9c-0.2-0.5-0.7-0.7-1.2-0.6c-0.5,0.2-0.7,0.7-0.6,1.2c0.6,1.7,1.5,3.2,2.8,4.5 c-0.7,0.5-1.5,1-2.3,1.3c-1.3,0.5-2.7,0.8-4.2,0.8c-0.5,0-0.9,0.4-0.9,0.9c0,0.5,0.4,0.9,0.9,0.9c1.7,0,3.3-0.3,4.9-1 c1.1-0.4,2.1-1,3-1.8c0.2,0.1,0.3,0.3,0.5,0.4c0.8,0.6,1.9,1.2,3.1,1.7c0.6,0.3,1.2,0.5,1.9,0.6l-1.6,3.4c-0.2,0.5,0,1,0.4,1.2 s1,0,1.2-0.4l1.6-3.5h8.1l1.6,3.5c0.2,0.5,0.8,0.7,1.2,0.4S33.1,28.8,32.9,28.3z M22.4,23.8l3.2-6.9l3.2,6.9H22.4z'/%3E%3C/svg%3E%0A")`;

const trans_status_btn_style = document.createElement("style");
trans_status_btn_style.setAttribute('type', 'text/css');
trans_status_btn_style.innerHTML = `
            .HeaderView_translate_status:hover {
                background-color: rgba(0,0,0,.04);
                border-radius: 50%;
                margin: -12px;
                padding: 12px;
            }
            .HeaderView_translate_status:before {
                content: "";
                background-image: var(--trans_background);
                display: block;
                height: 38px;
                width: 38px;
            }
            .HeaderView_translate_status:focus-visible {
                outline: none;
            }
            `;

document.head.appendChild(trans_status_btn_style);

const mutation_config = { childList: true, subtree: true };

function toggle_pip() {

    const video_player_wrapper = document.querySelector(".webplayer-internal-source-wrapper");
    const video_player = document.querySelector(".webplayer-internal-video");
    if (document.pictureInPictureElement) {
        document.exitPictureInPicture()
            .then(() => console.log("██████████ Exited Picture-in-picture mode"))
            .catch(error => console.error("██████████ Error exiting PiP mode:", error));
    } else {
        video_player.requestPictureInPicture()
            .then(() => console.log("██████████ Entered Picture-in-picture mode"))
            .catch(error => console.error("██████████ Error entering PiP mode:", error));
    }
}

function toggle_auto_translate() {
    const translateStatusBtn = document.querySelector(".HeaderView_translate_status");
    if (auto_translate_status) {
        auto_translate_status = false;
        translateStatusBtn.style.setProperty("--trans_background", auto_translate_status ? trans_button_active : trans_button_not_active);
        const status = auto_translate_status ? "Auto translator for artists' posts is enabled" : "Auto translator for artists' posts is disabled";
        translateStatusBtn.setAttribute('title', status);
        GM_setValue('storage_translator', false);
        popup_alert(auto_translate_status, status);
    } else {
        auto_translate_status = true;
        translateStatusBtn.style.setProperty("--trans_background", auto_translate_status ? trans_button_active : trans_button_not_active);
        const status = auto_translate_status ? "Auto translator for artists' posts is enabled" : "Auto translator for artists' posts is disabled";
        translateStatusBtn.setAttribute('title', status);
        GM_setValue('storage_translator', true);
        popup_alert(auto_translate_status, status);
    }
}

function popup_alert(auto_translate_status, status) {
    const popup_elem = document.createElement("div");
    popup_elem.classList.add('translate_popup');
    popup_elem.innerText = status;

    if (auto_translate_status) {
        background = 'linear-gradient(135deg,#e0fdfc,#e3fff5)';
        color = '#08ccca';
    } else {
        background = 'linear-gradient(135deg,#fde0e0,#ffe3e3)';
        color = '#c36666';
    }

    const popup_elem_styles = {
        color: color,
        position: 'fixed',
        top: '10px',
        margin: 'auto',
        border: `2px solid ${color}20`,
        borderRadius: '14px',
        backgroundColor: 'white',
        background: background,
        fontWeight: '900',
        padding: '20px 20px',
        opacity: 0,
        right: 0,
        left: 0,
        width: 'fit-content',
        boxShadow: '0 1px 12px #3e3f4e05, 0 5px 24px #3e3f4e1a',
        zIndex: 3999,
        transition: 'opacity 0.5s ease-in-out'
    };

    Object.assign(popup_elem.style, popup_elem_styles);

    document.body.appendChild(popup_elem);

    void popup_elem.offsetWidth;

    popup_elem.style.opacity = 1;
    setTimeout(() => {
        popup_elem.style.opacity = 0;
        setTimeout(() => {
            document.body.removeChild(popup_elem);
        }, 500);
    }, 2000);
}
function append_elem(changes, observer) {
    // Append Picture-in-picture
    const video_player = document.querySelector(".webplayer-internal-video");
    if (video_player) {
        if (video_player.hasAttribute("disablepictureinpicture")) {
            video_player.removeAttribute("disablepictureinpicture");
            console.log("██████████ Picture-in-picture is re-enabled.");
        }

        const locations = document.querySelectorAll(".pzp-pc__bottom-buttons-right, .pzp-mobile-bottom.pzp-mobile__bottom");
        if (locations.length > 0) {
            const pip_btn_exist = Array.from(locations).some(location => location.querySelector(".pzp-button-pip"));
            if (!pip_btn_exist) {
                const btn = document.createElement("button");
                btn.setAttribute("aria-label", "Toggle Picture-in-picture");
                const btn_class_names = locations[0].classList.contains("pzp-mobile-bottom")
                    ? ["pzp-button", "pzp-setting-button", "pzp-mobile__setting-button", "pzp-button-pip"]
                    : ["pzp-button", "pzp-button-pip", "pzp-pc-viewmode-button", "pzp-pc__viewmode-button", "pzp-pc-ui-button"];
                btn_class_names.forEach(item => btn.classList.add(item));
                btn.innerHTML = pip_btn_icon;
                btn.addEventListener("click", () => toggle_pip());
                locations[0].insertBefore(btn, locations[0].lastChild);
            }
        }
    }
    // Append Translation Button's Toggle

    const nav_bar = document.querySelector('div[class*="HeaderView_action__"]');

    if (nav_bar) {
        if (!nav_bar.querySelector('div[class*="HeaderView_action__"] .HeaderView_translate_status[trans_btn_added]')) {
            const trans_status_btn = document.createElement("button");
            trans_status_btn.classList.add("HeaderView_translate_status");
            trans_status_btn.setAttribute("type", "button");
            trans_status_btn.setAttribute("trans_btn_added", "");
            trans_status_btn.style.setProperty("--trans_background", auto_translate_status ? trans_button_active : trans_button_not_active);
            trans_status_btn.setAttribute('title', auto_translate_status ? "Auto translator for artists' posts is active" : "Auto translator for artists' posts is not active");
            trans_status_btn.addEventListener("click", () => toggle_auto_translate());
            nav_bar.insertBefore(trans_status_btn, nav_bar.children[nav_bar.children.length - 2]);

            if (auto_translate_status) {
                start_auto_translate()
            }

        }
    }

}

function start_auto_translate() {
    console.log("Auto translate is activated.");
    auto_translate_observer  = new MutationObserver(auto_translate_f);
    auto_translate_observer .observe(document, mutation_config);
}

function stop_auto_translate() {
    console.log("Auto translate is deactivated.");
    autoTranslateArtist = false;
    GM_setValue('storage_translator', false);
    auto_translate_observer .disconnect();
}

function auto_translate_f(changes, observer) {
    const current_url = window.location.href;
    const valid_url_pattern = /^https:\/\/weverse\.io\/\w+\/(artist|feed|fanpost|moment).*/;

    if (valid_url_pattern.test(current_url)) {
        const artist_posts = document.querySelectorAll('div[class^="PostHeaderView_header_wrap"]:has(em.BadgeView_badge__sSoG5.BadgeView_-artist__jr7QG) button.TranslationButtonView_translation_button__VSa80, button.TranslationButtonView_translation_button__VSa80.TranslationButtonView_style-artist__VoK6K, button.TranslationButtonView_translation_button__VSa80.TranslationButtonView_style-moment__BuR5U');
        if (artist_posts) {
            const not_auto_clicked_buttons = Array.from(artist_posts).filter(button => button.getAttribute("aria-pressed") === "false");

            not_auto_clicked_buttons.forEach(button => {
                const is_moment = /^https:\/\/weverse\.io\/\w+\/moment.*/;
                if (is_moment.test(current_url)) {
                    console.log('This is a moment page.');
                    const moment_video = document.querySelector('.webplayer-internal-video');
                    if (moment_video && !moment_video.paused) {
                        button.click();
                        button.setAttribute("auto_clicked", "");
                        button.setAttribute("aria-pressed", "true");
                        setTimeout(() => {
                            const vtt_element = document.querySelector('div[class*=MomentViewerControlUiView_translation_result'); // Replace 'yourElementId' with the actual ID of the created element
                            if (vtt_element) {
                                console.log('Subtitle activated!');
                            } else {
                                button.click();
                                button.setAttribute("auto_clicked", "");
                                button.setAttribute("aria-pressed", "true");
                                console.log('retrying...');
                            }
                        }, 300);
                    } else {
                        console.log('video paused.')
                    }
                } else {
                    console.log('2', not_auto_clicked_buttons)
                    button.click();
                    button.setAttribute("auto_clicked", "");
                    button.setAttribute("aria-pressed", "true");
                }
            });
        }
    }
}


// Observers

const elem_appender_observer = new MutationObserver(append_elem);
elem_appender_observer.observe(document, mutation_config);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址