mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-29 10:51:44 +02:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
2569e73018 | |||
4c790ac38d | |||
11c233e14e | |||
a81cb86140 | |||
c3de245545 | |||
a7ab506f0f | |||
8ecff6adae | |||
27ec45512d | |||
3a654b99cb | |||
a009cca866 | |||
19302ea444 | |||
3c4248c1c7 | |||
de834fcb80 | |||
baf2c2a35d | |||
522830a47d |
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Platform (please complete the following information):**
|
||||
- OS: [e.g. Android]
|
||||
- Browser: [e.g. chrome, firefox]
|
||||
- Browser Version: [e.g. 100]
|
||||
- Better xCloud Version: [e.g. 1.4]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[Feature]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
56
README.md
56
README.md
@ -6,12 +6,12 @@ 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/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">
|
||||
<img width="475" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/ad687344-214d-4822-affe-21f1b1e105c8">
|
||||
<img width="475" 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 the [**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.
|
||||
@ -22,12 +22,12 @@ Give this project a 🌟 if you like it. Thank you 🙏.
|
||||
> 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
|
||||
- **Disable bandwidth checking**
|
||||
> xCloud won't reduce quality when the internet speed is slow
|
||||
- **🔥 Capture screenshot**
|
||||
> Exclusive to **Better xCloud**. Check the [**Capture screenshot** section](#capture-screenshot) for more info.
|
||||
- **Skip Xbox splash video**
|
||||
> Save 3 seconds
|
||||
- **Hide Dots icon while playing**
|
||||
@ -51,7 +51,7 @@ Give this project a 🌟 if you like it. 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.
|
||||
|
||||
## How to use
|
||||
1. Install [Tampermonkey extension](https://www.tampermonkey.net/) on suppported browsers. It's also available for Firefox on Android.
|
||||
1. Install [Tampermonkey extension](https://www.tampermonkey.net/) on suppported browsers.
|
||||
2. Install **Better xCloud**:
|
||||
- [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)
|
||||
@ -65,22 +65,44 @@ 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
|
||||
➖ = unavailable
|
||||
⚠️ = see custom notes
|
||||
| | Desktop | Android | iOS |
|
||||
|----------------------------------------|------------------|------------------|------------------|
|
||||
| Chrome/Edge/Chromium variants | ✅ | ❌ | ❌ |
|
||||
| Firefox | ✅ | ✅<sup>(1)</sup> | ❌ |
|
||||
| Safari | ✅<sup>(2)</sup> | ➖ | ✅<sup>(3)</sup> |
|
||||
| [Hermit](https://hermit.chimbori.com) | ➖ | ⚠️<sup>(4)</sup> | ➖ |
|
||||
| Kiwi Browser | ➖ | ✅<sup>(5)</sup> | ➖ |
|
||||
| | Desktop | Android/Android TV | iOS |
|
||||
|-----------------------------------------|:-----------------|:-------------------|:----------------|
|
||||
| Chrome/Edge/Chromium variants | ✅ | ❌ | ❌ |
|
||||
| Firefox | ✅ | ⚠️<sup>(1)</sup> | ❌ |
|
||||
| Safari | ✅<sup>(2)</sup> | ➖ | ✅<sup>(3)</sup> |
|
||||
| [Hermit](https://hermit.chimbori.com) | ➖ | ⚠️<sup>(4)</sup> | ➖ |
|
||||
| [Kiwi Browser](https://kiwibrowser.com) | ➖ | ✅ | ➖ |
|
||||
|
||||
Don't see your browser in the table? If it supports Tampermonkey/Userscript then the answer is likely **"YES"**.
|
||||
|
||||
<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>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. Its Gamepad API doesn't work properly so it might not recognize your controller.
|
||||
<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).
|
||||
<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).
|
||||
|
||||
---
|
||||
- **Kiwi Browser** is the best choice on Android. All features work, it means you can get 1080p stream + high quality codec profile (the best possible quality).
|
||||
- **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.
|
||||
|
||||
## Capture screenshot
|
||||
- This feature is only available in **Better xCloud**.
|
||||
- Works on both desktop & mobile, but it's designed for mobile users.
|
||||
- It captures the current frame of the stream and save to a file. That means you won't get the raw quality like when you play on console, but it's still better than using the built-in screenshot feature on your phone.
|
||||
- Screenshot's resolution & quality depend on the quality of the stream at the moment.
|
||||
- Screenshot doesn't touch UI, notification bar... only the gameplay.
|
||||
- There might be a slight delay.
|
||||
|
||||
### How to capture screenshot
|
||||
1. Enable this feature in setting.
|
||||
2. Play a game.
|
||||
3. Tap once at the bottom left/right (depend on your setting) to show the Screenshot button.
|
||||
4. Tap on that button to capture screenshot.
|
||||
5. Screenshot will be saved by browser.
|
||||
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
|
||||
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.
|
||||
|
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 1.4.1
|
||||
// @version 1.5
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -13,15 +13,17 @@
|
||||
// ==/UserScript==
|
||||
'use strict';
|
||||
|
||||
const SCRIPT_VERSION = '1.4.1';
|
||||
const SCRIPT_VERSION = '1.5';
|
||||
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
||||
|
||||
const SERVER_REGIONS = {};
|
||||
|
||||
var $STREAM_VIDEO;
|
||||
var $SCREENSHOT_CANVAS;
|
||||
var GAME_TITLE_ID;
|
||||
|
||||
class StreamStatus {
|
||||
static ipv6 = false;
|
||||
static dimension = {width: 0, height: 0};
|
||||
static resolution = {width: 0, height: 0};
|
||||
static hqCodec = false;
|
||||
static region = '';
|
||||
|
||||
@ -39,7 +41,7 @@ class StreamStatus {
|
||||
['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'],
|
||||
['resolution', `${StreamStatus.resolution.width}x${StreamStatus.resolution.height}`, '#ff3977'],
|
||||
];
|
||||
|
||||
const $wrapper = createElement('div', {'class': 'better_xcloud_badges'});
|
||||
@ -56,6 +58,7 @@ class Preferences {
|
||||
static get FORCE_1080P_STREAM() { return 'force_1080p_stream'; }
|
||||
static get USE_DESKTOP_CODEC() { return 'use_desktop_codec'; }
|
||||
|
||||
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'; }
|
||||
static get DISABLE_BANDWIDTH_CHECKING() { return 'disable_bandwidth_checking'; }
|
||||
@ -73,88 +76,71 @@ class Preferences {
|
||||
'id': Preferences.SERVER_REGION,
|
||||
'label': 'Region of streaming server',
|
||||
'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.DISABLE_BANDWIDTH_CHECKING,
|
||||
'label': 'Disable bandwidth checking',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.SCREENSHOT_BUTTON_POSITION,
|
||||
'label': 'Screenshot button\'s position',
|
||||
'default': 'bottom-left',
|
||||
'options': {
|
||||
'bottom-left': 'Bottom Left',
|
||||
'bottom-right': 'Bottom Right',
|
||||
'none': 'Disable',
|
||||
},
|
||||
}, {
|
||||
'id': Preferences.SKIP_SPLASH_VIDEO,
|
||||
'label': 'Skip Xbox splash video',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.HIDE_DOTS_ICON,
|
||||
'label': 'Hide Dots icon while playing',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.REDUCE_ANIMATIONS,
|
||||
'label': 'Reduce UI animations',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.BLOCK_SOCIAL_FEATURES,
|
||||
'label': 'Disable social features',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.BLOCK_TRACKING,
|
||||
'label': 'Disable xCloud analytics',
|
||||
'default': false,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.VIDEO_FILL_FULL_SCREEN,
|
||||
'label': 'Stretch video to full screen',
|
||||
'default': false,
|
||||
'hidden': true,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.VIDEO_SATURATION,
|
||||
'label': 'Video saturation (%)',
|
||||
'default': 100,
|
||||
'min': 0,
|
||||
'max': 150,
|
||||
'hidden': true,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.VIDEO_CONTRAST,
|
||||
'label': 'Video contrast (%)',
|
||||
'default': 100,
|
||||
'min': 0,
|
||||
'max': 150,
|
||||
'hidden': true,
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
'id': Preferences.VIDEO_BRIGHTNESS,
|
||||
'label': 'Video brightness (%)',
|
||||
'default': 100,
|
||||
@ -363,6 +349,37 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.better_xcloud_screenshot_button {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
padding: 5px;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content-box;
|
||||
filter: drop-shadow(0 0 2px #000000B0);
|
||||
transition: opacity 0.1s ease-in-out 0s, padding 0.1s ease-in 0s;
|
||||
z-index: 8888;
|
||||
|
||||
/* Credit: https://www.iconfinder.com/iconsets/user-interface-outline-27 */
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCIgeG1sbnM6dj0iaHR0cHM6Ly92ZWN0YS5pby9uYW5vIiBmaWxsPSIjZmZmIj48cGF0aCBkPSJNMTIgN2E1LjAyIDUuMDIgMCAwIDAtNSA1IDUuMDIgNS4wMiAwIDAgMCA1IDUgNS4wMiA1LjAyIDAgMCAwIDUtNSA1LjAyIDUuMDIgMCAwIDAtNS01em0wIDJjMS42NjkgMCAzIDEuMzMxIDMgM3MtMS4zMzEgMy0zIDMtMy0xLjMzMS0zLTMgMS4zMzEtMyAzLTN6TTYgMkMzLjgwMSAyIDIgMy44MDEgMiA2djJhMSAxIDAgMSAwIDIgMFY2YTEuOTcgMS45NyAwIDAgMSAyLTJoMmExIDEgMCAxIDAgMC0yek0zIDE1YTEgMSAwIDAgMC0xIDF2MmMwIDIuMTk5IDEuODAxIDQgNCA0aDJhMSAxIDAgMSAwIDAtMkg2YTEuOTcgMS45NyAwIDAgMS0yLTJ2LTJhMSAxIDAgMCAwLTEtMXptMTggMGExIDEgMCAwIDAtMSAxdjJhMS45NyAxLjk3IDAgMCAxLTIgMmgtMmExIDEgMCAxIDAgMCAyaDJjMi4xOTkgMCA0LTEuODAxIDQtNHYtMmExIDEgMCAwIDAtMS0xeiIvPjxwYXRoIGQ9Ik0xNiAyYTEgMSAwIDEgMCAwIDJoMmExLjk3IDEuOTcgMCAwIDEgMiAydjJhMSAxIDAgMSAwIDIgMFY2YzAtMi4xOTktMS44MDEtNC00LTR6Ii8+PC9zdmc+Cg==);
|
||||
}
|
||||
|
||||
.better_xcloud_screenshot_button[data-showing=true] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.better_xcloud_screenshot_button[data-capturing=true] {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.better_xcloud_screenshot_canvas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide UI elements */
|
||||
#headerArea, #uhfSkipToMain, .uhf-footer {
|
||||
display: none;
|
||||
@ -720,27 +737,41 @@ function injectSettingsButton($parent) {
|
||||
|
||||
let $control;
|
||||
let labelAttrs = {};
|
||||
if (setting.id === Preferences.SERVER_REGION) {
|
||||
if (setting.id === Preferences.SERVER_REGION || setting.options) {
|
||||
let selectedValue;
|
||||
|
||||
$control = CE('select', {id: 'xcloud_setting_' + setting.id});
|
||||
$control.addEventListener('change', e => {
|
||||
PREFS.set(Preferences.SERVER_REGION, e.target.value);
|
||||
PREFS.set(setting.id, e.target.value);
|
||||
});
|
||||
|
||||
for (let regionName in SERVER_REGIONS) {
|
||||
const region = SERVER_REGIONS[regionName];
|
||||
let value = regionName;
|
||||
if (setting.id === Preferences.SERVER_REGION) {
|
||||
selectedValue = preferredRegion;
|
||||
setting.options = {};
|
||||
for (let regionName in SERVER_REGIONS) {
|
||||
const region = SERVER_REGIONS[regionName];
|
||||
let value = regionName;
|
||||
|
||||
let label = regionName;
|
||||
if (region.isDefault) {
|
||||
label += ' (Default)';
|
||||
value = 'default';
|
||||
let label = regionName;
|
||||
if (region.isDefault) {
|
||||
label += ' (Default)';
|
||||
value = 'default';
|
||||
}
|
||||
|
||||
setting.options[value] = label;
|
||||
}
|
||||
} else {
|
||||
selectedValue = PREFS.get(setting.id);
|
||||
}
|
||||
|
||||
for (let value in setting.options) {
|
||||
const label = setting.options[value];
|
||||
|
||||
const $option = CE('option', {value: value}, label);
|
||||
$option.selected = regionName === preferredRegion;
|
||||
|
||||
$option.selected = value === selectedValue || label.includes(selectedValue);
|
||||
$control.appendChild($option);
|
||||
}
|
||||
|
||||
} else {
|
||||
$control = CE('input', {
|
||||
id: 'xcloud_setting_' + setting.id,
|
||||
@ -972,6 +1003,7 @@ function injectVideoSettingsButton() {
|
||||
|
||||
function patchVideoApi() {
|
||||
const PREF_SKIP_SPLASH_VIDEO = PREFS.get(Preferences.SKIP_SPLASH_VIDEO);
|
||||
const PREF_SCREENSHOT_BUTTON_POSITION = PREFS.get(Preferences.SCREENSHOT_BUTTON_POSITION);
|
||||
|
||||
// Show video player when it's ready
|
||||
var showFunc;
|
||||
@ -980,7 +1012,23 @@ function patchVideoApi() {
|
||||
this.removeEventListener('playing', showFunc);
|
||||
|
||||
if (this.videoWidth) {
|
||||
StreamStatus.dimension = {width: this.videoWidth, height: this.videoHeight};
|
||||
$STREAM_VIDEO = this;
|
||||
$SCREENSHOT_CANVAS.width = this.videoWidth;
|
||||
$SCREENSHOT_CANVAS.height = this.videoHeight;
|
||||
StreamStatus.resolution = {width: this.videoWidth, height: this.videoHeight};
|
||||
|
||||
if (PREF_SCREENSHOT_BUTTON_POSITION !== 'none') {
|
||||
const $btn = document.querySelector('.better_xcloud_screenshot_button');
|
||||
$btn.style.display = 'block';
|
||||
|
||||
if (PREF_SCREENSHOT_BUTTON_POSITION === 'bottom-right') {
|
||||
$btn.style.right = '0';
|
||||
} else {
|
||||
$btn.style.left = '0';
|
||||
}
|
||||
}
|
||||
|
||||
GAME_TITLE_ID = /\/launch\/([^/]+)/.exec(window.location.pathname)[1];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1021,36 +1069,23 @@ function patchRtcCodecs() {
|
||||
RTCRtpTransceiver.prototype.orgSetCodecPreferences = RTCRtpTransceiver.prototype.setCodecPreferences;
|
||||
RTCRtpTransceiver.prototype.setCodecPreferences = function(codecs) {
|
||||
// Use the same codecs as desktop
|
||||
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;
|
||||
const newCodecs = codecs.slice();
|
||||
let pos = 0;
|
||||
newCodecs.forEach((codec, i) => {
|
||||
// Find high quality codecs
|
||||
if (codec.sdpFmtpLine && codec.sdpFmtpLine.includes('profile-level-id=4d')) {
|
||||
// Move it to the top of the array
|
||||
newCodecs.splice(i, 1);
|
||||
newCodecs.splice(pos, 0, codec);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
this.orgSetCodecPreferences.apply(this, [newCodecs]);
|
||||
} catch (e) {
|
||||
this.orgSetCodecPreferences(codecs);
|
||||
console.log(e);
|
||||
this.orgSetCodecPreferences.apply(this, [codecs]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1227,6 +1262,75 @@ function setupVideoSettingsBar() {
|
||||
}
|
||||
|
||||
|
||||
function setupScreenshotButton() {
|
||||
$SCREENSHOT_CANVAS = createElement('canvas', {'class': 'better_xcloud_screenshot_canvas'});
|
||||
document.documentElement.appendChild($SCREENSHOT_CANVAS);
|
||||
|
||||
const $canvasContext = $SCREENSHOT_CANVAS.getContext('2d');
|
||||
|
||||
const delay = 2000;
|
||||
const $btn = createElement('div', {'class': 'better_xcloud_screenshot_button', 'data-showing': false});
|
||||
|
||||
let timeout;
|
||||
const detectDbClick = e => {
|
||||
if (!$STREAM_VIDEO) {
|
||||
timeout = null;
|
||||
$btn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
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);
|
||||
|
||||
// Hide button
|
||||
$btn.setAttribute('data-showing', 'false');
|
||||
setTimeout(() => {
|
||||
if (!timeout) {
|
||||
$btn.setAttribute('data-capturing', 'false');
|
||||
}
|
||||
}, 100);
|
||||
}, 'image/png');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const isShowing = $btn.getAttribute('data-showing') === 'true';
|
||||
if (!isShowing) {
|
||||
// Show button
|
||||
$btn.setAttribute('data-showing', 'true');
|
||||
$btn.setAttribute('data-capturing', 'false');
|
||||
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null;
|
||||
$btn.setAttribute('data-showing', 'false');
|
||||
$btn.setAttribute('data-capturing', 'false');
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
$btn.addEventListener('mousedown', detectDbClick);
|
||||
document.documentElement.appendChild($btn);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function patchHistoryMethod(type) {
|
||||
var orig = window.history[type];
|
||||
return function(...args) {
|
||||
@ -1249,6 +1353,9 @@ function hideUiOnPageChange() {
|
||||
if ($quickBar) {
|
||||
$quickBar.style.display = 'none';
|
||||
}
|
||||
|
||||
$STREAM_VIDEO = null;
|
||||
document.querySelector('.better_xcloud_screenshot_button').style = '';
|
||||
}
|
||||
|
||||
|
||||
@ -1270,15 +1377,14 @@ if (PREFS.get(Preferences.DISABLE_BANDWIDTH_CHECKING)) {
|
||||
}
|
||||
|
||||
patchRtcCodecs();
|
||||
|
||||
interceptHttpRequests();
|
||||
|
||||
patchVideoApi();
|
||||
|
||||
// Setup UI
|
||||
addCss();
|
||||
updateVideoPlayerCss();
|
||||
setupVideoSettingsBar();
|
||||
setupScreenshotButton();
|
||||
|
||||
// Workaround for Hermit browser
|
||||
var onLoadTriggered = false;
|
||||
|
Reference in New Issue
Block a user