mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-29 19:01:43 +02:00
Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
7207646379 | |||
597c150c77 | |||
e7980c186d | |||
0c38b54c38 | |||
1929834c98 | |||
6e80ea08e8 | |||
a5caafa93a | |||
f8134c3e5a | |||
89ea55774b | |||
2836eeb6ed | |||
876b090ad2 | |||
e33730b124 | |||
8b4f26155c | |||
a52ba7dddf | |||
a8eb296bcf | |||
f4a3c38cca | |||
e8ab19c318 | |||
89e4dd0003 | |||
9874d36f3a | |||
ed54d1ed38 | |||
4676e42215 | |||
ad791bdc45 |
72
README.md
72
README.md
@ -2,21 +2,30 @@
|
||||
Improve [Xbox Cloud Gaming (xCloud)](https://www.xbox.com/play/) experience on web browser.
|
||||
The main target of this script is mobile users, but it should work great on desktop too.
|
||||
|
||||
Give this project a 🌟 if you like it. Thank you.
|
||||
Give this project a 🌟 if you like it. Thank you 🙏.
|
||||
|
||||
## Features
|
||||
|
||||
<img width="500" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/4f60c2e6-9706-4326-940f-f46998177633">
|
||||
<img width="500" alt="Video Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/130aa870-6938-4604-9e23-45e217b800cc">
|
||||
<img width="500" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/8fb9f0ac-85f5-4e5a-9570-5a5e119e4fc1">
|
||||
<img width="500" alt="Video Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/ed219d50-02ab-40bd-95c5-a010956d77bf">
|
||||
|
||||
|
||||
- **Switch region of streaming server**
|
||||
> Connect to another server instead of the default one. Check [FAQ section](#faq) for some notes.
|
||||
> Connect to another server instead of the default one. Check [FAQ section](#faq) for some notes.
|
||||
> Not working in Hermit ([#5](https://github.com/redphx/better-xcloud/issues/5)).
|
||||
- **Force 1080p stream**
|
||||
> By default you only get 1080p stream when playing on desktop.
|
||||
> This feature will give you 1080p stream even on mobile, without having to change User-Agent.
|
||||
> Not working in Hermit ([#5](https://github.com/redphx/better-xcloud/issues/5)).
|
||||
- **Force high quality codec (if possible)<sup>(\*)</sup>**
|
||||
> Force xCloud to use the best streaming codec profile (same as desktop & TV) if possible. You don't have to change User-Agent anymore.
|
||||
> You should enable this feature even if you're on desktop.
|
||||
> Use more bandwidth & battery.
|
||||
> Comparison video with the setting ON & OFF: https://youtu.be/-9PuBJJSgR4
|
||||
> Disable if it causes crashes.
|
||||
> This feature doesn't work on Kiwi Browser (unsupported codec).
|
||||
- **Prefer IPv6 streaming server**
|
||||
> Might reduce latency
|
||||
- **Force high quality stream**
|
||||
> Force xCloud to use the best streaming codec profile (same as desktop). You don't have to change User-Agent anymore.
|
||||
> Some browsers (like Firefox) don't support this feature. Check [the full list](https://caniuse.com/?search=setCodecPreferences).
|
||||
> If you're on Android and want to use it, try [Hermit](https://hermit.chimbori.com).
|
||||
- **Disable bandwidth checking**
|
||||
> xCloud won't reduce quality when the internet speed is slow
|
||||
- **Skip Xbox splash video**
|
||||
@ -29,12 +38,18 @@ Give this project a 🌟 if you like it. Thank you.
|
||||
> Useful when you don't have a 16:9 screen
|
||||
- **Adjust video filters**
|
||||
> Brightness/Contrast/Saturation
|
||||
- **Display stream's statuses**
|
||||
> Region/Server/Quality/Dimension...
|
||||
- **Disable social features**
|
||||
> Features like friends, chat... Disable these will make the page load faster.
|
||||
> Features like friends, chat... Disable these will make the page load faster.
|
||||
> Not working in Hermit ([#5](https://github.com/redphx/better-xcloud/issues/5)).
|
||||
- **Disable xCloud analytics**
|
||||
> The analytics contains statistics of your streaming session, so I'd recommend to allow analytics to help Xbox improve xCloud's experence in the future.
|
||||
> The analytics contains statistics of your streaming session, so I'd recommend to allow analytics to help Xbox improve xCloud's experence in the future.
|
||||
> Not working in Hermit ([#5](https://github.com/redphx/better-xcloud/issues/5)).
|
||||
- **Hide footer and other UI elements**
|
||||
|
||||
<sup>(\*)</sup> By default (for compatibility reasons) xCloud only uses high quality codec profile when you use Tizen TV or Chrome/Edge/Chromium browser on Chrome/MacOS. Enable this setting will give you the best experience no matter what platform & browser you're on.
|
||||
|
||||
## How to use
|
||||
1. Install [Tampermonkey extension](https://www.tampermonkey.net/) on suppported browsers. It's also available for Firefox on Android.
|
||||
2. Install **Better xCloud**:
|
||||
@ -50,19 +65,22 @@ To update manually, just install the script again (you won't lose your settings)
|
||||
✅ = confirmed to be working
|
||||
❓ = not yet tested
|
||||
❌ = not supported (mostly because of lacking Userscript/extension support)
|
||||
➖ = unavailable
|
||||
⚠️ = see custom notes
|
||||
| | Desktop | Android | iOS |
|
||||
|----------------------------------------|------------------|------------------|-----------------|
|
||||
| | Desktop | Android | iOS |
|
||||
|----------------------------------------|------------------|------------------|------------------|
|
||||
| Chrome/Edge/Chromium variants | ✅ | ❌ | ❌ |
|
||||
| Firefox | ✅ | ✅ | ❌ |
|
||||
| Safari | ✅<sup>(1)</sup> | ❌ | ✅<sup>(2)</sup> |
|
||||
| [Hermit](https://hermit.chimbori.com) | ❌ | ⚠️<sup>(3)</sup> | ❌ |
|
||||
| Firefox | ✅ | ✅<sup>(1)</sup> | ❌ |
|
||||
| Safari | ✅<sup>(2)</sup> | ➖ | ✅<sup>(3)</sup> |
|
||||
| [Hermit](https://hermit.chimbori.com) | ➖ | ⚠️<sup>(4)</sup> | ➖ |
|
||||
| Kiwi Browser | ➖ | ✅<sup>(5)</sup> | ➖ |
|
||||
|
||||
Don't see your browser in the table? If it supports Tampermonkey/Userscript then the answer is likely **"YES"**.
|
||||
|
||||
<sup>1, 2</sup> Requires [Userscripts app](https://apps.apple.com/us/app/userscripts/id1463298887).
|
||||
<sup>3</sup> NOT RECOMMENDED at the moment since its Userscript implementation is not working properly. Non-network related features (skip splash video, video settings...) still work. It's still my favorite app to play xCloud on because it's lightweight, supports Userscript (premium features, only $1.99) without having to install anything else. I built **Better xCloud** just so I could use it with Hermit.
|
||||
|
||||
<sup>1</sup> Follow [this guide](https://support.mozilla.org/en-US/kb/find-and-install-add-ons-firefox-android) to install Tampermonkey on Firefox Android.
|
||||
<sup>2, 3</sup> Requires [Userscripts app](https://apps.apple.com/us/app/userscripts/id1463298887) (free & open source).
|
||||
<sup>4</sup> NOT RECOMMENDED at the moment since its Userscript implementation is not working properly (see https://github.com/redphx/better-xcloud/issues/5 for full details). It's still my favorite app to play xCloud on because it's lightweight, supports Userscript (premium features, only $1.99) without having to install anything else. I built **Better xCloud** just so I could use it with Hermit.
|
||||
<sup>5</sup> The "Force high quality codec" is unsupported (causes crashes).
|
||||
## FAQ
|
||||
1. **Will I get banned for using this?**
|
||||
I think it's very unlikely that you'll get banned for using this. Most of the features only affect client-side, except for switching region of streaming server (you'll connect to another server instead of the default one). If you want to be safe just avoid using that. As always, use as your own risk.
|
||||
@ -79,14 +97,15 @@ No you can't. You'll have to modify the app.
|
||||
5. **Will you able to enable "Clarity Boost" feature on non-Edge browsers?**
|
||||
No. "Clarity Boost" feature uses an exclusive API (`Video.msVideoProcessing`) that's only available on Edge browser for desktop at the moment.
|
||||
|
||||
## Acknowledgements
|
||||
- [n-thumann/xbox-cloud-server-selector](https://github.com/n-thumann/xbox-cloud-server-selector) for the idea of IPv6 feature
|
||||
- Icons by [Adam Design](https://www.iconfinder.com/iconsets/user-interface-outline-27)
|
||||
|
||||
## User-Agent
|
||||
> You're no longer needed to change User-Agent since you can just use the **Force high quality stream** setting.
|
||||
> I'll still keep this section because it has some interesting info.
|
||||
You're no longer needed to change User-Agent since you can just use the **Force high quality stream** setting.
|
||||
If your browser doesn't support **Force high quality stream** setting, try changing User-Agent to:
|
||||
```
|
||||
Mozilla/5.0 (SMART-TV; LINUX; Tizen 7.0) AppleWebKit/537.36 (KHTML, like Gecko) 94.0.4606.31/7.0 TV Safari/537.36
|
||||
```
|
||||
This will change your device to a Samsung TV running Tizen OS. It will improve the stream quality.
|
||||
|
||||
---
|
||||
Change User-Agent to:
|
||||
```
|
||||
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67
|
||||
@ -99,7 +118,10 @@ Other options (only do one of these):
|
||||
- Add ` 36102dd3-6953-45f6-8b48-031fb95e0e0d` to become a Logitech G Cloud device.
|
||||
- Add ` 0ed22b6f-b61d-41eb-810a-a1ed586a550b` to become a Razer Edge device.
|
||||
|
||||
## Acknowledgements
|
||||
- [n-thumann/xbox-cloud-server-selector](https://github.com/n-thumann/xbox-cloud-server-selector) for the idea of IPv6 feature
|
||||
- Icons by [Adam Design](https://www.iconfinder.com/iconsets/user-interface-outline-27)
|
||||
|
||||
## Disclaimers
|
||||
- Use as your own risk.
|
||||
- This project is not affiliated with Xbox in any way. All Xbox logos/icons/trademarks are copyright of their respective owners.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 1.3.1
|
||||
// @version 1.4.1
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -13,15 +13,47 @@
|
||||
// ==/UserScript==
|
||||
'use strict';
|
||||
|
||||
const SCRIPT_VERSION = '1.3.1';
|
||||
const SCRIPT_VERSION = '1.4.1';
|
||||
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
||||
|
||||
const SERVER_REGIONS = {};
|
||||
|
||||
|
||||
class StreamStatus {
|
||||
static ipv6 = false;
|
||||
static dimension = {width: 0, height: 0};
|
||||
static hqCodec = false;
|
||||
static region = '';
|
||||
|
||||
static #renderBadge(name, value, color) {
|
||||
const CE = createElement;
|
||||
const $badge = CE('div', {'class': 'better_xcloud_badge'},
|
||||
CE('span', {'class': 'better_xcloud_badge_name'}, name),
|
||||
CE('span', {'class': 'better_xcloud_badge_value', 'style': `background-color: ${color}`}, value));
|
||||
|
||||
return $badge;
|
||||
}
|
||||
|
||||
static render() {
|
||||
const BADGES = [
|
||||
['region', StreamStatus.region, '#d7450b'],
|
||||
['server', StreamStatus.ipv6 ? 'IPv6' : 'IPv4', '#008746'],
|
||||
['quality', StreamStatus.hqCodec ? 'High' : 'Normal', '#007c8f'],
|
||||
['dimension', `${StreamStatus.dimension.width}x${StreamStatus.dimension.height}`, '#ff3977'],
|
||||
];
|
||||
|
||||
const $wrapper = createElement('div', {'class': 'better_xcloud_badges'});
|
||||
BADGES.forEach(item => $wrapper.appendChild(StreamStatus.#renderBadge(...item)));
|
||||
|
||||
return $wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Preferences {
|
||||
static get SERVER_REGION() { return 'server_region'; }
|
||||
static get PREFER_IPV6_SERVER() { return 'prefer_ipv6_server'; }
|
||||
static get FORCE_1080P_STREAM() { return 'force_1080p_stream'; }
|
||||
static get USE_DESKTOP_CODEC() { return 'use_desktop_codec'; }
|
||||
|
||||
static get BLOCK_TRACKING() { return 'block_tracking'; }
|
||||
@ -43,21 +75,27 @@ class Preferences {
|
||||
'default': 'default',
|
||||
},
|
||||
|
||||
{
|
||||
'id': Preferences.FORCE_1080P_STREAM,
|
||||
'label': 'Force 1080p stream',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
'id': Preferences.USE_DESKTOP_CODEC,
|
||||
'label': 'Force high quality codec (if possible)',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
'id': Preferences.PREFER_IPV6_SERVER,
|
||||
'label': 'Prefer IPv6 streaming server',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
'id': Preferences.USE_DESKTOP_CODEC,
|
||||
'label': 'Force high quality stream (same as desktop)',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
'id': Preferences.DISABLE_BANDWIDTH_CHECKING,
|
||||
'label': 'Disable bandwitdh checking',
|
||||
'label': 'Disable bandwidth checking',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
@ -81,7 +119,7 @@ class Preferences {
|
||||
|
||||
{
|
||||
'id': Preferences.BLOCK_SOCIAL_FEATURES,
|
||||
'label': 'Disable social features (Friends, Chat...)',
|
||||
'label': 'Disable social features',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
@ -193,7 +231,7 @@ function addCss() {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.better_xcloud_settings_button:hover, .better_xlcoud_settings_button:focus {
|
||||
.better_xcloud_settings_button:hover, .better_xcloud_settings_button:focus {
|
||||
background-color: #515863;
|
||||
}
|
||||
|
||||
@ -209,9 +247,9 @@ function addCss() {
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper {
|
||||
width: 400px;
|
||||
width: 450px;
|
||||
margin: auto;
|
||||
padding: 12px;
|
||||
padding: 12px 6px;
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper *:focus {
|
||||
@ -225,11 +263,23 @@ function addCss() {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #5dc21e;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.better_xcloud_settings_wrapper a:hover {
|
||||
color: #83f73a;
|
||||
}
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper a:focus {
|
||||
color: #83f73a;
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper .setting_row {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper .setting_row label {
|
||||
@ -238,6 +288,12 @@ function addCss() {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media not (hover: hover) {
|
||||
.better_xcloud_settings_wrapper .setting_row:focus-within {
|
||||
background-color: #242424;
|
||||
}
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper .setting_row input {
|
||||
align-self: center;
|
||||
}
|
||||
@ -263,8 +319,48 @@ function addCss() {
|
||||
}
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper .setting_button:focus {
|
||||
background-color: #00753c;
|
||||
}
|
||||
|
||||
.better_xcloud_settings_wrapper .setting_button:active {
|
||||
background-color: #00753c;
|
||||
background-color: #00753c;
|
||||
}
|
||||
|
||||
div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.better_xcloud_badges {
|
||||
position: absolute;
|
||||
bottom: -35px;
|
||||
margin-left: 0px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.better_xcloud_badge {
|
||||
border: none;
|
||||
display: inline-block;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
font-family: Bahnschrift Semibold, Arial, Helvetica, sans-serif;
|
||||
font-weight: 400;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.better_xcloud_badge .better_xcloud_badge_name {
|
||||
background-color: #2d3036;
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.better_xcloud_badge .better_xcloud_badge_value {
|
||||
background-color: grey;
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
/* Hide UI elements */
|
||||
@ -340,7 +436,7 @@ function getPreferredServerRegion() {
|
||||
|
||||
|
||||
function updateIceCandidates(candidates) {
|
||||
const pattern = new RegExp(/a=candidate:(?<order>\d+) (?<num>\d+) UDP (?<priority>\d+) (?<ip>[^\s]+) (?<the_rest>.*)/);
|
||||
const pattern = new RegExp(/a=candidate:(?<foundation>\d+) (?<component>\d+) UDP (?<priority>\d+) (?<ip>[^\s]+) (?<the_rest>.*)/);
|
||||
|
||||
const lst = [];
|
||||
for (let item of candidates) {
|
||||
@ -355,21 +451,19 @@ function updateIceCandidates(candidates) {
|
||||
lst.sort((a, b) => (a.ip.includes(':') || a.ip > b.ip) ? -1 : 1);
|
||||
|
||||
const newCandidates = [];
|
||||
let order = 1;
|
||||
let priority = 100;
|
||||
let foundation = 1;
|
||||
lst.forEach(item => {
|
||||
item.order = order;
|
||||
item.priority = priority;
|
||||
item.foundation = foundation;
|
||||
item.priority = (foundation == 1) ? 100 : 1;
|
||||
|
||||
newCandidates.push({
|
||||
'candidate': `a=candidate:${item.order} 1 UDP ${item.priority} ${item.ip} ${item.the_rest}`,
|
||||
'candidate': `a=candidate:${item.foundation} 1 UDP ${item.priority} ${item.ip} ${item.the_rest}`,
|
||||
'messageType': 'iceCandidate',
|
||||
'sdpMLineIndex': '0',
|
||||
'sdpMid': '0',
|
||||
});
|
||||
|
||||
++order;
|
||||
--priority;
|
||||
++foundation;
|
||||
});
|
||||
|
||||
newCandidates.push({
|
||||
@ -428,6 +522,9 @@ function interceptHttpRequests() {
|
||||
};
|
||||
|
||||
const PREF_PREFER_IPV6_SERVER = PREFS.get(Preferences.PREFER_IPV6_SERVER);
|
||||
const PREF_FORCE_1080P_STREAM = PREFS.get(Preferences.FORCE_1080P_STREAM);
|
||||
const PREF_USE_DESKTOP_CODEC = PREFS.get(Preferences.USE_DESKTOP_CODEC);
|
||||
const HAS_CODECS_API_SUPPORT = hasRtcSetCodecPreferencesSupport();
|
||||
|
||||
const orgFetch = window.fetch;
|
||||
window.fetch = async (...arg) => {
|
||||
@ -468,8 +565,59 @@ function interceptHttpRequests() {
|
||||
});
|
||||
}
|
||||
|
||||
// Get region
|
||||
if (url.endsWith('/sessions/cloud/play')) {
|
||||
const parsedUrl = new URL(url);
|
||||
|
||||
StreamStatus.region = parsedUrl.host.split('.', 1)[0];
|
||||
for (let regionName in SERVER_REGIONS) {
|
||||
const region = SERVER_REGIONS[regionName];
|
||||
if (parsedUrl.origin == region.baseUri) {
|
||||
StreamStatus.region = regionName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Force 1080p stream
|
||||
if (PREF_FORCE_1080P_STREAM) {
|
||||
// Intercept "osName" value
|
||||
const clone = request.clone();
|
||||
const body = await clone.json();
|
||||
body.settings.osName = 'windows';
|
||||
|
||||
const newRequest = new Request(request, {
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
arg[0] = newRequest;
|
||||
}
|
||||
|
||||
return orgFetch(...arg);
|
||||
}
|
||||
|
||||
// Work-around for browsers with no setCodecPreferences() support
|
||||
if (PREF_USE_DESKTOP_CODEC && !HAS_CODECS_API_SUPPORT && url.endsWith('/sdp') && url.includes('/sessions/cloud/') && request.method === 'GET') {
|
||||
const promise = orgFetch(...arg);
|
||||
|
||||
return promise.then(response => {
|
||||
return response.clone().text().then(text => {
|
||||
if (!text.length) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const obj = JSON.parse(text);
|
||||
obj.exchangeResponse = obj.exchangeResponse.replaceAll('profile-level-id=42', 'profile-level-id=4d');
|
||||
|
||||
response.json = () => Promise.resolve(obj);
|
||||
response.text = () => Promise.resolve(JSON.stringify(obj));
|
||||
|
||||
return response;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ICE server candidates
|
||||
if (PREF_PREFER_IPV6_SERVER && url.endsWith('/ice') && url.includes('/sessions/cloud/')) {
|
||||
if (PREF_PREFER_IPV6_SERVER && url.endsWith('/ice') && url.includes('/sessions/cloud/') && request.method === 'GET') {
|
||||
const promise = orgFetch(...arg);
|
||||
|
||||
return promise.then(response => {
|
||||
@ -484,6 +632,8 @@ function interceptHttpRequests() {
|
||||
obj.exchangeResponse = JSON.stringify(exchangeResponse);
|
||||
|
||||
response.json = () => Promise.resolve(obj);
|
||||
response.text = () => Promise.resolve(JSON.stringify(obj));
|
||||
|
||||
return response;
|
||||
});
|
||||
});
|
||||
@ -569,6 +719,7 @@ function injectSettingsButton($parent) {
|
||||
}
|
||||
|
||||
let $control;
|
||||
let labelAttrs = {};
|
||||
if (setting.id === Preferences.SERVER_REGION) {
|
||||
$control = CE('select', {id: 'xcloud_setting_' + setting.id});
|
||||
$control.addEventListener('change', e => {
|
||||
@ -608,22 +759,18 @@ function injectSettingsButton($parent) {
|
||||
setting.value = PREFS.get(setting.id);
|
||||
$control.checked = setting.value;
|
||||
|
||||
if (setting.id === Preferences.USE_DESKTOP_CODEC && !hasRtcSetCodecPreferencesSupport()) {
|
||||
$control.disabled = true;
|
||||
$control.checked = false;
|
||||
$control.title = 'Not supported by this browser';
|
||||
}
|
||||
labelAttrs = {'for': 'xcloud_setting_' + setting.id, 'tabindex': 0};
|
||||
}
|
||||
|
||||
const $elm = CE('div', {'class': 'setting_row'},
|
||||
CE('label', {'for': 'xcloud_setting_' + setting.id}, setting.label),
|
||||
CE('label', labelAttrs, setting.label),
|
||||
$control
|
||||
);
|
||||
|
||||
$wrapper.appendChild($elm);
|
||||
}
|
||||
|
||||
const $reloadBtn = CE('button', {'class': 'setting_button'}, 'Reload page to reflect changes');
|
||||
const $reloadBtn = CE('button', {'class': 'setting_button', 'tabindex': 0}, 'Reload page to reflect changes');
|
||||
$reloadBtn.addEventListener('click', e => window.location.reload());
|
||||
$wrapper.appendChild($reloadBtn);
|
||||
|
||||
@ -796,9 +943,6 @@ function injectVideoSettingsButton() {
|
||||
// Show Quick settings bar
|
||||
$quickBar.style.display = 'flex';
|
||||
|
||||
// Close HUD
|
||||
document.querySelector('button[class*=StreamMenu-module__backButton]').click();
|
||||
|
||||
$parent.addEventListener('click', hideQuickBarFunc);
|
||||
$parent.addEventListener('touchend', hideQuickBarFunc);
|
||||
|
||||
@ -809,6 +953,15 @@ function injectVideoSettingsButton() {
|
||||
});
|
||||
|
||||
$orgButton.parentElement.insertBefore($button, $orgButton.parentElement.firstChild);
|
||||
|
||||
// Hide Quick bar when closing HUD
|
||||
document.querySelector('button[class*=StreamMenu-module__backButton]').addEventListener('click', e => {
|
||||
$quickBar.style.display = 'none';
|
||||
});
|
||||
|
||||
// Render stream badges
|
||||
const $menu = document.querySelector('div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module]');
|
||||
$menu.appendChild(StreamStatus.render());
|
||||
});
|
||||
|
||||
});
|
||||
@ -825,6 +978,10 @@ function patchVideoApi() {
|
||||
showFunc = function() {
|
||||
this.style.visibility = 'visible';
|
||||
this.removeEventListener('playing', showFunc);
|
||||
|
||||
if (this.videoWidth) {
|
||||
StreamStatus.dimension = {width: this.videoWidth, height: this.videoHeight};
|
||||
}
|
||||
}
|
||||
|
||||
HTMLMediaElement.prototype.orgPlay = HTMLMediaElement.prototype.play;
|
||||
@ -864,19 +1021,37 @@ function patchRtcCodecs() {
|
||||
RTCRtpTransceiver.prototype.orgSetCodecPreferences = RTCRtpTransceiver.prototype.setCodecPreferences;
|
||||
RTCRtpTransceiver.prototype.setCodecPreferences = function(codecs) {
|
||||
// Use the same codecs as desktop
|
||||
codecs = [
|
||||
{
|
||||
'clockRate': 90000,
|
||||
'mimeType': 'video/H264',
|
||||
'sdpFmtpLine': 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f',
|
||||
},
|
||||
{
|
||||
'clockRate': 90000,
|
||||
'mimeType': 'video/H264',
|
||||
'sdpFmtpLine': 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f',
|
||||
let profileSetting;
|
||||
for (let codec of codecs) {
|
||||
if (codec.sdpFmtpLine.includes('profile-level-id=4d') || codec.sdpFmtpLine.includes('profile-level-id=42')) {
|
||||
profileSetting = codec.sdpFmtpLine.slice(-4); // get the last 4 characters
|
||||
break;
|
||||
}
|
||||
].concat(codecs);
|
||||
this.orgSetCodecPreferences(codecs);
|
||||
}
|
||||
|
||||
let newCodecs;
|
||||
if (profileSetting) {
|
||||
newCodecs = [
|
||||
{
|
||||
'clockRate': 90000,
|
||||
'mimeType': 'video/H264',
|
||||
'sdpFmtpLine': 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d' + profileSetting,
|
||||
},
|
||||
{
|
||||
'clockRate': 90000,
|
||||
'mimeType': 'video/H264',
|
||||
'sdpFmtpLine': 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d' + profileSetting,
|
||||
}
|
||||
].concat(codecs);
|
||||
} else {
|
||||
newCodecs = codecs;
|
||||
}
|
||||
|
||||
try {
|
||||
this.orgSetCodecPreferences(newCodecs);
|
||||
} catch (e) {
|
||||
this.orgSetCodecPreferences(codecs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1114,3 +1289,44 @@ window.onload = () => {
|
||||
if (document.readyState === 'complete' && !onLoadTriggered) {
|
||||
watchHeader();
|
||||
}
|
||||
|
||||
|
||||
RTCPeerConnection.prototype.orgSetRemoteDescription = RTCPeerConnection.prototype.setRemoteDescription;
|
||||
RTCPeerConnection.prototype.setRemoteDescription = function(...args) {
|
||||
StreamStatus.hqCodec = false;
|
||||
|
||||
const sdpDesc = args[0];
|
||||
if (sdpDesc.sdp) {
|
||||
const sdp = sdpDesc.sdp;
|
||||
|
||||
let lineIndex = 0;
|
||||
let endPos = 0;
|
||||
let line;
|
||||
while (lineIndex > -1) {
|
||||
lineIndex = sdp.indexOf('a=fmtp:', endPos);
|
||||
if (lineIndex === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
endPos = sdp.indexOf('\n', lineIndex);
|
||||
line = sdp.substring(lineIndex, endPos);
|
||||
if (line.includes('profile-level-id')) {
|
||||
StreamStatus.hqCodec = line.includes('profile-level-id=4d');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.orgSetRemoteDescription.apply(this, args);
|
||||
}
|
||||
|
||||
|
||||
RTCPeerConnection.prototype.orgAddIceCandidate = RTCPeerConnection.prototype.addIceCandidate;
|
||||
RTCPeerConnection.prototype.addIceCandidate = function(...args) {
|
||||
const candidate = args[0].candidate;
|
||||
if (candidate && candidate.startsWith('a=candidate:1 ')) {
|
||||
StreamStatus.ipv6 = candidate.substring(20).includes(':');
|
||||
}
|
||||
|
||||
return this.orgAddIceCandidate.apply(this, args);
|
||||
}
|
||||
|
Reference in New Issue
Block a user