[Chrome] Enable Picture-in-picture (PiP) for Weverse.io

Enable Picture-in-picture (PiP) on weverse.io for Chrome browser.

// ==UserScript==
// @name        [Chrome] Enable Picture-in-picture (PiP) 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.3
// @author      jho / @jhooo_o
// @run-at      document-end
// @description Enable Picture-in-picture (PiP) on weverse.io for Chrome browser.
// @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 mutation_config = { childList: true, subtree: true };

const is_firefox = /firefox/i.test(navigator.userAgent);
if (is_firefox) {
    console.log('██████████ User is using Firefox. PIP button will not be appended.');
} else {
    console.log('██████████ User is not using Firefox. PIP button will be added.');
}

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 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 && !is_firefox) {
            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);
            }
        }
    }

}

// Observers

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