mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-07-03 21:01:43 +02:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
3a82b74cda | |||
dce0a44d2a | |||
1d0d69850f | |||
e719e6e1c5 | |||
9f3c6e5a6d | |||
b6e1d3debc | |||
c229cf7c47 |
12
.github/ISSUE_TEMPLATE/bug_report.md
vendored
12
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,18 +1,18 @@
|
|||||||
---
|
---
|
||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
title: "[Bug]"
|
title: "[Bug] ..."
|
||||||
labels: bug
|
labels: bug
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Platform**
|
**Platform**
|
||||||
- Device: [e.g. Phone, Laptop, Desktop, TV]
|
- Device: Phone, Laptop, Desktop, TV...
|
||||||
- OS: [e.g. Windows, Android, iOS]
|
- OS: Windows, Android, iOS...
|
||||||
- Browser: [e.g. Chrome, Kiwi]
|
- Browser: Chrome, Safari, Kiwi...
|
||||||
- Browser Version: [e.g. 100]
|
- Browser Version:
|
||||||
- Better xCloud Version: [e.g. 1.10]
|
- Better xCloud Version:
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
...
|
...
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: Feature request
|
name: Feature request
|
||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
title: "[Feature]"
|
title: "[Feature] ..."
|
||||||
labels: enhancement
|
labels: enhancement
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
|
50
README.md
50
README.md
@ -30,12 +30,15 @@ If you like this project please give it a 🌟. Thank you 🙏.
|
|||||||
<br>
|
<br>
|
||||||
<img width="600" alt="Stream HUD" src="https://github.com/redphx/better-xcloud/assets/96280/e30f6514-13ca-41c6-bff2-979573cff956">
|
<img width="600" alt="Stream HUD" src="https://github.com/redphx/better-xcloud/assets/96280/e30f6514-13ca-41c6-bff2-979573cff956">
|
||||||
<br>
|
<br>
|
||||||
<img width="600" alt="Video settings" src="https://github.com/redphx/better-xcloud/assets/96280/c45877f9-379c-4ba4-977c-021d3d8835e4">
|
<img width="600" alt="Video settings" src="https://github.com/redphx/better-xcloud/assets/96280/a8614693-7f56-4a49-82ad-c1fd7e2e00a5">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Demo video:** [https://youtu.be/oDr5Eddp55E ](https://youtu.be/AYb-EUcz72U)
|
**Demo video:** [https://youtu.be/oDr5Eddp55E ](https://youtu.be/AYb-EUcz72U)
|
||||||
|
|
||||||
|
- **🔥 Improve visual quality of the stream**
|
||||||
|
> Similar to (but not as good as) the "Clarity Boost" of xCloud on Edge browser. [Demo video](https://youtu.be/ZhW2choAHUs).
|
||||||
- **🔥 Show stream stats**
|
- **🔥 Show stream stats**
|
||||||
> Check [Stream stats section](#stream-stats) for more info.
|
> Check [Stream stats section](#stream-stats) for more info.
|
||||||
- **🔥 Capture screenshot**
|
- **🔥 Capture screenshot**
|
||||||
@ -74,19 +77,20 @@ If you like this project please give it a 🌟. Thank you 🙏.
|
|||||||
|
|
||||||
### 🔥 Touch controller
|
### 🔥 Touch controller
|
||||||
- **Availability**
|
- **Availability**
|
||||||
> Only for devices with touch support (Android/iOS/iPadOS/...).
|
> Only for devices with touch support (Android/iOS/iPadOS/...). Using "Desktop mode" in mobile browsers also disables this feature.
|
||||||
> - **Default**: nothing change.
|
> - **Default**: nothing change.
|
||||||
> - **Off**: stop the touch controller from showing when touching the screen. Useful when you play on a device with a built-in controller like Logitech G Cloud, Steam Deck, etc.
|
> - **Off**: stop the touch controller from showing when touching the screen. Useful when you play on a device with a built-in controller like Logitech G Cloud, Steam Deck, etc.
|
||||||
> - **All games**: enable touch controller support for all games. Games with custom layout won't be affected.
|
> - **All games**: enable touch controller support for all games. Games with custom layout won't be affected.
|
||||||
> Double-tap anywhere at the bottom of the screen to show/hide the controller. Useful when you're viewing cutscenes.
|
> Double-tap anywhere at the bottom of the screen to show/hide the controller. Useful when you're viewing cutscenes.
|
||||||
> 
|
>
|
||||||
|
> 
|
||||||
- **Button styles**
|
- **Button styles**
|
||||||
> - Default
|
> - Default
|
||||||
> - Muted
|
> - Muted
|
||||||
> - All white (only for standard/default controller)
|
> - All white (only for standard/default controller)
|
||||||
|
>
|
||||||
> <img width="400" alt="Button styles" src="https://github.com/redphx/better-xcloud/assets/96280/2bfef2b3-6712-4924-b067-c2312f8c8062">
|
> <img width="400" alt="Button styles" src="https://github.com/redphx/better-xcloud/assets/96280/2bfef2b3-6712-4924-b067-c2312f8c8062">
|
||||||
|
|
||||||
|
|
||||||
### UI
|
### UI
|
||||||
- **Simplify Stream's menu**
|
- **Simplify Stream's menu**
|
||||||
> Hide the labels of the menu buttons.
|
> Hide the labels of the menu buttons.
|
||||||
@ -104,12 +108,20 @@ If you like this project please give it a 🌟. Thank you 🙏.
|
|||||||
> The analytics contains statistics of your streaming session, so I'd recommend allowing analytics to help Xbox improve xCloud's experience in the future.
|
> The analytics contains statistics of your streaming session, so I'd recommend allowing analytics to help Xbox improve xCloud's experience in the future.
|
||||||
|
|
||||||
### Stream's video features
|
### Stream's video features
|
||||||
⚠️ These features don't work when xCloud's "Clarity Boost" feature is ON ([#64](https://github.com/redphx/better-xcloud/issues/64)).
|
|
||||||
|
- **🔥 Improve stream's clarity**
|
||||||
|
> Similar to (but not as good as) the "Clarity Boost" of xCloud on Edge browser. [Demo video](https://youtu.be/ZhW2choAHUs).
|
||||||
|
> Also known as poor man's "Clarity Boost".
|
||||||
|
> Affects the stream's performance, uses more battery, and may causes frames to drop (especially on lower-end devices).
|
||||||
|
> Doesn't work with Safari.
|
||||||
|
>
|
||||||
|
> 
|
||||||
|
|
||||||
- **Stretch video to full sctreen**
|
- **Stretch video to full sctreen**
|
||||||
> Useful when you don't have a 16:9 screen
|
> Useful when you don't have a 16:9 screen
|
||||||
- **Adjust video filters**
|
- **Adjust video filters**
|
||||||
> Brightness/Contrast/Saturation.
|
> Brightness/Contrast/Saturation.
|
||||||
|
> ⚠️ These features don't work when xCloud's "Clarity Boost" feature is ON ([#64](https://github.com/redphx/better-xcloud/issues/64)).
|
||||||
- **Display stream's statuses**
|
- **Display stream's statuses**
|
||||||
> Region/Server/Codecs/Resolution...
|
> Region/Server/Codecs/Resolution...
|
||||||
> Current playtime of the session.
|
> Current playtime of the session.
|
||||||
@ -126,7 +138,7 @@ If you like this project please give it a 🌟. Thank you 🙏.
|
|||||||
<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.
|
<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 install
|
## How to install
|
||||||
1. Install [Tampermonkey extension](https://www.tampermonkey.net/) on suppported browsers. For Safari, use [Userscripts app](https://apps.apple.com/us/app/userscripts/id1463298887) (not working properly, see [#81](https://github.com/redphx/better-xcloud/issues/81)).
|
1. Install [Tampermonkey extension](https://www.tampermonkey.net/) on suppported browsers. For Safari, use the [Userscripts extension](https://apps.apple.com/us/app/userscripts/id1463298887) (check [this page](https://github.com/redphx/better-xcloud/wiki/Using-with-Safari) before using).
|
||||||
2. Install **Better xCloud**:
|
2. Install **Better xCloud**:
|
||||||
- [Stable version](https://github.com/redphx/better-xcloud/releases/latest/download/better-xcloud.user.js)
|
- [Stable version](https://github.com/redphx/better-xcloud/releases/latest/download/better-xcloud.user.js)
|
||||||
- [Dev version](https://github.com/redphx/better-xcloud/raw/main/better-xcloud.user.js)
|
- [Dev version](https://github.com/redphx/better-xcloud/raw/main/better-xcloud.user.js)
|
||||||
@ -170,6 +182,9 @@ Don't see your browser in the table? If it supports Tampermonkey/Userscript then
|
|||||||
- **Better xCloud** also works on Android TV, but you'll have to sideload the browser APK and need a Bluetooth mouse if you want to interact with the Settings.
|
- **Better xCloud** also works on Android TV, but you'll have to sideload the browser APK and need a Bluetooth mouse if you want to interact with the Settings.
|
||||||
|
|
||||||
## Stream stats
|
## Stream stats
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
<img width="500" alt="Stream stats" src="https://github.com/redphx/better-xcloud/assets/96280/0d4abb6b-49ab-4c9a-a52d-df7e396d2145">
|
<img width="500" alt="Stream stats" src="https://github.com/redphx/better-xcloud/assets/96280/0d4abb6b-49ab-4c9a-a52d-df7e396d2145">
|
||||||
|
|
||||||
- While playing > `...` > `Stream Stats`.
|
- While playing > `...` > `Stream Stats`.
|
||||||
@ -178,14 +193,14 @@ Don't see your browser in the table? If it supports Tampermonkey/Userscript then
|
|||||||
- **Quick glance** feature: only show the stats bar when the System menu is expanded. The 👀 emoji at the beginning indicates that the stats bar is in the quick glance mode.
|
- **Quick glance** feature: only show the stats bar when the System menu is expanded. The 👀 emoji at the beginning indicates that the stats bar is in the quick glance mode.
|
||||||
- ⚠️ Using **Better xCloud** or showing the stats bar also affects the performance of the stream.
|
- ⚠️ Using **Better xCloud** or showing the stats bar also affects the performance of the stream.
|
||||||
|
|
||||||
| Abbr. | Full name | Explain |
|
| Abbr. | Full name | Explain |
|
||||||
|------:|:-------------------|:-------------------------------------------------------------------------------------------------------------------------------------------|
|
|------:|:-------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| FPS | Frames per Seconds | The number of decoded frames in the last second of the stream (may not be the same as the FPS of the game) |
|
| FPS | Frames per Seconds | The number of decoded frames in the last second of the stream (may not be the same as the FPS of the game) |
|
||||||
|
| RTT | Round Trip Time | The number of seconds it takes for data to be sent from your device to the server and back over (similar to ping, lower is better) |
|
||||||
| DT | Decode Time | The average time it took to decode one frame in the last second (bugged in Kiwi Browser [#26](https://github.com/redphx/better-xcloud/issues/26)) |
|
| DT | Decode Time | The average time it took to decode one frame in the last second (bugged in Kiwi Browser [#26](https://github.com/redphx/better-xcloud/issues/26)) |
|
||||||
| RTT | Round Trip Time | The number of seconds it takes for data to be sent from your device to the server and back over (similar to ping, lower is better) |
|
| BR | Bitrate | The amount of data the server sent to your device in the last second |
|
||||||
| BR | Bitrate | The amount of data the server sent to your device in the last second |
|
| PL | Packets Lost | The total number of packets lost |
|
||||||
| PL | Packets Lost | The total number of packets lost |
|
| FL | Frames Lost | The total number of frames dropped prior to decode or dropped because the frame missed its display deadline |
|
||||||
| FL | Frames Lost | The total number of frames dropped prior to decode or dropped because the frame missed its display deadline |
|
|
||||||
|
|
||||||
This info is provided by WebRTC API. You can use browser's built-in tool to see more info:
|
This info is provided by WebRTC API. You can use browser's built-in tool to see more info:
|
||||||
- Chrome/Edge/Chromium variants: `chrome://webrtc-internals`
|
- Chrome/Edge/Chromium variants: `chrome://webrtc-internals`
|
||||||
@ -217,7 +232,7 @@ Colors:
|
|||||||
5. Screenshot will be saved by the browser.
|
5. Screenshot will be saved by the browser.
|
||||||
6. You can double-tap that corner to capture screenshot.
|
6. You can double-tap that corner to capture screenshot.
|
||||||
|
|
||||||
<img width="600" alt="Screenshot button" src="https://github.com/redphx/better-xcloud/assets/96280/a911b141-5dc0-450a-aeac-30d9cf202b44">
|

|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
1. **Will I get banned for using this?**
|
1. **Will I get banned for using this?**
|
||||||
@ -236,12 +251,13 @@ Think of this project as an unofficial beta version of xCloud.
|
|||||||
No, you can't. You'll have to modify the app.
|
No, you can't. You'll have to modify the app.
|
||||||
|
|
||||||
5. **Will it be able to enable the "Clarity Boost" feature on non-Edge browsers?**
|
5. **Will it be able to enable the "Clarity Boost" feature on non-Edge browsers?**
|
||||||
No. The "Clarity Boost" feature uses an exclusive API (`Video.msVideoProcessing`) that's only available on Edge browser for desktop at the moment.
|
~~No. The "Clarity Boost" feature uses an exclusive API (`Video.msVideoProcessing`) that's only available on Edge browser for desktop at the moment.~~
|
||||||
|
Fake news! This feature has been implemented in **Better xCloud** since version 1.12, but the original "Clarity Boost" still perform better.
|
||||||
|
|
||||||
6. **Will it be able to request a lower FPS or increase the maximum bitrate (15Mbps) of the stream?**
|
7. **Will it be able to request a lower FPS or increase the maximum bitrate (15Mbps) of the stream?**
|
||||||
Sorry, no. The server decides all these settings.
|
Sorry, no. The server decides all these settings.
|
||||||
|
|
||||||
7. **What's the meaning behind the name "Better xCloud"?**
|
8. **What's the meaning behind the name "Better xCloud"?**
|
||||||
It's a reference to an Userscript called "better360" that I created many years ago. I regret not choosing the name "xCloud Enhancement Suite", or XES for short.
|
It's a reference to an Userscript called "better360" that I created many years ago. I regret not choosing the name "xCloud Enhancement Suite", or XES for short.
|
||||||
|
|
||||||
## Donation
|
## Donation
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 1.11
|
// @version 1.12
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 1.11
|
// @version 1.12
|
||||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||||
// @author redphx
|
// @author redphx
|
||||||
// @license MIT
|
// @license MIT
|
||||||
@ -13,18 +13,37 @@
|
|||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const SCRIPT_VERSION = '1.12';
|
||||||
|
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
||||||
|
|
||||||
console.log(`[Better xCloud] readyState: ${document.readyState}`);
|
console.log(`[Better xCloud] readyState: ${document.readyState}`);
|
||||||
|
|
||||||
|
|
||||||
// Quickly create a tree of elements without having to use innerHTML
|
// Quickly create a tree of elements without having to use innerHTML
|
||||||
function createElement(elmName, props = {}) {
|
function createElement(elmName, props = {}) {
|
||||||
const $elm = document.createElement(elmName);
|
let $elm;
|
||||||
|
const hasNs = 'xmlns' in props;
|
||||||
|
|
||||||
|
if (hasNs) {
|
||||||
|
$elm = document.createElementNS(props.xmlns, elmName);
|
||||||
|
} else {
|
||||||
|
$elm = document.createElement(elmName);
|
||||||
|
}
|
||||||
|
|
||||||
for (let key in props) {
|
for (let key in props) {
|
||||||
|
if (key === 'xmlns') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!props.hasOwnProperty(key) || $elm.hasOwnProperty(key)) {
|
if (!props.hasOwnProperty(key) || $elm.hasOwnProperty(key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$elm.setAttribute(key, props[key]);
|
if (hasNs) {
|
||||||
|
$elm.setAttributeNS(null, key, props[key]);
|
||||||
|
} else {
|
||||||
|
$elm.setAttribute(key, props[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 2, size = arguments.length; i < size; i++) {
|
for (let i = 2, size = arguments.length; i < size; i++) {
|
||||||
@ -79,15 +98,13 @@ window.addEventListener('load', e => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (document.body.classList.contains('legacyBackground')) {
|
if (document.body.classList.contains('legacyBackground')) {
|
||||||
// Has error message -> reload page
|
// Has error message -> reload page
|
||||||
|
window.stop();
|
||||||
window.location.reload(true);
|
window.location.reload(true);
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const SCRIPT_VERSION = '1.11';
|
|
||||||
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
|
||||||
|
|
||||||
const SERVER_REGIONS = {};
|
const SERVER_REGIONS = {};
|
||||||
var STREAM_WEBRTC;
|
var STREAM_WEBRTC;
|
||||||
var $STREAM_VIDEO;
|
var $STREAM_VIDEO;
|
||||||
@ -765,8 +782,12 @@ class UserAgent {
|
|||||||
[UserAgent.PROFILE_SMARTTV_TIZEN]: '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',
|
[UserAgent.PROFILE_SMARTTV_TIZEN]: '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',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDefault() {
|
||||||
|
return window.navigator.orgUserAgent || window.navigator.userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
static get(profile) {
|
static get(profile) {
|
||||||
const defaultUserAgent = window.navigator.orgUserAgent || window.navigator.userAgent;
|
const defaultUserAgent = UserAgent.getDefault();
|
||||||
if (profile === UserAgent.PROFILE_CUSTOM) {
|
if (profile === UserAgent.PROFILE_CUSTOM) {
|
||||||
return PREFS.get(Preferences.USER_AGENT_CUSTOM, '');
|
return PREFS.get(Preferences.USER_AGENT_CUSTOM, '');
|
||||||
}
|
}
|
||||||
@ -774,6 +795,17 @@ class UserAgent {
|
|||||||
return UserAgent.#USER_AGENTS[profile] || defaultUserAgent;
|
return UserAgent.#USER_AGENTS[profile] || defaultUserAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isSafari(mobile=false) {
|
||||||
|
const userAgent = (UserAgent.getDefault() || '').toLowerCase();
|
||||||
|
let result = userAgent.includes('safari') && !userAgent.includes('chrom');
|
||||||
|
|
||||||
|
if (result && mobile) {
|
||||||
|
result = userAgent.includes('mobile');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static spoof() {
|
static spoof() {
|
||||||
const profile = PREFS.get(Preferences.USER_AGENT_PROFILE);
|
const profile = PREFS.get(Preferences.USER_AGENT_PROFILE);
|
||||||
if (profile === UserAgent.PROFILE_DEFAULT) {
|
if (profile === UserAgent.PROFILE_DEFAULT) {
|
||||||
@ -861,6 +893,7 @@ class Preferences {
|
|||||||
static get HIDE_DOTS_ICON() { return 'hide_dots_icon'; }
|
static get HIDE_DOTS_ICON() { return 'hide_dots_icon'; }
|
||||||
static get REDUCE_ANIMATIONS() { return 'reduce_animations'; }
|
static get REDUCE_ANIMATIONS() { return 'reduce_animations'; }
|
||||||
|
|
||||||
|
static get VIDEO_CLARITY() { return 'video_clarity'; }
|
||||||
static get VIDEO_FILL_FULL_SCREEN() { return 'video_fill_full_screen'; }
|
static get VIDEO_FILL_FULL_SCREEN() { return 'video_fill_full_screen'; }
|
||||||
static get VIDEO_BRIGHTNESS() { return 'video_brightness'; }
|
static get VIDEO_BRIGHTNESS() { return 'video_brightness'; }
|
||||||
static get VIDEO_CONTRAST() { return 'video_contrast'; }
|
static get VIDEO_CONTRAST() { return 'video_contrast'; }
|
||||||
@ -1005,6 +1038,11 @@ class Preferences {
|
|||||||
[Preferences.USER_AGENT_CUSTOM]: {
|
[Preferences.USER_AGENT_CUSTOM]: {
|
||||||
'default': '',
|
'default': '',
|
||||||
},
|
},
|
||||||
|
[Preferences.VIDEO_CLARITY]: {
|
||||||
|
'default': 0,
|
||||||
|
'min': 0,
|
||||||
|
'max': 3,
|
||||||
|
},
|
||||||
[Preferences.VIDEO_FILL_FULL_SCREEN]: {
|
[Preferences.VIDEO_FILL_FULL_SCREEN]: {
|
||||||
'default': false,
|
'default': false,
|
||||||
},
|
},
|
||||||
@ -1242,6 +1280,10 @@ function addCss() {
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.better-xcloud-hidden {
|
||||||
|
visibility: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
.better-xcloud-settings-wrapper {
|
.better-xcloud-settings-wrapper {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
@ -1598,17 +1640,17 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 20px;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
padding: 20px;
|
padding: 16px;
|
||||||
width: 620px;
|
width: 600px;
|
||||||
background: #1a1b1e;
|
background: #1a1b1e;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 8px 8px 0 0;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 16px;
|
font-size: 14px;
|
||||||
font-family: Bahnschrift, Arial, Helvetica, sans-serif;
|
font-family: Bahnschrift, Arial, Helvetica, sans-serif;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
box-shadow: 0px 0px 6px #000;
|
box-shadow: 0px 0px 6px #000;
|
||||||
@ -1624,22 +1666,22 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.better-xcloud-quick-settings-bar label {
|
.better-xcloud-quick-settings-bar label {
|
||||||
font-size: 20px;
|
font-size: 16px;
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.better-xcloud-quick-settings-bar input {
|
.better-xcloud-quick-settings-bar input {
|
||||||
width: 24px;
|
width: 22px;
|
||||||
height: 24px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.better-xcloud-quick-settings-bar button {
|
.better-xcloud-quick-settings-bar button {
|
||||||
border: none;
|
border: none;
|
||||||
width: 24px;
|
width: 22px;
|
||||||
height: 24px;
|
height: 22px;
|
||||||
margin: 0 8px;
|
margin: 0 4px;
|
||||||
line-height: 24px;
|
line-height: 22px;
|
||||||
background-color: #515151;
|
background-color: #515151;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@ -2319,6 +2361,15 @@ function injectSettingsButton($parent) {
|
|||||||
function getVideoPlayerFilterStyle() {
|
function getVideoPlayerFilterStyle() {
|
||||||
const filters = [];
|
const filters = [];
|
||||||
|
|
||||||
|
const clarity = PREFS.get(Preferences.VIDEO_CLARITY);
|
||||||
|
if (clarity != 0) {
|
||||||
|
const level = 7 - (clarity - 1); // 5,6,7
|
||||||
|
const matrix = `0 -1 0 -1 ${level} -1 0 -1 0`;
|
||||||
|
document.getElementById('better-xcloud-filter-clarity-matrix').setAttributeNS(null, 'kernelMatrix', matrix);
|
||||||
|
|
||||||
|
filters.push(`url(#better-xcloud-filter-clarity)`);
|
||||||
|
}
|
||||||
|
|
||||||
const saturation = PREFS.get(Preferences.VIDEO_SATURATION);
|
const saturation = PREFS.get(Preferences.VIDEO_SATURATION);
|
||||||
if (saturation != 100) {
|
if (saturation != 100) {
|
||||||
filters.push(`saturate(${saturation}%)`);
|
filters.push(`saturate(${saturation}%)`);
|
||||||
@ -2341,8 +2392,22 @@ function getVideoPlayerFilterStyle() {
|
|||||||
function updateVideoPlayerCss() {
|
function updateVideoPlayerCss() {
|
||||||
let $elm = document.getElementById('better-xcloud-video-css');
|
let $elm = document.getElementById('better-xcloud-video-css');
|
||||||
if (!$elm) {
|
if (!$elm) {
|
||||||
$elm = createElement('style', {id: 'better-xcloud-video-css'});
|
const CE = createElement;
|
||||||
|
|
||||||
|
$elm = CE('style', {id: 'better-xcloud-video-css'});
|
||||||
document.documentElement.appendChild($elm);
|
document.documentElement.appendChild($elm);
|
||||||
|
|
||||||
|
// Setup SVG filters
|
||||||
|
const $svg = CE('svg', {
|
||||||
|
'id': 'better-xcloud-video-filters',
|
||||||
|
'xmlns': 'http://www.w3.org/2000/svg',
|
||||||
|
'class': 'better-xcloud-gone',
|
||||||
|
}, CE('defs', {'xmlns': 'http://www.w3.org/2000/svg'},
|
||||||
|
CE('filter', {'id': 'better-xcloud-filter-clarity', 'xmlns': 'http://www.w3.org/2000/svg'},
|
||||||
|
CE('feConvolveMatrix', {'id': 'better-xcloud-filter-clarity-matrix', 'order': '3', 'xmlns': 'http://www.w3.org/2000/svg'}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
document.documentElement.appendChild($svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let filters = getVideoPlayerFilterStyle();
|
let filters = getVideoPlayerFilterStyle();
|
||||||
@ -2632,20 +2697,31 @@ function patchRtcCodecs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function numberPicker(key) {
|
function numberPicker(key, suffix='', disabled=false) {
|
||||||
|
const setting = Preferences.SETTINGS[key]
|
||||||
let value = PREFS.get(key);
|
let value = PREFS.get(key);
|
||||||
|
|
||||||
let $text, $decBtn, $incBtn;
|
let $text, $decBtn, $incBtn;
|
||||||
|
|
||||||
const MIN = 0;
|
const MIN = setting.min;
|
||||||
const MAX= 150;
|
const MAX= setting.max;
|
||||||
|
|
||||||
const CE = createElement;
|
const CE = createElement;
|
||||||
const $wrapper = CE('div', {},
|
const $wrapper = CE('div', {},
|
||||||
$decBtn = CE('button', {'data-type': 'dec'}, '-'),
|
$decBtn = CE('button', {'data-type': 'dec'}, '-'),
|
||||||
$text = CE('span', {}, value + '%'),
|
$text = CE('span', {}, value + suffix),
|
||||||
$incBtn = CE('button', {'data-type': 'inc'}, '+'),
|
$incBtn = CE('button', {'data-type': 'inc'}, '+'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
$incBtn.disabled = true;
|
||||||
|
$incBtn.classList.add('better-xcloud-hidden');
|
||||||
|
|
||||||
|
$decBtn.disabled = true;
|
||||||
|
$decBtn.classList.add('better-xcloud-hidden');
|
||||||
|
return $wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
let interval;
|
let interval;
|
||||||
let isHolding = false;
|
let isHolding = false;
|
||||||
|
|
||||||
@ -2664,7 +2740,7 @@ function numberPicker(key) {
|
|||||||
value = (value >= MAX) ? MAX : value + 1;
|
value = (value >= MAX) ? MAX : value + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$text.textContent = value + '%';
|
$text.textContent = value + suffix;
|
||||||
PREFS.set(key, value);
|
PREFS.set(key, value);
|
||||||
updateVideoPlayerCss();
|
updateVideoPlayerCss();
|
||||||
|
|
||||||
@ -2705,21 +2781,25 @@ function numberPicker(key) {
|
|||||||
|
|
||||||
function setupVideoSettingsBar() {
|
function setupVideoSettingsBar() {
|
||||||
const CE = createElement;
|
const CE = createElement;
|
||||||
|
const isSafari = UserAgent.isSafari();
|
||||||
|
|
||||||
let $stretchInp;
|
let $stretchInp;
|
||||||
const $wrapper = CE('div', {'class': 'better-xcloud-quick-settings-bar'},
|
const $wrapper = CE('div', {'class': 'better-xcloud-quick-settings-bar'},
|
||||||
CE('div', {},
|
CE('div', {},
|
||||||
CE('label', {'for': 'better-xcloud-quick-setting-stretch'}, 'Stretch Video'),
|
CE('label', {'for': 'better-xcloud-quick-setting-stretch'}, 'Stretch Video'),
|
||||||
$stretchInp = CE('input', {'id': 'better-xcloud-quick-setting-stretch', 'type': 'checkbox'})),
|
$stretchInp = CE('input', {'id': 'better-xcloud-quick-setting-stretch', 'type': 'checkbox'})),
|
||||||
|
CE('div', {},
|
||||||
|
CE('label', {}, 'Clarity'),
|
||||||
|
numberPicker(Preferences.VIDEO_CLARITY, '', isSafari)), // disable this feature in Safari
|
||||||
CE('div', {},
|
CE('div', {},
|
||||||
CE('label', {}, 'Saturation'),
|
CE('label', {}, 'Saturation'),
|
||||||
numberPicker(Preferences.VIDEO_SATURATION)),
|
numberPicker(Preferences.VIDEO_SATURATION, '%')),
|
||||||
CE('div', {},
|
CE('div', {},
|
||||||
CE('label', {}, 'Contrast'),
|
CE('label', {}, 'Contrast'),
|
||||||
numberPicker(Preferences.VIDEO_CONTRAST)),
|
numberPicker(Preferences.VIDEO_CONTRAST, '%')),
|
||||||
CE('div', {},
|
CE('div', {},
|
||||||
CE('label', {}, 'Brightness'),
|
CE('label', {}, 'Brightness'),
|
||||||
numberPicker(Preferences.VIDEO_BRIGHTNESS))
|
numberPicker(Preferences.VIDEO_BRIGHTNESS, '%'))
|
||||||
);
|
);
|
||||||
|
|
||||||
$stretchInp.checked = PREFS.get(Preferences.VIDEO_FILL_FULL_SCREEN);
|
$stretchInp.checked = PREFS.get(Preferences.VIDEO_FILL_FULL_SCREEN);
|
||||||
@ -2943,7 +3023,7 @@ function disablePwa() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's Safari on mobile
|
// Check if it's Safari on mobile
|
||||||
if (userAgent.includes('mobile') && userAgent.includes('safari') && !userAgent.includes('chrom')) {
|
if (UserAgent.isSafari(true)) {
|
||||||
// Disable the PWA prompt
|
// Disable the PWA prompt
|
||||||
Object.defineProperty(window.navigator, 'standalone', {
|
Object.defineProperty(window.navigator, 'standalone', {
|
||||||
value: true,
|
value: true,
|
||||||
|
Reference in New Issue
Block a user