// ==UserScript==
// @name HoldBoost Tweaks
// @namespace http://tampermonkey.net/
// @version 0.2.14
// @description fix holdboost styles and add feature tweaks
// @author Californ1a
// @match http://holdboost.com/*
// @match https://holdboost.com/*
// @match http://*.holdboost.com/*
// @match https://*.holdboost.com/*
// ==/UserScript==
(async function() {
const css = `
/* Levels */
#pills-tab {
flex-wrap: nowrap;
align-items: center;
}
.level-medal-times {
flex: 1 1 5vw;
max-width: 100%;
min-width: 150px;
margin: 0 max(0.5vw,18px) 1vw max(0.5vw,16px) !important;
padding: 0.25vw !important;
}
#pills-sightings > div,
#pills-improvements > div,
#pills-info > div {
max-height: calc(100vh - 27.7rem);
overflow-y: auto;
}
.sticky-headers thead th {
z-index: 1;
}
table tbody tr td.entry-img {
vertical-align: middle;
}
body {
background-position: center;
}
th.text-left {
text-align: center !important;
}
#pills-tab .nav-item {
flex: 1;
align-self: stretch;
}
.nav-pills .nav-link {
background-color: #00000033;
margin: 0 0.2vw 0 0.2vw;
height: 100%;
}
.nav-pills .nav-link:not(.active):hover {
background-color: #00000044;
}
.nav-pills:first-child .nav-link {
margin-left: 0;
}
.nav-pills:last-child .nav-link {
margin-right: 0;
}
.col-3.offset-1 .nav-pills .nav-item:first-child a:not(#pills-recent-activity-tab) {
/*line-height: 3.06rem;*/
padding: 1.25rem;
}
thead th {
position: sticky;
top: -2px;
background-color: #212529;
}
#levelsPlaceholder + #levels > .text-left {
position: sticky;
top: -20px;
z-index: 10;
background-color: #222222;
}
@keyframes custom-fade {
0% {color: yellow;}
50% {color: yellow;}
100% {color: white;}
}
.fade-in-custom {
animation: custom-fade 1s ease-out;
}
h5 a {
color: white;
}
h5 a:hover {
color: #eee;
}
#customAvatar {
max-height: 40px;
margin-right: 5px;
}
#customRank {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.col-4 table:nth-child(5) {
table-layout: fixed;
}
.col-4 table:nth-child(5) td.no-wrap:not(.entry-img) {
padding-left: 4px;
padding-right: 4px;
}
.col-4 table:nth-child(5) td:nth-child(2) div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
div.col-4.col-xl-12 > h2 > a:nth-child(2) {
padding-left: 10px;
color: inherit;
text-decoration: none;
}
`.split("\n").filter((e) => e !== "").join("\n");
if (typeof GM_addStyle != "undefined") {
GM_addStyle(css);
} else if (typeof PRO_addStyle != "undefined") {
PRO_addStyle(css);
} else if (typeof addStyle != "undefined") {
addStyle(css);
} else {
var node = document.createElement("style");
node.type = "text/css";
node.appendChild(document.createTextNode(css));
var heads = document.getElementsByTagName("head");
if (heads.length > 0) {
heads[0].appendChild(node);
} else {
// no head yet, stick it whereever
document.documentElement.appendChild(node);
}
}
/* Add delimiter to numbers on homepage */
const homepageRows = [
document.querySelector(".container .row div form+div"),
document.querySelector(".container .row div form+div+div"),
document.querySelector(".container .row div form+div+div+div"),
document.querySelector(".container .row div form+div+div+div+div")
];
if (homepageRows[3]) {
const nums = homepageRows.map(r => r.children[0]);
if (nums[3]) {
nums.forEach(n => {
n.innerText = parseInt(n.innerText, 10).toLocaleString();
});
}
}
/* Auto-refresh activity pages */
let pause = false;
let interval;
function createRow(activity, pageType, fade = true) {
let row = "";
if (pageType === "player") {
if (activity.sighting != null) {
row = `
<td class="text-left entry-img no-wrap"><div class="${(fade)?"fade-in":""}">
<img class="card-img-top" src="${activity.sighting.leaderboard.imageURL}">
</div></td>
<td class="text-left"><div class="${(fade)?"fade-in":""}">
<a class="link" href="/Leaderboard/Level?leaderboardID=${activity.sighting.leaderboard.id}">
${activity.sighting.leaderboard.levelName}
</a>
</div></td>
<td><div class="${(fade)?"fade-in":""}">${/*TODO*/''}</div></td>
<td><div class="${(fade)?"fade-in":""}">${activity.sighting.millisecondsString} <span class="text-success">New!</span></div></td>
<td><div class="${(fade)?"fade-in":"fade-in-custom"}">${activity.timeAgoString}</div></td>
`;
} else {
row = `
<td class="text-left entry-img no-wrap"><div class="${(fade)?"fade-in":""}">
<img class="card-img-top" src="${activity.improvement.leaderboard.imageURL}">
</div></td>
<td class="text-left"><div class="${(fade)?"fade-in":""}">
<a class="link" href="/Leaderboard/Level?leaderboardID=${activity.improvement.leaderboard.id}">
${activity.improvement.leaderboard.levelName}
</a>
</div></td>
<td><div class="${(fade)?"fade-in":""}">
${activity.improvement.newRank}
( <i class="fas fa-arrow-up fa-sm text-success"></i> ${activity.improvement.oldRank - activity.improvement.newRank} )</div></td>
<td><div class="${(fade)?"fade-in":""}">
${activity.improvement.millisecondsString}
( <i class="fas fa-arrow-up fa-sm text-success"></i> ${activity.improvement.timeImprovement} )</div></td>
<td><div class="${(fade)?"fade-in":"fade-in-custom"}">${activity.timeAgoString}</div></td>
`;
}
} else {
if (activity.sighting != null) {
row = `
<td class="text-left entry-img no-wrap"><div class="${(fade)?"fade-in":""}">
<img src="${activity.sighting.player.steamAvatar}" />
<a class="link" href="/Player?steamID=${activity.sighting.player.steamID}">
${activity.sighting.player.name}
</a>
</div></td>
<td class="text-left entry-img no-wrap"><div class="${(fade)?"fade-in":""}">
<img src="${activity.sighting.leaderboard.imageURL}" />
<a class="link" href="/Leaderboard/Level?leaderboardID=${activity.sighting.leaderboard.id}">
${activity.sighting.leaderboard.levelName}
</a>
</div></td>
<td class="no-wrap"><div class="${(fade)?"fade-in":""}">${/*TODO*/''}</div></td>
<td class="no-wrap"><div class="${(fade)?"fade-in":""}">${activity.sighting.millisecondsString} <span class="text-success">New!</span></div></td>
<td class="no-wrap"><div class="${(fade)?"fade-in":"fade-in-custom"}">${activity.timeAgoString}</div></td>
`;
} else {
row = `
<td class="text-left entry-img no-wrap"><div class="${(fade)?"fade-in":""}">
<img src="${activity.improvement.player.steamAvatar}" />
<a class="link" href="/Player?steamID=${activity.improvement.player.steamID}">
${activity.improvement.player.name}
</a>
</div></td>
<td class="text-left entry-img no-wrap"><div class="${(fade)?"fade-in":""}">
<img src="${activity.improvement.leaderboard.imageURL}" />
<a class="link" href="/Leaderboard/Level?leaderboardID=${activity.improvement.leaderboard.id}">
${activity.improvement.leaderboard.levelName}
</a>
</div></td>
<td class="no-wrap"><div class="${(fade)?"fade-in":""}">
${activity.improvement.newRank}
( <i class="fas fa-arrow-up fa-sm text-success"></i> ${activity.improvement.oldRank - activity.improvement.newRank} )</div></td>
<td class="no-wrap"><div class="${(fade)?"fade-in":""}">
${activity.improvement.millisecondsString}
( <i class="fas fa-arrow-up fa-sm text-success"></i> ${activity.improvement.timeImprovement} )</div></td>
<td class="no-wrap"><div class="${(fade)?"fade-in":"fade-in-custom"}">${activity.timeAgoString}</div></td>
`;
}
}
return row;
}
function compare(a, b, x, y) {
if (x === y) return a[x].isEqualNode(b[x]);
else return a[x].isEqualNode(b[x]) && compare(a, b, x + 1, y);
}
async function getNewActivity() {
if (document.visibilityState !== 'visible') return;
const h = document.location.href;
const pageType = (h.match(/Player\?steamID=\d+$/)) ? "player" : (h.match(/\/Home\/(WR|Top100)Activity$/)) ? "activity" : null;
if (!pageType) return;
if (pause || (pageType === "player" && !($('.nav').children()[0].children[0].isSameNode($('.nav-link.active').get(0))))) {
console.log("[CAL] paused");
return;
}
try {
let json;
if (pageType === "player") {
const player = document.location.search.split("=")[1];
const res = await fetch(`/Player/GetRecentActivity?steamID=${player}`);
json = await res.json();
} else {
let res;
if (h.match(/GlobalActivity$/)) {
res = await fetch("/Home/GetGlobalRecentActivity");
} else if (h.match(/WRActivity$/)) {
res = await fetch("/Home/GetWRActivity");
} else if (h.match(/Top100Activity$/)) {
res = await fetch("/Home/GetTop100RecentActivity");
}
json = await res.json();
}
const recentActivity = $('#recentActivity');
console.log("[CAL] got data");
const mostRecentVisible = recentActivity.children()[0];
const rowsToInsert = [];
let found = false;
let i = 0;
for (const activity of json) {
const row = $("<tr>" + createRow(activity, pageType) + "</tr>");
const c = document.querySelector("#recentActivity").children[0].children;
const d = row.children();
//const recentStr = c[0].innerHTML+c[1].innerHTML+c[2].innerHTML+c[3].innerHTML;
//const rowStr = d[0].innerHTML+d[1].innerHTML+d[2].innerHTML+d[3].innerHTML;
//console.log("recentStr", recentStr);
//console.log("rowStr", rowStr);
//console.log("compare", rowStr !== recentStr);
//console.log("c", c);
//console.log("d", d);
if (!found && !compare(c, d, 0, 3)) {
console.log("[CAL] insert row");
rowsToInsert.push(row);
} else {
found = true;
const rc = row.children()[4];
const ra = document.querySelector("#recentActivity").children[i];
//console.log("i", i);
//console.log("document.querySelector(\"#recentActivity\").children", document.querySelector("#recentActivity").children);
//console.log("ra", ra);
if (rc.innerText !== ra.children[4].innerText) {
$(ra.children[4]).replaceWith($("<tr>" + createRow(activity, pageType, false) + "</tr>").children()[4]);
}
i++;
}
}
if (!rowsToInsert[0]) {
return;
}
if (pageType === "player" && getGlobalStats) {
console.log("[CAL] getting new global stats");
getGlobalStats();
displayRivals();
}
rowsToInsert.reverse();
for (const row of rowsToInsert) {
recentActivity.prepend(row);
const maxCount = (pageType === "activity") ? 100 : 30;
if (recentActivity.children().length > maxCount) {
recentActivity.get(0).deleteRow(recentActivity.children().length - 1);
}
}
} catch (e) {
console.error(e);
toastr.error('[HBT] Failed to load recent activity for this player');
clearInterval(interval);
}
}
if (document.location.href.match(/Player\?steamID=\d+$/) || document.location.href.match(/\/Home\/(WR|Top100)Activity$/)) {
interval = setInterval(getNewActivity, 1000 * 10);
}
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === 'visible') {
pause = false;
getNewActivity();
interval = setInterval(getNewActivity, 1000 * 10);
} else {
pause = true;
clearInterval(interval);
}
});
const navLinks = document.querySelectorAll(".nav-pills .nav-link");
navLinks.forEach(l => {
l.addEventListener("click", (e) => {
const customFades = document.querySelectorAll(".fade-in-custom");
customFades.forEach(f => {
f.classList.remove("fade-in-custom");
f.style.animation = "none";
setTimeout(() => {
const parent = f.parentElement;
$(f).detach().addClass("fade-in").appendTo(parent);
f.style.animation = "";
}, 200);
});
});
});
/* Find rivals for player pages */
function getRivals(steamId, data) {
if (!data.success) {
return 0;
}
// Find the index of the player with the given steam ID
let playerIndex = -1;
for (let i = 0; i < data.success.rows.length; i++) {
if (data.success.rows[i][0] === steamId) {
playerIndex = i;
break;
}
}
// Return null if the player with the given steam ID is not found
if (playerIndex === -1) {
return null;
}
// Initialize the list of rivals
let rivals = [data.success.rows[playerIndex]]; // Add the player to the list of rivals
// Add the 5 players ranked above the player to the list of rivals
for (let i = playerIndex - 1; i >= Math.max(0, playerIndex - 5); i--) {
if (i < 0) {
break;
}
rivals.push(data.success.rows[i]);
}
// Add the 5 players ranked below the player to the list of rivals
for (let i = playerIndex + 1; i <= Math.min(data.success.rows.length - 1, playerIndex + 5); i++) {
if (i > data.success.rows.length - 1) {
break;
}
rivals.push(data.success.rows[i]);
}
rivals.forEach((player, index) => {
player.index = index;
});
// Sort the list of rivals by global rank
rivals.sort((a, b) => {
if (parseInt(a[1]) === parseInt(b[1])) { // If the ranks are the same
return a.index - b.index; // Compare the indices of the players in the original list
}
return parseInt(a[1]) - parseInt(b[1]); // Compare the global ranks (column 1) of the players
});
return rivals;
}
async function displayRivals() {
if (document.location.href.match(/Player\?steamID=\d+$/)) {
try {
const limit = 10000;
const res = await fetch(`https://distance-db-sql-api.seekr.pw/?query=SELECT%0A%20%20steam_id,%0A%20%20RANK()%20OVER%20(%0A%20%20%20%20ORDER%20BY%20SUM(noodle_points)%20DESC%0A%20%20)%20as%20global_rank,%0A%20%20name,%0A%20%20SUM(noodle_points)%20as%20noodle_points,%0A%20%20ROUND((SUM(noodle_points)%20/%201200)::numeric,%202)%20as%20player_rating%0AFROM%20(%0A%20%20SELECT%0A%20%20%20%20user_info.steam_id,%0A%20%20%20%20user_info.name,%0A%20%20%20%20official_sprint.id,%0A%20%20%20%20CASE%20WHEN%20sle.rank%20is%20NULL%20OR%20sle.rank%20%3E%201000%20THEN%200%20ELSE%20ROUND(1000.0%20*%20(1.0%20-%20%7C/(1.0%20-%20(((sle.rank%20-%201.0)/1000.0)%20-%201.0)%5E2)))%20END%20AS%20noodle_points%0A%20%20FROM%20(%0A%20%20%20%20SELECT%20steam_id,%20name%20FROM%20Users%0A%20%20)%20user_info%0A%20%20CROSS%20JOIN%20(%0A%20%20%20%20SELECT%20id%20FROM%20official_levels%20WHERE%20is_sprint%0A%20%20)%20official_sprint%0A%20%20INNER%20JOIN%20sprint_leaderboard_entries%20sle%20ON%20sle.level_id%20=%20official_sprint.id%20AND%20sle.steam_id%20=%20user_info.steam_id%0A)%20official_ranks%0AGROUP%20BY%20steam_id,%20name%0AORDER%20BY%20SUM(noodle_points)%20DESC%0ALIMIT%20${limit}`, {
"method": "GET",
"mode": "cors",
"credentials": "omit",
"cache": "no-cache"
});
const json = await res.json();
const currentPlayerId = document.location.href.match(/Player\?steamID=(\d+)$/)[1];
const rivals = getRivals(currentPlayerId, json);
console.log("[CAL] rivals:", rivals);
const column = document.querySelector("body > div > main > div > div > div.col-xl-3.col-12");
if (column.children.length >= 5) {
column.children[4].remove();
}
if (column.children.length >= 4) {
column.children[3].remove();
}
const hr = document.createElement("hr");
const rivalDiv = document.createElement("div");
rivalDiv.classList.add("fade-in");
const rivalHead = document.createElement("h4");
rivalHead.innerText = "Rivals";
rivalDiv.appendChild(rivalHead);
column.appendChild(hr);
column.appendChild(rivalDiv);
if (rivals === 0) {
const p = document.createElement("p");
p.innerHTML = "Rivals list could not be fetched. Try refreshing the page.";
console.log("[CAL] failed fetching json", json);
rivalDiv.appendChild(p);
} else if (!rivals || rivals.find(r => r[0] === currentPlayerId)[3] === "0") {
const p = document.createElement("p");
p.innerHTML = "This player has 0 points.<br />They must be ranked within the top 1000 on any level to get points before a rivals list can be made.";
rivalDiv.appendChild(p);
} else {
const ul = document.createElement("ul");
ul.style.listStyleType = "none";
ul.style.textAlign = "left";
ul.style.paddingLeft = "0";
rivalDiv.appendChild(ul);
let oddEven = false;
for (const rival of rivals) {
const [id, rank, name, points, rating] = rival;
const res2 = await fetch(`/Search/Players?q=${name}`);
const players = await res2.json();
const li = document.createElement("li");
li.style.margin = "3px";
li.style.padding = "3px";
li.style.borderRadius = "5px";
li.style.background = (oddEven) ? "#ffffff11" : "#ffffff1f";
oddEven = !oddEven;
const player = players.find(p => p.steamID === id);
if (id === currentPlayerId) {
li.style.background = "#00ffff2f";
}
let txt;
if (!player) {
txt = `${rank} 		 <a class="link" style="margin-left:39px;" href="/Player?steamID=${id}">${name}</a>`
} else {
txt = `${rank} 		 <a class="link" href="/Player?steamID=${id}"><img src="${player.steamAvatar}" class="mr-2" \>${name}</a>`;
}
ul.appendChild(li);
li.innerHTML = txt;
}
}
/*column.appendChild(rivalDiv);*/
} catch (e) {
console.error(e);
}
}
}
displayRivals();
/* Add your own player ranks */
const lssteamIDs = localStorage.getItem("mySteamID");
const lsIds = lssteamIDs.split(",");
async function getRankings(playerId) {
if (!playerId) return;
const match = document.location.href.match(/Leaderboard\/Level\?leaderboard(id|ID)=\d+$/);
if (!match) return;
const matches = document.location.href.match(/Leaderboard\/Level\?leaderboard(id|ID)=(\d+)$/);
console.log(matches);
if (!matches || !matches[2]) return;
const [,, mapId] = matches;
try {
const res = await fetch(`/Player/GetLeaderboardRankings?steamID=${playerId}`);
const json = await res.json();
if (!json?.[0]) {
return toastr.error('[HBT] No user found with the given SteamID64');
}
let thisMap = json.find(entry => entry.leaderboard.id == mapId);
let unranked = false;
if (!thisMap) {
unranked = true;
thisMap = json[0];
}
const topInfo = document.querySelector("body > div > main > div > div:nth-child(1)");
while (topInfo.children.length >= 5 + lsIds.length) {
topInfo.removeChild(topInfo.lastChild);
}
topInfo.style.marginBottom = "10px";
const yourRank = `<div class="col-12"><h5 class="stroke" id="customRank"><img id="customAvatar" src="${thisMap.player.steamAvatar}" /><span><a href="/Player?steamID=${thisMap.player.steamID}">${thisMap.player.name}</a> Rank: ${(unranked) ? "None" : thisMap.rank}</span></h5></div>`
topInfo.innerHTML += yourRank;
} catch (e) {
console.error(e);
}
}
if (lsIds[0]) {
for (const id of lsIds) {
getRankings(id);
}
}
async function getRankingsAll(playerId) {
if (!playerId) return;
if (!document.location.href.match(/Leaderboard\/Levels$/)) return;
try {
const res = await fetch(`/Player/GetLeaderboardRankings?steamID=${playerId}`);
const json = await res.json();
if (!json?.[0]) {
return toastr.error('[HBT] No user found with the given SteamID64');
}
while (document.querySelectorAll(".level-card").length < 159) {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
}
const cards = Array.from(document.querySelectorAll(".level-card"));
for (const card of cards) {
const matches = card.children[0]?.href?.match(/Leaderboard\/Level\?leaderboard(id|ID)=(\d+)$/);
if (!matches || !matches[2]) continue;
const [,, mapId] = matches;
if (!mapId) continue;
const thisMap = json.find(entry => entry.leaderboard.id == mapId);
if (!thisMap) continue;
const cardInfo = card.children[0].children[0].children[1];
while (cardInfo.children.length >= 3 + lsIds.length) {
cardInfo.removeChild(cardInfo.lastChild);
}
const yourRank = `<h6 class="card-subtitle mb-2">${thisMap.player.name} Rank: ${thisMap.rank}</h6>`;
cardInfo.innerHTML += yourRank;
}
} catch (e) {
console.error(e);
}
}
if (lsIds[0]) {
for (const id of lsIds) {
getRankingsAll(id);
}
}
function insertSteamIDForm() {
const form = `<form class="form-inline" id="steamID"><input class="form-control mr-sm-2" placeholder="Enter your SteamID64"><button class="btn btn-success">Profile</button></form>`;
const div = document.createElement("div");
div.innerHTML = form;
const navbar = document.querySelector("body > header > nav");
const search = navbar.querySelector("form input[placeholder=\"Enter player name\"]");
if (search) {
navbar.insertBefore(div.firstChild, navbar.querySelector("form"));
document.querySelector("form#steamID button").style.marginRight = "15px";
} else {
navbar.appendChild(div.firstChild);
}
const steamIDs = localStorage.getItem("mySteamID");
const ids = steamIDs.split(",");
if (steamIDs && ids[0]) {
document.querySelector("form#steamID input").value = steamIDs;
document.querySelector("form#steamID button").addEventListener("click", (event) => {
event.preventDefault();
window.location.href = `http://holdboost.com/Player?steamID=${ids[0]}`;
});
}
document.querySelector("form#steamID input").addEventListener("input", (event) => {
const val = event.target.value;
localStorage.setItem("mySteamID", val);
console.log(`[CAL] Set SteamID: ${val}`);
processChange(val);
});
}
async function removeCustomProfile() {
if (document.location.href.match(/Leaderboard\/Level\?leaderboard(id|ID)=\d+$/)) {
const topInfo = document.querySelector("body > div > main > div > div:nth-child(1)");
while (topInfo.children.length >= 6) {
topInfo.removeChild(topInfo.lastChild);
}
topInfo.style.marginBottom = "50px";
} else if (document.location.href.match(/Leaderboard\/Levels$/)) {
while (document.querySelectorAll(".level-card").length < 120) {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
}
const cards = Array.from(document.querySelectorAll(".level-card"));
for (const card of cards) {
const cardInfo = card.children[0].children[0].children[1];
while (cardInfo.children.length >= 3) {
cardInfo.removeChild(cardInfo.lastChild);
}
}
}
}
async function testValidID() {
const idItem = localStorage.getItem("mySteamID");
const ids = idItem.split(",");
if (ids.length === 1 && ids[0] === "") {
toastr.info('[HBT] Removed SteamID64');
removeCustomProfile();
}
for (const id of ids) {
const res = await fetch(`/Player/GetLeaderboardRankings?steamID=${id}`);
const json = await res.json();
if (!json?.[0]) {
toastr.error(`[HBT] No user found with the given SteamID64: `);
removeCustomProfile();
} else {
toastr.success(`[HBT] Found user with matching SteamID64: `);
getRankings(id);
getRankingsAll(id);
}
}
}
insertSteamIDForm();
function debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}
const processChange = debounce(() => testValidID());
function autofillCompare() {
if (!document.location.href.match(/Player\/Compare$/)) return;
const compareInput = document.querySelector("input[name=\"steamIDs\"]");
if (!compareInput) return;
const idItem = localStorage.getItem("mySteamID");
if (!idItem) return;
compareInput.value = `${idItem},`;
}
autofillCompare();
function profileCompareButton() {
if (!document.location.href.match(/Player\?steamID=\d+$/)) return;
const nameElem = document.querySelector("body > div > main > div > div > div.col-xl-3.col-12 > div:nth-child(1) > div > div.col-4.col-xl-12 > h2");
if (!nameElem) return;
const idItem = localStorage.getItem("mySteamID");
if (!idItem) return;
const compareID = new URL(location.href).searchParams.get('steamID');
if (!compareID || compareID === idItem) return;
const compareBtn = document.createElement("a");
const compareIcon = document.createElement("i");
compareBtn.appendChild(compareIcon);
compareIcon.title = "Compare with your SteamID";
compareIcon.classList.add("fas", "fa-user-friends", "fa-xxs", "pointer");
compareBtn.href = `/Player/Compare?steamIDs=${idItem},${compareID}`;
nameElem.appendChild(compareBtn);
}
profileCompareButton();
function challengeThumbnailFixer() {
const images = {
detached: 'https://i.imgur.com/tlkiNbm.png',
secondTheory: 'https://i.imgur.com/tSuPbHY.png',
transfer: 'https://i.imgur.com/sDP8KEU.png',
divide: 'https://i.imgur.com/xhYXbk8.png',
thunderStruck: 'https://i.imgur.com/FEu5aUy.png',
electric: 'https://i.imgur.com/5R2LbgX.png',
descent: 'https://i.imgur.com/kRqjD5v.png',
disassemblyLine: 'https://i.imgur.com/v0LRhej.png',
redHeat: 'https://i.imgur.com/QvK7BIi.png',
grinder: 'https://i.imgur.com/JcsEZ5b.png',
dodge: 'https://i.imgur.com/123tJfC.png',
elevation: 'https://i.imgur.com/OjA5vOw.png',
obsidian: 'https://i.imgur.com/BuOIbjU.png',
hexahorrific: 'https://i.imgur.com/DyjdmL1.png',
variantBlue: 'https://i.imgur.com/HOexe45.png',
biotec: 'https://i.imgur.com/w6WaBq2.png'
};
function runSwitch(name, defaultVal) {
switch (name) {
case 'Detached':
return images.detached;
case '44 Second Theory':
return images.secondTheory;
case 'Transfer':
return images.transfer;
case 'Divide':
return images.divide;
case 'Thunder Struck':
return images.thunderStruck;
case 'Electric':
return images.electric;
case 'Descent':
return images.descent;
case 'Disassembly Line':
return images.disassemblyLine;
case 'Red Heat':
return images.redHeat;
case 'Grinder':
return images.grinder;
case 'Dodge':
return images.dodge;
case 'Elevation':
return images.elevation;
case 'Obsidian':
return images.obsidian;
case 'Hexahorrific':
return images.hexahorrific;
case 'Variant Blue':
return images.variantBlue;
case 'Biotec 4':
return images.biotec;
default:
return defaultVal || '';
}
}
if (document.location.href.match(/Leaderboard\/Level\?leaderboard(id|ID)=\d+$/)) {
const bgImg = window.getComputedStyle(document.body).backgroundImage;
// console.log('[CAL]', bgImg);
if (bgImg.includes('placekitten.com')) {
const nameElem = document.querySelector(".col-12 > h1");
const name = nameElem.innerText;
const newBgImg = runSwitch(name);
if (!newBgImg) return;
document.body.style.backgroundImage = `url(${newBgImg})`;
}
} else if (document.location.href.match(/Player\?steamID=\d+$/)) {
// potential change to disconnect observer after initial entries are loaded:
// https://chatgpt.com/share/26f76f89-e0f4-4c81-b84b-1db0353860e2
const recentActivity = document.querySelector('#recentActivity');
const rankingsTable = document.querySelector('#leaderboardRankingsTable');
if (!recentActivity) return;
const config = { childList: true, subtree: true };
const callback = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.type !== 'childList') continue;
// console.log('[CAL]', 'child node added', mutation.addedNodes);
const rows = Array.from(mutation.addedNodes);
for (const row of rows) {
if (!row?.children?.[0] || !row?.children?.[1]) continue;
if (!row?.children?.[0]?.children?.[0]?.children?.[0]?.src) continue;
const src = new URL(row.children[0].children[0].children[0].src);
if (src.hostname !== 'placekitten.com') continue;
const mapName = row.children[1].innerText;
const newSrc = runSwitch(mapName, row.children[0].children[0].children[0].src);
row.children[0].children[0].children[0].src = newSrc;
}
}
}
const observer = new MutationObserver(callback);
observer.observe(recentActivity, config);
observer.observe(rankingsTable, config);
} else if (document.location.href.match(/Leaderboard\/Levels$/)) {
const levels = document.querySelector('#levels');
if (!levels) return;
const config = { childList: true, subtree: true }
const callback = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.type !== 'childList') continue;
// console.log('[CAL]', 'added nodes', mutation.addedNodes);
const lvlCards = Array.from(mutation.addedNodes);
for (const card of lvlCards) {
if (!card.classList?.contains('level-card')) continue;
const img = card.querySelector('img');
if (!img.src.includes('placekitten.com')) continue;
const name = card.querySelector('h5').innerText;
const newSrc = runSwitch(name);
if (!newSrc) continue;
img.src = newSrc;
}
}
}
const observer = new MutationObserver(callback);
observer.observe(levels, config);
}
}
challengeThumbnailFixer();
})();