mirror of
https://codeberg.org/vlw/stadia-avatar.git
synced 2025-09-13 23:23:40 +02:00
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:
parent
b586850c26
commit
c90b64b671
5 changed files with 135 additions and 46 deletions
|
@ -6,7 +6,7 @@
|
|||
"host" => "",
|
||||
"username" => "",
|
||||
"password" => "",
|
||||
"database" => "stadia_avatars"
|
||||
"database" => "stadia_avatars" // 'setup-db.sql' contains the db structure
|
||||
];
|
||||
|
||||
protected static $instance;
|
||||
|
@ -44,6 +44,7 @@
|
|||
|
||||
}
|
||||
|
||||
// DB interface for manipulating Stadia Avatar
|
||||
class StadiaAvatarDB extends DBConnector {
|
||||
|
||||
public function __construct() {
|
||||
|
@ -64,6 +65,7 @@
|
|||
return $this->sql->exec_query($SQL);
|
||||
}
|
||||
|
||||
// Return the value of column 'avatar'
|
||||
public function get_avatar($user_id) {
|
||||
$SQL = "SELECT `userid`, `avatar` FROM `avatars` WHERE `userid` = '${user_id}'";
|
||||
$query = $this->sql->exec_query($SQL);
|
||||
|
@ -73,6 +75,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Insert or update user avatar
|
||||
public function set_avatar($user_id,$avatar) {
|
||||
if(!$this->get_avatar($user_id)) {
|
||||
http_response_code("201");
|
||||
|
|
|
@ -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() {
|
||||
'use strict';
|
||||
|
||||
/* 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. */
|
||||
|
||||
const endpoint = "";
|
||||
const endpoint = "https://api.victorwesterlund.com/stadia-avatar/update";
|
||||
const sharedSecret = ""; // Key to update the database
|
||||
|
||||
const className = {
|
||||
|
@ -67,7 +78,7 @@
|
|||
console.log("StadiaAvatar bot started.");
|
||||
},
|
||||
stop: () => {
|
||||
interval = null
|
||||
interval = null;
|
||||
console.log("StadiaAvatar bot stopped.");
|
||||
}
|
||||
}
|
118
userscript-client.js
Normal file
118
userscript-client.js
Normal 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
|
||||
});
|
||||
|
||||
})();
|
|
@ -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==
|
|
@ -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();
|
||||
})();
|
Loading…
Add table
Reference in a new issue