Moved userscripts to repo root.

Added client userscript in a "proof of concept" state of readiness.

The bot userscript is neat and tidy, it works very well too.

Added additional comments.
This commit is contained in:
Victor Westerlund 2021-02-05 16:05:46 +01:00
parent b586850c26
commit c90b64b671
5 changed files with 135 additions and 46 deletions

View file

@ -6,7 +6,7 @@
"host" => "", "host" => "",
"username" => "", "username" => "",
"password" => "", "password" => "",
"database" => "stadia_avatars" "database" => "stadia_avatars" // 'setup-db.sql' contains the db structure
]; ];
protected static $instance; protected static $instance;
@ -44,6 +44,7 @@
} }
// DB interface for manipulating Stadia Avatar
class StadiaAvatarDB extends DBConnector { class StadiaAvatarDB extends DBConnector {
public function __construct() { public function __construct() {
@ -64,6 +65,7 @@
return $this->sql->exec_query($SQL); return $this->sql->exec_query($SQL);
} }
// Return the value of column 'avatar'
public function get_avatar($user_id) { public function get_avatar($user_id) {
$SQL = "SELECT `userid`, `avatar` FROM `avatars` WHERE `userid` = '${user_id}'"; $SQL = "SELECT `userid`, `avatar` FROM `avatars` WHERE `userid` = '${user_id}'";
$query = $this->sql->exec_query($SQL); $query = $this->sql->exec_query($SQL);
@ -73,6 +75,7 @@
} }
} }
// Insert or update user avatar
public function set_avatar($user_id,$avatar) { public function set_avatar($user_id,$avatar) {
if(!$this->get_avatar($user_id)) { if(!$this->get_avatar($user_id)) {
http_response_code("201"); http_response_code("201");

View file

@ -1,10 +1,21 @@
// ==UserScript==
// @name Stadia Avatars - Bot
// @namespace https://victorwesterlund.com/
// @version 1.0
// @description https://github.com/VictorWesterlund/stadia-avatar
// @author VictorWesterlund
// @match https://stadia.google.com/*
// @grant none
// @noframes
// ==/UserScript==
(function() { (function() {
'use strict'; 'use strict';
/* The Stadia Service Worker "mgsw.js" acts like a proxy and rejects requests to the StadiaAvatar endpoint. /* The Stadia Service Worker "mgsw.js" acts like a proxy and rejects requests to the StadiaAvatar endpoint.
Enable the "Bypass for network" toggle in DevTools->Application->Service Workers to circumvent this issue. */ Enable the "Bypass for network" toggle in DevTools->Application->Service Workers to circumvent this issue. */
const endpoint = ""; const endpoint = "https://api.victorwesterlund.com/stadia-avatar/update";
const sharedSecret = ""; // Key to update the database const sharedSecret = ""; // Key to update the database
const className = { const className = {
@ -67,7 +78,7 @@
console.log("StadiaAvatar bot started."); console.log("StadiaAvatar bot started.");
}, },
stop: () => { stop: () => {
interval = null interval = null;
console.log("StadiaAvatar bot stopped."); console.log("StadiaAvatar bot stopped.");
} }
} }

118
userscript-client.js Normal file
View file

@ -0,0 +1,118 @@
// ==UserScript==
// @name Stadia Avatars
// @namespace https://victorwesterlund.com/
// @version 1.0
// @description victorWesterlund/stadia-avatar
// @author VictorWesterlund
// @match https://stadia.google.com/*
// @grant none
// @noframes
// ==/UserScript==
(function() {
'use strict';
const stadiaAvatar = new URL("https://api.victorwesterlund.com/stadia-avatar/get");
const gravatar = new URL("https://www.gravatar.com/");
/*
G: Suitable for display on all websites with any audience type.
PG: May contain rude gestures, provocatively dressed individuals, the lesser swear words, or mild violence.
R: May contain such things as harsh profanity, intense violence, nudity, or hard drug use.
X: May contain hardcore sexual imagery or extremely disturbing violence.
*/
gravatar.searchParams.set("rating","G");
// Stylesheet for Stadia Avatars
class StadiaAvatarCSS {
constructor() {
this.sheet = null;
this.createStylesheet();
}
createStylesheet() {
const style = document.createElement("style");
style.setAttribute("data-stadia-avatars","");
style.setAttribute("data-late-css","");
document.head.appendChild(style);
this.sheet = style.sheet;
}
// Serialized group of selectors based on context
selectors(group,id = false) {
switch(group) {
case "me": return ".ksZYgc, .rybUIf";
case "friends": return `.Y1rZWd[data-playerid="${id}"] .Fnd1Pd, .w2Sl7c[data-playerid="${id}"] .drvCDc`;
}
}
add(selectors,avatar) {
this.sheet.insertRule(`${selectors} { background-image: url(${avatar}) !important; }`);
console.log(`${selectors} { background-image: url(${avatar}) !important; }`);
}
}
const avatars = new StadiaAvatarCSS();
// ----
// Return the player ID attribute of an element
const getID = (target) => {
const id = target.getAttribute("data-player-id") ?? target.getAttribute("data-playerid");
return id;
}
async function getStadiaAvatar(playerID) {
stadiaAvatar.searchParams.set("userID",playerID);
const response = await fetch(stadiaAvatar);
return response.json();
}
// Fetch avatar and append to stylesheet
function replaceWithGravatar(group,playerID) {
getStadiaAvatar(playerID).then(response => {
gravatar.pathname = "/avatar/" + response.avatar; // Append Gravatar hash
avatars.add(avatars.selectors(group,playerID),gravatar); // Add style override by group
});
}
// ----
replaceWithGravatar("me",getID(document.querySelector("[jsname='HiaYvf']")));
function updateFamily(group,wrapper) {
for(const element of wrapper) {
const id = getID(element);
if(!id) {
continue;
}
replaceWithGravatar(group,id);
}
}
let timeout = null;
const friendsList = (mutation,observer) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
const friends = document.querySelector("[jsname='FhFdCc']").children;
const messages = document.querySelector("[jsname='FhFdCc']").children;
updateFamily("friends",messages);
},700);
}
const friendsMenu = document.querySelector("[jsname='TpfyL']");
const friends = new MutationObserver(friendsList);
friends.observe(friendsMenu,{
childList: true,
subtree: true
});
})();

View file

@ -1,11 +0,0 @@
// ==UserScript==
// @name Stadia Avatars
// @namespace https://victorwesterlund.com/
// @version 0.1
// @description try to take over the world!
// @author VictorWesterlund
// @match https://stadia.google.com/*
// @grant none
// @require file://C:\path\to\userscript.user.js
// @noframes
// ==/UserScript==

View file

@ -1,32 +0,0 @@
(function() {
'use strict';
function getElementByJSname(name) {
return document.querySelector(`[jsname="${name}"]`);
}
const myID = () => {
let element = getElementByJSname("HiaYvf");
return element.getAttribute("data-player-id");
}
function locationChanged() {
switch(window.location.pathname) {
case "/home": console.log("home"); break;
case "/settings": console.log("settings"); break;
default: break;
}
}
let currentLocation = window.location.href;
// Poll window.location.href for changes
let poll = setInterval(() => {
if(window.location.href != currentLocation) {
currentLocation = window.location.href;
locationChanged();
}
},500);
locationChanged();
})();