NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Twitch Player Quality Changer // @description Automatically change the quality of the Twitch player to your liking. // @downloadURL https://github.com/ramhaidar/Twitch-Player-Quality-Changer/raw/main/TwitchPlayerQualityChanger.user.js // @namespace https://github.com/ramhaidar/Twitch-Player-Quality-Changer // @version 0.0.7 // @author ramhaidar // @homepageURL https://github.com/ramhaidar/Twitch-Player-Quality-Changer // @icon https://www.google.com/s2/favicons?sz=64&domain=twitch.tv // @license MIT // @match https://www.twitch.tv/* // @match https://player.twitch.tv/* // @grant none // @run-at document-end // @updateURL https://github.com/ramhaidar/Twitch-Player-Quality-Changer/raw/main/TwitchPlayerQualityChanger.user.js // ==/UserScript== (function () { 'use strict'; // Set the desired auto-quality. /* Available Quality Options: - 1080p60 - 936p60 - 720p60 - 720p - 480p - 360p - 160p */ const PreferedQuality = "480p"; // Change this to your Prefered Quality const AllQuality = ["1080p60", "936p60", "720p60", "720p", "480p", "360p", "160p"]; const PreferredIndex = AllQuality.indexOf(PreferedQuality); // A function that waits for an element to exist in the DOM and then executes a callback function. function waitForElement(selector, maxAttempts = 10, callback) { let attempts = 0; const intervalId = setInterval(function () { const element = document.querySelector(selector); if (element) { clearInterval(intervalId); callback(element); } else { attempts++; if (attempts >= maxAttempts) { clearInterval(intervalId); console.warn('Element ' + selector + ' not found after ' + maxAttempts + ' attempts'); } } }, 500); } // Get the element that indicates if a channel is live or offline. const elem = document.querySelector('.tw-channel-status-text-indicator, .channel-status-info'); // A callback function to execute when the element is found. function onElementFound(elem) { console.warn('Element found:', elem); main(); } // A function that waits until the element exists in the DOM, then executes a callback function. function waitUntilElementExists(elem, callback) { elem = document.querySelector('.tw-channel-status-text-indicator, .channel-status-info'); if (elem !== null) { callback(elem); } else { setTimeout(function () { waitUntilElementExists(elem, callback); }, 500); } } waitUntilElementExists(elem, onElementFound); function main() { // Check if the channel is live or offline. if (document.querySelector('.tw-channel-status-text-indicator')?.textContent === "LIVE" || document.querySelector('.channel-status-info')?.textContent === "Offline") { console.warn("Channel is live or offline."); let settingsButton = null; let settingsMenuButton = null; // Click the settings button. waitForElement('[data-a-target="player-settings-button"]', 25, function (element) { settingsButton = element; settingsButton.click(); }); // Click the quality settings button. waitForElement('[data-a-target="player-settings-menu-item-quality"]', 25, function (element) { settingsMenuButton = element; settingsMenuButton.click(); }); // Wait for the quality options to load and select the preferred quality option. waitForElement('[data-a-target="tw-radio"]', 25, function (element) { const inputs = document.querySelectorAll('input[type="radio"]'); var qualityFound = false; var inputsx = document.querySelectorAll('input[type="radio"]') for (let i = 0; i < inputsx.length; i++) { if (inputsx[i].parentNode.textContent.includes(AllQuality[PreferredIndex])) { qualityFound = true; } } console.warn("Preferred Quality Found: " + qualityFound); // If the preferred quality is available, select it. if (qualityFound == true) { for (let i = 0; i < inputs.length; i++) { const label = inputs[i].parentNode.querySelector('label'); if (label && label.textContent.trim().includes(AllQuality[PreferredIndex])) { inputs[i].checked = true; inputs[i].click(); console.warn("Quality Used: " + inputs[i].parentNode.querySelector('label').textContent); // Click the settings button again. waitForElement('[data-a-target="player-settings-button"]', Infinity, function (element) { var settingsButton = element; settingsButton.click(); console.warn("Clicked Settings Button"); }); } } } // If the preferred quality is not available, select the lowest available quality. if (qualityFound == false) { var lastQualityIndex = AllQuality.length - 1; var lastInputIndex = inputsx.length - 1; inputsx[lastInputIndex].checked = true; inputsx[lastInputIndex].click(); console.warn("Quality Used: " + inputsx[lastInputIndex].parentNode.querySelector('label').textContent); // Click the settings button again. waitForElement('[data-a-target="player-settings-button"]', Infinity, function (element) { var settingsButton = element; settingsButton.click(); console.warn("Clicked Settings Button"); }); } }); } else { console.warn("Can't detect whether Channel is live or offline."); } } })();