This repository has been archived by the owner on May 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e9c232c
Showing
23 changed files
with
778 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Stadia+ | ||
Stadia+ is a chrome extension for Google's Stadia platform. It is designed to improve and extend Stadia's features and upgrade existing ones. | ||
|
||
## Installation | ||
Stadia+ is not yet available on the Chrome Web Store, at the moment you will need to install it through developer mode. | ||
1. Go to `chrome://extensions` in your Chrome browser. | ||
2. Press the switch in the top right corner to enable "developer mode". | ||
3. Download any of the releases available on Github as a zip file. | ||
4. Drag the zip file anywhere into the extension window. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
chrome.runtime.onInstalled.addListener(function () { | ||
chrome.declarativeContent.onPageChanged.removeRules(undefined, function () { | ||
chrome.declarativeContent.onPageChanged.addRules([{ | ||
conditions: [new chrome.declarativeContent.PageStateMatcher({ | ||
pageUrl: { hostEquals: 'stadia.google.com' }, | ||
}) | ||
], | ||
actions: [ | ||
new chrome.declarativeContent.ShowPageAction() | ||
] | ||
}]); | ||
}); | ||
}) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
console.log("[STADIA+] Injecting Clock"); | ||
|
||
window.addEventListener("load", () => { | ||
setInterval(() => { | ||
let container = document.querySelector(".hxhAyf"); | ||
let clock = document.querySelector("#sidebar_clock"); | ||
if(clock) { | ||
clock.innerHTML = new Date().toLocaleTimeString(); | ||
return; | ||
} | ||
if(!container) { | ||
return; | ||
} | ||
let el = document.createElement("span"); | ||
el.id = "sidebar_clock"; | ||
el.innerHTML = new Date().toLocaleTimeString(); | ||
el.classList.add("stadiaplus_clock"); | ||
container.prepend(el); | ||
}, 1000); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
console.log("[STADIA+] Injecting Filters"); | ||
|
||
let gameStorage = {}; | ||
let sunStorage = false; | ||
let sortStorage = "played"; | ||
let recentlyPlayed = []; | ||
|
||
if(window.location.href.includes("/home")) { | ||
window.addEventListener("load", () => { | ||
//chrome.storage.local.clear(); | ||
let elements = document.querySelectorAll(".GqLi4d"); | ||
for(let el of elements) { | ||
recentlyPlayed.push(el); | ||
} | ||
|
||
injectImages(); | ||
injectFilterBar(); | ||
setInterval(createImages, 500); | ||
setInterval(injectFilterBar, 100) | ||
updateStorage(); | ||
}) | ||
} | ||
|
||
function updateStorage(callback) { | ||
chrome.storage.local.get(['games', 'sun', 'order'], function(result) { | ||
let resStorage = result["games"]; | ||
if(!resStorage) resStorage = {}; | ||
|
||
sunStorage = result.sun; | ||
orderStorage = result.order; | ||
|
||
let sun = document.querySelector(".stadiaplus_icon_sun"); | ||
if(sun) sun.classList.remove("enabled"); | ||
|
||
let order = document.querySelector(".stadiaplus_filterbar>.order-dropdown>#dropdown"); | ||
if(order) order.value = orderStorage; | ||
|
||
if(sunStorage) sun.classList.add("enabled"); | ||
|
||
for(let element of document.querySelectorAll(".GqLi4d.QAAyWd")) { | ||
let game; | ||
let name = element.getAttribute("aria-label"); | ||
|
||
if(resStorage.hasOwnProperty(name)) { | ||
game = resStorage[name]; | ||
} | ||
else { | ||
game = { | ||
visible: element.style["display"] != "none" | ||
}; | ||
} | ||
|
||
gameStorage[name] = game; | ||
updateGame(name); | ||
} | ||
if(callback) { | ||
callback(); | ||
} | ||
saveStorage(); | ||
}); | ||
} | ||
|
||
function saveStorage(callback) { | ||
chrome.storage.local.set({'games': gameStorage, 'sun': sunStorage, 'order': orderStorage}, callback); | ||
} | ||
|
||
function updateGame(name) { | ||
let tile = getTile(name); | ||
let sun = document.querySelector(".stadiaplus_filterbar>.stadiaplus_icon_sun"); | ||
|
||
if(sun.classList.contains("enabled")) { | ||
tile.style["display"] = ""; | ||
} | ||
else { | ||
tile.style["display"] = getFromStorage(name).visible ? "" : "none"; | ||
} | ||
} | ||
|
||
function injectImages() { | ||
if(!document.querySelector(".stadiaplus_game")) { | ||
//createImages(); | ||
updateStorage(); | ||
} | ||
|
||
setTimeout(injectImages, 100); | ||
} | ||
|
||
function getFromStorage(name) { | ||
return gameStorage[name]; | ||
} | ||
|
||
function getTile(name) { | ||
for(let g of document.querySelectorAll(".GqLi4d.QAAyWd")) { | ||
if(g.getAttribute("aria-label") == name) { | ||
return g; | ||
} | ||
} | ||
} | ||
|
||
function createImages() { | ||
let gameTiles = document.querySelectorAll(".GqLi4d"); | ||
|
||
let eyes = document.querySelectorAll(".stadiaplus_icon_visibility"); | ||
for(let e of eyes) { | ||
e.remove(); | ||
} | ||
|
||
|
||
gameTiles.forEach(element => { | ||
if(element.style["display"] == "none") return; | ||
|
||
let game = getFromStorage(element.getAttribute("aria-label")); | ||
if(game == null) { | ||
game = { | ||
visible: true | ||
}; | ||
} | ||
|
||
|
||
let eye = document.createElement("img"); | ||
|
||
if(game.visible) { | ||
eye.src = chrome.runtime.getURL("images/icons/visibility.svg"); | ||
} | ||
else { | ||
eye.src = chrome.runtime.getURL("images/icons/visibility_off.svg"); | ||
} | ||
|
||
eye.classList.add("stadiaplus_icon_visibility"); | ||
element.classList.add("stadiaplus_game"); | ||
|
||
element.parentElement.insertBefore(eye, element); | ||
|
||
eye.style["left"] = (element.offsetLeft+element.clientWidth) + "px"; | ||
eye.style["top"] = (element.offsetTop+element.clientHeight) + "px"; | ||
|
||
eye.addEventListener("click", (event) => { | ||
let tile = element; | ||
//tile.style["display"] = tile.style["display"] == "none" ? "" : "none"; | ||
|
||
let name = element.getAttribute("aria-label") | ||
let game = getFromStorage(name); | ||
game.visible = !game.visible; | ||
|
||
gameStorage[name] = game; | ||
saveStorage(()=>{updateStorage(createImages)}); | ||
}); | ||
}); | ||
} | ||
|
||
function injectFilterBar() { | ||
if(!document.querySelector(".stadiaplus_filterbar")) { | ||
let html = ` | ||
<div class="stadiaplus_filterbar"> | ||
<img class="stadiaplus_icon_filter" src="${chrome.runtime.getURL("images/icons/filter.svg")}"> | ||
<div class="order-dropdown"> | ||
<select name="order" id="dropdown"> | ||
<p>order</p> | ||
<option value="played">Recently Played</option> | ||
<option value="alphabetical">A-Z</option> | ||
<option value="bought" disabled>Recently Bought</option> | ||
<option value="random">Random</option> | ||
</select> | ||
</div> | ||
<img class="stadiaplus_icon_sun" src="${chrome.runtime.getURL("images/icons/sun.svg")}"> | ||
</div> | ||
` | ||
|
||
let container = document.querySelector(".CVVXfc.YYy3Zb"); | ||
let el = document.createElement("div"); | ||
el.innerHTML = html; | ||
container.appendChild(el); | ||
|
||
new SlimSelect({ | ||
select: '.order-dropdown>#dropdown', | ||
showSearch: false | ||
}); | ||
|
||
addFilterBarEvents(); | ||
sortGames(); | ||
} | ||
} | ||
|
||
function addFilterBarEvents() { | ||
let orderDropdown = document.querySelector(".stadiaplus_filterbar>.order-dropdown>#dropdown"); | ||
orderDropdown.addEventListener("change", (event) => { | ||
orderStorage = orderDropdown.value; | ||
saveStorage(); | ||
sortGames(); | ||
}); | ||
|
||
|
||
let sun = document.querySelector(".stadiaplus_filterbar>.stadiaplus_icon_sun"); | ||
sun.addEventListener("click", (event) => { | ||
sun.classList.toggle("enabled"); | ||
sunStorage = !sunStorage; | ||
saveStorage(); | ||
updateStorage(); | ||
}) | ||
} | ||
|
||
function sortGames() { | ||
let orderDropdown = document.querySelector(".stadiaplus_filterbar>.order-dropdown>#dropdown"); | ||
switch(orderDropdown.value) { | ||
case "alphabetical": | ||
sortAlphabetical(); | ||
break; | ||
case "played": | ||
sortRecentlyPlayed(); | ||
break; | ||
case "random": | ||
sortRandom(); | ||
break; | ||
} | ||
} | ||
|
||
function sortAlphabetical() { | ||
let elements = document.querySelectorAll(".GqLi4d"); | ||
let arr = []; | ||
let parent = elements[0].parentElement; | ||
for(let el of elements) { | ||
arr.push(el); | ||
el.remove(); | ||
} | ||
|
||
arr.sort(function(a, b) { | ||
return a.getAttribute("aria-label") < b.getAttribute("aria-label") ? -1 : 1; | ||
}); | ||
|
||
for(let el of arr) { | ||
parent.appendChild(el); | ||
} | ||
} | ||
|
||
|
||
function sortRandom() { | ||
let elements = document.querySelectorAll(".GqLi4d"); | ||
let arr = []; | ||
let parent = elements[0].parentElement; | ||
for(let el of elements) { | ||
arr.push(el); | ||
el.remove(); | ||
} | ||
|
||
arr.sort(function(a, b) { | ||
return Math.sign(Math.random() - 0.5); | ||
}); | ||
|
||
for(let el of arr) { | ||
parent.appendChild(el); | ||
} | ||
} | ||
|
||
function sortRecentlyPlayed() { | ||
let elements = document.querySelectorAll(".GqLi4d"); | ||
let parent = elements[0].parentElement; | ||
for(let el of elements) { | ||
el.remove(); | ||
} | ||
|
||
for(let el of recentlyPlayed) { | ||
parent.appendChild(el); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
console.log("[STADIA+] Injecting Network Listener"); | ||
|
||
// @version 0.3 | ||
// @author AquaRegia | ||
|
||
function createRTCOverride() { | ||
const url = chrome.runtime.getURL('monitorScript.js'); | ||
|
||
let element = document.createElement("script"); | ||
element.innerHTML = httpGet(url); | ||
document.body.appendChild(element); | ||
} | ||
|
||
document.addEventListener("DOMContentLoaded", function() { | ||
createRTCOverride(); | ||
}); | ||
|
||
function httpGet(theUrl) { | ||
var xmlHttp = new XMLHttpRequest(); | ||
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request | ||
xmlHttp.send( null ); | ||
return xmlHttp.responseText; | ||
} |
Oops, something went wrong.