mirror of
				https://github.com/redphx/better-xcloud.git
				synced 2025-11-03 23:44:05 +01:00 
			
		
		
		
	Controller shortcuts (#157)
* Basic code for GamepadHandler * Take screenshot using Home + RB * Enable shortcuts using setting * Only poll gamepad when playing * Toogle stats using Home + Select * Add basic Toast class * Update translations
This commit is contained in:
		@@ -375,6 +375,13 @@ const Translations = {
 | 
			
		||||
        "vi-VN": "Độ tương phản",
 | 
			
		||||
        "zh-CN": "对比度",
 | 
			
		||||
    },
 | 
			
		||||
    "controller": {
 | 
			
		||||
        "en-US": "Controller",
 | 
			
		||||
        "ja-JP": "コントローラー",
 | 
			
		||||
        "pl-PL": "Kontroler",
 | 
			
		||||
        "pt-BR": "Controle",
 | 
			
		||||
        "vi-VN": "Bộ điều khiển",
 | 
			
		||||
    },
 | 
			
		||||
    "custom": {
 | 
			
		||||
        "de-DE": "Benutzerdefiniert",
 | 
			
		||||
        "en-US": "Custom",
 | 
			
		||||
@@ -484,6 +491,13 @@ const Translations = {
 | 
			
		||||
        "vi-VN": "Khóa phân tích thông tin của xCloud",
 | 
			
		||||
        "zh-CN": "关闭 xCloud 遥测数据统计",
 | 
			
		||||
    },
 | 
			
		||||
    "enable-controller-shortcuts": {
 | 
			
		||||
        "en-US": "Enable controller shortcuts",
 | 
			
		||||
        "ja-JP": "コントローラーショートカットを有効化",
 | 
			
		||||
        "pl-PL": "Włącz skróty kontrolera",
 | 
			
		||||
        "pt-BR": "Ativar atalhos do controle",
 | 
			
		||||
        "vi-VN": "Bật tính năng phím tắt cho bộ điều khiển",
 | 
			
		||||
    },
 | 
			
		||||
    "enable-mic-on-startup": {
 | 
			
		||||
        "de-DE": "Mikrofon bei Spielstart aktivieren",
 | 
			
		||||
        "en-US": "Enable microphone on game launch",
 | 
			
		||||
@@ -623,6 +637,20 @@ const Translations = {
 | 
			
		||||
        "vi-VN": "Thông số stream",
 | 
			
		||||
        "zh-CN": "串流统计数据",
 | 
			
		||||
    },
 | 
			
		||||
    "microphone": {
 | 
			
		||||
        "en-US": "Microphone",
 | 
			
		||||
        "ja-JP": "マイク",
 | 
			
		||||
        "pl-PL": "Mikrofon",
 | 
			
		||||
        "pt-BR": "Microfone",
 | 
			
		||||
        "vi-VN": "Mic",
 | 
			
		||||
    },
 | 
			
		||||
    "muted": {
 | 
			
		||||
        "en-US": "Muted",
 | 
			
		||||
        "ja-JP": "ミュート",
 | 
			
		||||
        "pl-PL": "Wyciszony",
 | 
			
		||||
        "pt-BR": "Mutado",
 | 
			
		||||
        "vi-VN": "Đã tắt âm",
 | 
			
		||||
    },
 | 
			
		||||
    "normal": {
 | 
			
		||||
        "de-DE": "Mittel",
 | 
			
		||||
        "en-US": "Normal",
 | 
			
		||||
@@ -651,6 +679,13 @@ const Translations = {
 | 
			
		||||
        "vi-VN": "Tắt",
 | 
			
		||||
        "zh-CN": "关",
 | 
			
		||||
    },
 | 
			
		||||
    "on": {
 | 
			
		||||
        "en-US": "On",
 | 
			
		||||
        "ja-JP": "オン",
 | 
			
		||||
        "pl-PL": "Włącz",
 | 
			
		||||
        "pt-BR": "Ativado",
 | 
			
		||||
        "vi-VN": "Bật",
 | 
			
		||||
    },
 | 
			
		||||
    "opacity": {
 | 
			
		||||
        "de-DE": "Deckkraft",
 | 
			
		||||
        "en-US": "Opacity",
 | 
			
		||||
@@ -987,6 +1022,13 @@ const Translations = {
 | 
			
		||||
        "vi-VN": "Nhỏ",
 | 
			
		||||
        "zh-CN": "小",
 | 
			
		||||
    },
 | 
			
		||||
    "sound": {
 | 
			
		||||
        "en-US": "Sound",
 | 
			
		||||
        "ja-JP": "サウンド",
 | 
			
		||||
        "pl-PL": "Dźwięk",
 | 
			
		||||
        "pt-BR": "Som",
 | 
			
		||||
        "vi-VN": "Âm thanh",
 | 
			
		||||
    },
 | 
			
		||||
    "stat-bitrate": {
 | 
			
		||||
        "de-DE": "Bitrate",
 | 
			
		||||
        "en-US": "Bitrate",
 | 
			
		||||
@@ -1323,6 +1365,13 @@ const Translations = {
 | 
			
		||||
        "vi-VN": "Giao diện",
 | 
			
		||||
        "zh-CN": "UI",
 | 
			
		||||
    },
 | 
			
		||||
    "unmuted": {
 | 
			
		||||
        "en-US": "Unmuted",
 | 
			
		||||
        "ja-JP": "ミュート解除",
 | 
			
		||||
        "pl-PL": "Wyciszenie wyłączone",
 | 
			
		||||
        "pt-BR": "Desmutado",
 | 
			
		||||
        "vi-VN": "Đã mở âm",
 | 
			
		||||
    },
 | 
			
		||||
    "user-agent-profile": {
 | 
			
		||||
        "de-DE": "User-Agent Profil",
 | 
			
		||||
        "en-US": "User-Agent profile",
 | 
			
		||||
@@ -1500,6 +1549,7 @@ window.addEventListener('load', e => {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const SERVER_REGIONS = {};
 | 
			
		||||
var IS_PLAYING = false;
 | 
			
		||||
var STREAM_WEBRTC;
 | 
			
		||||
var STREAM_AUDIO_CONTEXT;
 | 
			
		||||
var STREAM_AUDIO_GAIN_NODE;
 | 
			
		||||
@@ -1893,6 +1943,164 @@ class TouchController {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Toast {
 | 
			
		||||
    static #$wrapper;
 | 
			
		||||
    static #$msg;
 | 
			
		||||
    static #$status;
 | 
			
		||||
 | 
			
		||||
    static setup() {
 | 
			
		||||
        Toast.#$wrapper = createElement('div', {'class': 'bx-toast bx-gone'},
 | 
			
		||||
                                        Toast.#$msg = createElement('span', {'class': 'bx-toast-msg'}),
 | 
			
		||||
                                        Toast.#$status = createElement('span', {'class': 'bx-toast-status'}));
 | 
			
		||||
 | 
			
		||||
        document.documentElement.appendChild(Toast.#$wrapper);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GamepadHandler {
 | 
			
		||||
    static #BUTTON_A = 0;
 | 
			
		||||
    static #BUTTON_B = 1;
 | 
			
		||||
    static #BUTTON_X = 2;
 | 
			
		||||
    static #BUTTON_Y = 3;
 | 
			
		||||
 | 
			
		||||
    static #BUTTON_UP = 12;
 | 
			
		||||
    static #BUTTON_DOWN = 13;
 | 
			
		||||
    static #BUTTON_LEFT = 14;
 | 
			
		||||
    static #BUTTON_RIGHT = 15;
 | 
			
		||||
 | 
			
		||||
    static #BUTTON_LB = 4;
 | 
			
		||||
    static #BUTTON_LT = 6;
 | 
			
		||||
    static #BUTTON_RB = 5;
 | 
			
		||||
    static #BUTTON_RT = 7;
 | 
			
		||||
 | 
			
		||||
    static #BUTTON_SELECT = 8;
 | 
			
		||||
    static #BUTTON_START = 9;
 | 
			
		||||
    static #BUTTON_HOME = 16;
 | 
			
		||||
 | 
			
		||||
    static #isPolling = false;
 | 
			
		||||
    static #pollingInterval;
 | 
			
		||||
    static #isHoldingHome = false;
 | 
			
		||||
    static #buttonsCache = [];
 | 
			
		||||
    static #buttonsStatus = [];
 | 
			
		||||
 | 
			
		||||
    static #emulatedGamepads = [null, null, null, null];
 | 
			
		||||
    static #nativeGetGamepads = window.navigator.getGamepads.bind(window.navigator);
 | 
			
		||||
 | 
			
		||||
    static #cloneGamepad(gamepad) {
 | 
			
		||||
        const buttons = Array(gamepad.buttons.length).fill({pressed: false, value: 0});
 | 
			
		||||
        buttons[GamepadHandler.#BUTTON_HOME] = {
 | 
			
		||||
            pressed: true,
 | 
			
		||||
            value: 0,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            timestamp: gamepad.timestamp,
 | 
			
		||||
            id: gamepad.id,
 | 
			
		||||
            index: gamepad.index,
 | 
			
		||||
            connected: gamepad.connected,
 | 
			
		||||
            mapping: gamepad.mapping,
 | 
			
		||||
            axes: [0, 0, 0, 0],
 | 
			
		||||
            buttons: buttons,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static #customGetGamepads() {
 | 
			
		||||
        return GamepadHandler.#emulatedGamepads;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static #isPressed(buttonIndex) {
 | 
			
		||||
        return !GamepadHandler.#buttonsCache[buttonIndex] && GamepadHandler.#buttonsStatus[buttonIndex];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static #poll() {
 | 
			
		||||
        // Move the buttons status from the previous frame to the cache
 | 
			
		||||
        GamepadHandler.#buttonsCache = GamepadHandler.#buttonsStatus.slice(0);
 | 
			
		||||
        // Clear the buttons status
 | 
			
		||||
        GamepadHandler.#buttonsStatus = [];
 | 
			
		||||
 | 
			
		||||
        const pressed = [];
 | 
			
		||||
        const timestamps = [0, 0, 0, 0];
 | 
			
		||||
        GamepadHandler.#nativeGetGamepads().forEach(gamepad => {
 | 
			
		||||
            if (!gamepad || gamepad.mapping !== 'standard' || !gamepad.buttons) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            gamepad.buttons.forEach((button, index) => {
 | 
			
		||||
                // Only add the newly pressed button to the array (holding doesn't count)
 | 
			
		||||
                if (button.pressed) {
 | 
			
		||||
                    timestamps[index] = gamepad.timestamp;
 | 
			
		||||
                    pressed[index] = true;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        GamepadHandler.#buttonsStatus = pressed;
 | 
			
		||||
        GamepadHandler.#isHoldingHome = !!pressed[GamepadHandler.#BUTTON_HOME];
 | 
			
		||||
 | 
			
		||||
        if (GamepadHandler.#isHoldingHome) {
 | 
			
		||||
            // Update timestamps
 | 
			
		||||
            GamepadHandler.#emulatedGamepads.forEach(gamepad => {
 | 
			
		||||
                gamepad && (gamepad.timestamp = timestamps[gamepad.index]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Patch getGamepads()
 | 
			
		||||
            window.navigator.getGamepads = GamepadHandler.#customGetGamepads;
 | 
			
		||||
 | 
			
		||||
            // Check pressed button
 | 
			
		||||
            if (GamepadHandler.#isPressed(GamepadHandler.#BUTTON_RB)) {
 | 
			
		||||
                takeScreenshot();
 | 
			
		||||
            } else if (GamepadHandler.#isPressed(GamepadHandler.#BUTTON_SELECT)) {
 | 
			
		||||
                StreamStats.toggle();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Restore to native getGamepads()
 | 
			
		||||
            window.navigator.getGamepads = GamepadHandler.#nativeGetGamepads;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static initialSetup() {
 | 
			
		||||
        window.addEventListener('gamepadconnected', e => {
 | 
			
		||||
            const gamepad = e.gamepad;
 | 
			
		||||
            console.log('Gamepad connected', gamepad);
 | 
			
		||||
 | 
			
		||||
            GamepadHandler.#emulatedGamepads[gamepad.index] = GamepadHandler.#cloneGamepad(gamepad);
 | 
			
		||||
            if (IS_PLAYING) {
 | 
			
		||||
                GamepadHandler.startPolling();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        window.addEventListener('gamepaddisconnected', e => {
 | 
			
		||||
            console.log('Gamepad disconnected', e.gamepad);
 | 
			
		||||
            GamepadHandler.#emulatedGamepads[e.gamepad.index] = null;
 | 
			
		||||
 | 
			
		||||
            // No gamepads left
 | 
			
		||||
            const noGamepads = GamepadHandler.#nativeGetGamepads().every(gamepad => gamepad === null);
 | 
			
		||||
            if (noGamepads) {
 | 
			
		||||
                GamepadHandler.stopPolling();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static startPolling() {
 | 
			
		||||
        if (GamepadHandler.#isPolling) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        GamepadHandler.stopPolling();
 | 
			
		||||
 | 
			
		||||
        GamepadHandler.#isPolling = true;
 | 
			
		||||
        GamepadHandler.#pollingInterval = setInterval(GamepadHandler.#poll, 50);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static stopPolling() {
 | 
			
		||||
        GamepadHandler.#isPolling = false;
 | 
			
		||||
        GamepadHandler.#isHoldingHome = false;
 | 
			
		||||
        GamepadHandler.#pollingInterval && clearInterval(GamepadHandler.#pollingInterval);
 | 
			
		||||
        GamepadHandler.#pollingInterval = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MouseCursorHider {
 | 
			
		||||
    static #timeout;
 | 
			
		||||
    static #cursorVisible = true;
 | 
			
		||||
@@ -2544,6 +2752,8 @@ class Preferences {
 | 
			
		||||
 | 
			
		||||
    static get STREAM_DISABLE_FEEDBACK_DIALOG() { return 'stream_disable_feedback_dialog'; }
 | 
			
		||||
 | 
			
		||||
    static get CONTROLLER_ENABLE_SHORTCUTS() { return 'controller_enable_shortcuts'; }
 | 
			
		||||
 | 
			
		||||
    static get SCREENSHOT_BUTTON_POSITION() { return 'screenshot_button_position'; }
 | 
			
		||||
    static get BLOCK_TRACKING() { return 'block_tracking'; }
 | 
			
		||||
    static get BLOCK_SOCIAL_FEATURES() { return 'block_social_features'; }
 | 
			
		||||
@@ -2761,6 +2971,9 @@ class Preferences {
 | 
			
		||||
        [Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: {
 | 
			
		||||
            'default': false,
 | 
			
		||||
        },
 | 
			
		||||
        [Preferences.CONTROLLER_ENABLE_SHORTCUTS]: {
 | 
			
		||||
            'default': false,
 | 
			
		||||
        },
 | 
			
		||||
        [Preferences.REDUCE_ANIMATIONS]: {
 | 
			
		||||
            'default': false,
 | 
			
		||||
        },
 | 
			
		||||
@@ -3797,6 +4010,35 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
 | 
			
		||||
    font-family: var(--bx-monospaced-font);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bx-toast {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    left: 50%;
 | 
			
		||||
    top: 24px;
 | 
			
		||||
    transform: translate(-50%, 0);
 | 
			
		||||
    background: #000000cc;
 | 
			
		||||
    border-radius: 40px;
 | 
			
		||||
    padding: 8px 18px;
 | 
			
		||||
    color: white;
 | 
			
		||||
    z-index: 999;
 | 
			
		||||
    font-family: var(--bx-normal-font);
 | 
			
		||||
    border: 1px solid #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bx-toast-msg {
 | 
			
		||||
    font-size: 12px;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bx-toast-status {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    font-size: 18px;
 | 
			
		||||
    text-transform: uppercase;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    margin-left: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (hover: hover) {
 | 
			
		||||
    .bx-quick-settings-bar button:hover {
 | 
			
		||||
        background-color: #414141;
 | 
			
		||||
@@ -4432,6 +4674,9 @@ function injectSettingsButton($parent) {
 | 
			
		||||
            [Preferences.STREAM_HIDE_IDLE_CURSOR]: __('hide-idle-cursor'),
 | 
			
		||||
            [Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: __('disable-post-stream-feedback-dialog'),
 | 
			
		||||
        },
 | 
			
		||||
        [__('controller')]: {
 | 
			
		||||
            [Preferences.CONTROLLER_ENABLE_SHORTCUTS]: __('enable-controller-shortcuts'),
 | 
			
		||||
        },
 | 
			
		||||
        [__('touch-controller')]: {
 | 
			
		||||
            [Preferences.STREAM_TOUCH_CONTROLLER]: __('tc-availability'),
 | 
			
		||||
            [Preferences.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD]: __('tc-standard-layout-style'),
 | 
			
		||||
@@ -4968,12 +5213,32 @@ function setupVideoSettingsBar() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function takeScreenshot(callback) {
 | 
			
		||||
    const $canvasContext = $SCREENSHOT_CANVAS.getContext('2d');
 | 
			
		||||
 | 
			
		||||
    $canvasContext.drawImage($STREAM_VIDEO, 0, 0, $SCREENSHOT_CANVAS.width, $SCREENSHOT_CANVAS.height);
 | 
			
		||||
    $SCREENSHOT_CANVAS.toBlob(blob => {
 | 
			
		||||
        // Download screenshot
 | 
			
		||||
        const now = +new Date;
 | 
			
		||||
        const $anchor = createElement('a', {
 | 
			
		||||
            'download': `${GAME_TITLE_ID}-${now}.png`,
 | 
			
		||||
            'href': URL.createObjectURL(blob),
 | 
			
		||||
        });
 | 
			
		||||
        $anchor.click();
 | 
			
		||||
 | 
			
		||||
        // Free screenshot from memory
 | 
			
		||||
        URL.revokeObjectURL($anchor.href);
 | 
			
		||||
        $canvasContext.clearRect(0, 0, $SCREENSHOT_CANVAS.width, $SCREENSHOT_CANVAS.height);
 | 
			
		||||
 | 
			
		||||
        callback && callback();
 | 
			
		||||
    }, 'image/png');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function setupScreenshotButton() {
 | 
			
		||||
    $SCREENSHOT_CANVAS = createElement('canvas', {'class': 'bx-screenshot-canvas'});
 | 
			
		||||
    document.documentElement.appendChild($SCREENSHOT_CANVAS);
 | 
			
		||||
 | 
			
		||||
    const $canvasContext = $SCREENSHOT_CANVAS.getContext('2d');
 | 
			
		||||
 | 
			
		||||
    const delay = 2000;
 | 
			
		||||
    const $btn = createElement('div', {'class': 'bx-screenshot-button', 'data-showing': false});
 | 
			
		||||
 | 
			
		||||
@@ -4990,20 +5255,7 @@ function setupScreenshotButton() {
 | 
			
		||||
            timeout = null;
 | 
			
		||||
            $btn.setAttribute('data-capturing', 'true');
 | 
			
		||||
 | 
			
		||||
            $canvasContext.drawImage($STREAM_VIDEO, 0, 0, $SCREENSHOT_CANVAS.width, $SCREENSHOT_CANVAS.height);
 | 
			
		||||
            $SCREENSHOT_CANVAS.toBlob(blob => {
 | 
			
		||||
                // Download screenshot
 | 
			
		||||
                const now = +new Date;
 | 
			
		||||
                const $anchor = createElement('a', {
 | 
			
		||||
                    'download': `${GAME_TITLE_ID}-${now}.png`,
 | 
			
		||||
                    'href': URL.createObjectURL(blob),
 | 
			
		||||
                });
 | 
			
		||||
                $anchor.click();
 | 
			
		||||
 | 
			
		||||
                // Free screenshot from memory
 | 
			
		||||
                URL.revokeObjectURL($anchor.href);
 | 
			
		||||
                $canvasContext.clearRect(0, 0, $SCREENSHOT_CANVAS.width, $SCREENSHOT_CANVAS.height);
 | 
			
		||||
 | 
			
		||||
            takeScreenshot(() => {
 | 
			
		||||
                // Hide button
 | 
			
		||||
                $btn.setAttribute('data-showing', 'false');
 | 
			
		||||
                setTimeout(() => {
 | 
			
		||||
@@ -5011,7 +5263,7 @@ function setupScreenshotButton() {
 | 
			
		||||
                        $btn.setAttribute('data-capturing', 'false');
 | 
			
		||||
                    }
 | 
			
		||||
                }, 100);
 | 
			
		||||
            }, 'image/png');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -5033,7 +5285,6 @@ function setupScreenshotButton() {
 | 
			
		||||
 | 
			
		||||
    $btn.addEventListener('mousedown', detectDbClick);
 | 
			
		||||
    document.documentElement.appendChild($btn);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -5050,6 +5301,8 @@ function patchHistoryMethod(type) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function onHistoryChanged() {
 | 
			
		||||
    IS_PLAYING = false;
 | 
			
		||||
 | 
			
		||||
    const $settings = document.querySelector('.better_xcloud_settings');
 | 
			
		||||
    if ($settings) {
 | 
			
		||||
        $settings.classList.add('bx-gone');
 | 
			
		||||
@@ -5070,11 +5323,15 @@ function onHistoryChanged() {
 | 
			
		||||
 | 
			
		||||
    LoadingScreen.reset();
 | 
			
		||||
 | 
			
		||||
    GamepadHandler.stopPolling();
 | 
			
		||||
 | 
			
		||||
    setTimeout(checkHeader, 2000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function onStreamStarted($video) {
 | 
			
		||||
    IS_PLAYING = true;
 | 
			
		||||
 | 
			
		||||
    // Get title ID for screenshot's name
 | 
			
		||||
    GAME_TITLE_ID = /\/launch\/([^/]+)/.exec(window.location.pathname)[1];
 | 
			
		||||
 | 
			
		||||
@@ -5082,6 +5339,10 @@ function onStreamStarted($video) {
 | 
			
		||||
        TouchController.enableBar();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (PREFS.get(Preferences.CONTROLLER_ENABLE_SHORTCUTS)) {
 | 
			
		||||
        GamepadHandler.startPolling();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const PREF_SCREENSHOT_BUTTON_POSITION = PREFS.get(Preferences.SCREENSHOT_BUTTON_POSITION);
 | 
			
		||||
    const PREF_STATS_QUICK_GLANCE = PREFS.get(Preferences.STATS_QUICK_GLANCE);
 | 
			
		||||
 | 
			
		||||
@@ -5275,7 +5536,6 @@ window.RTCPeerConnection = function() {
 | 
			
		||||
    return peer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
patchRtcCodecs();
 | 
			
		||||
interceptHttpRequests();
 | 
			
		||||
patchVideoApi();
 | 
			
		||||
@@ -5284,9 +5544,14 @@ patchVideoApi();
 | 
			
		||||
addCss();
 | 
			
		||||
updateVideoPlayerCss();
 | 
			
		||||
window.addEventListener('resize', updateVideoPlayerCss);
 | 
			
		||||
Toast.setup();
 | 
			
		||||
 | 
			
		||||
setupVideoSettingsBar();
 | 
			
		||||
setupScreenshotButton();
 | 
			
		||||
StreamStats.render();
 | 
			
		||||
 | 
			
		||||
disablePwa();
 | 
			
		||||
 | 
			
		||||
if (PREFS.get(Preferences.CONTROLLER_ENABLE_SHORTCUTS)) {
 | 
			
		||||
    GamepadHandler.initialSetup();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user