Skip to content

Commit 78f7db7

Browse files
authored
feat(GeoGuessr): add missing division badges and improve duel presence format (#11099)
- Add Bronze I-IV, Silver IV, Gold IV, Master III-IV division badge icons - Add new Solo Duels and Team Duels game mode icons (upscaled to 512x512) - Redesign duel presence: details shows mode and division, state shows round and score - Round number incremented by 1 (post-round screen shows completed round) - Fix round extraction to handle non-breaking spaces via regex - Fix viewActivities string key typo (was viewActivity, caused undefined on /activities) - Fix isUnranked stale state reset on re-entering multiplayer - Bump version 2.2.0 to 2.3.0
1 parent bcea31e commit 78f7db7

3 files changed

Lines changed: 123 additions & 27 deletions

File tree

websites/G/GeoGuessr/assets.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
export const divisionIcons: Record<string, string> = {
2+
'Bronze IV': 'https://i.imgur.com/AmbABKF.png',
3+
'Bronze III': 'https://i.imgur.com/qfdOO5p.png',
4+
'Bronze II': 'https://i.imgur.com/G2NuNVO.png',
5+
'Bronze I': 'https://i.imgur.com/0xHlqrA.png',
6+
'Silver IV': 'https://i.imgur.com/JUX1ITk.png',
27
'Silver III': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/0.png',
38
'Silver II': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/1.png',
49
'Silver I': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/2.png',
10+
'Gold IV': 'https://i.imgur.com/bLTDFXc.png',
511
'Gold III': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/3.png',
612
'Gold II': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/4.png',
713
'Gold I': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/5.png',
14+
'Master IV': 'https://i.imgur.com/w8IDLOi.png',
15+
'Master III': 'https://i.imgur.com/hwEJGGF.png',
816
'Master II': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/6.png',
917
'Master I': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/7.png',
1018
'Champion': 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/8.png',
@@ -20,8 +28,8 @@ export const gameModeIcons: Record<string, string> = {
2028
live_challenge: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/14.png',
2129
party: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/15.png',
2230
quiz: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/16.png',
23-
solo_duels: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/17.png',
24-
team_duels: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/18.png',
31+
solo_duels: 'https://i.imgur.com/vyHUTfm.png',
32+
team_duels: 'https://i.imgur.com/JIANvyy.png',
2533
streaks: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/19.png',
2634
halloween: 'https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/3376.png',
2735
}

websites/G/GeoGuessr/metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"geoguessr.com"
2121
],
2222
"regExp": "^https?[:][/][/](www[.])?geoguessr[.]com[/]",
23-
"version": "2.2.0",
23+
"version": "2.3.0",
2424
"logo": "https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/logo.png",
2525
"thumbnail": "https://cdn.rcd.gg/PreMiD/websites/G/GeoGuessr/assets/thumbnail.png",
2626
"color": "#7950e5",

websites/G/GeoGuessr/presence.ts

Lines changed: 112 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ async function updateStrings() {
129129
details: strings.viewHelppage,
130130
},
131131
'activities': {
132-
details: strings.viewActivity,
132+
details: strings.viewActivities,
133133
},
134134
'community': {
135135
details: strings.viewCommunity,
@@ -206,9 +206,14 @@ let urlCache: any
206206

207207
let soloDivision: any
208208
let soloRatingString: any
209+
let teamDivision: any
210+
let teamRatingString: any
209211

210212
let isUnranked: boolean = false
211213
let currentGameMode: string = ''
214+
let currentDuelRound: any = null
215+
let duelGameActive = false
216+
let duelBaseDetails = ''
212217

213218
presence.on('UpdateData', async () => {
214219
const currentRawURL = document.location.href
@@ -227,6 +232,12 @@ presence.on('UpdateData', async () => {
227232
pathCache = currentPath
228233
urlCache = currentRawURL
229234

235+
if (isNewURL) {
236+
currentDuelRound = null
237+
if (currentPath[0] === 'multiplayer' && lastPath[0] !== 'multiplayer')
238+
isUnranked = false
239+
}
240+
230241
if (!strings) {
231242
await updateStrings()
232243
}
@@ -273,23 +284,60 @@ presence.on('UpdateData', async () => {
273284
setTimeout(() => {
274285
cooldowns.health = false
275286
}, 5000)
276-
const healthUI = document.querySelectorAll('[class^="health-bar-2_barLabel__"]')
277-
let scoreText: any
278-
if (healthUI.length >= 2) {
287+
288+
const roundElement = document.querySelector('[class^="round-score_roundNumber__"]')
289+
if (roundElement && roundElement.textContent) {
290+
const roundNum = Number(roundElement.textContent.replace(/\D/g, ''))
291+
// +1 because the post-round screen shows the round just completed
292+
currentDuelRound = roundNum ? `Round ${roundNum + 1}` : null
293+
}
294+
295+
const healthUI = document.querySelectorAll('[class^="health-bar-2_barLabel__"], [class^="health-bar_barLabel__"]')
296+
let scoreText: string | undefined
297+
const hasHealth = healthUI.length >= 2
298+
if (hasHealth) {
279299
const firstLabel = healthUI[0] as HTMLElement
280300
const secondLabel = healthUI[1] as HTMLElement
281301
if (firstLabel && secondLabel && firstLabel.textContent && secondLabel.textContent) {
282-
scoreText = ` | ${firstLabel.textContent} - ${secondLabel.textContent}`
302+
scoreText = `${firstLabel.textContent} - ${secondLabel.textContent}`
283303
}
284304
}
285-
if (autoSetGamemode && currentGameMode !== '') {
305+
else {
306+
if (!roundElement) {
307+
currentDuelRound = null
308+
}
309+
}
310+
311+
// default to Round 1 before any round completes
312+
if (hasHealth && !currentDuelRound) {
313+
currentDuelRound = 'Round 1'
314+
}
315+
316+
const hasGameState = !!(currentDuelRound || scoreText)
317+
318+
if (hasGameState && autoSetGamemode && currentGameMode !== '') {
286319
prefix = `${currentGameMode} ${prefix}`
287320
}
321+
288322
if (!isConnected()) {
289323
return
290324
}
291-
presenceData.details = `${prefix}${scoreText || ''}`
325+
presenceData.details = prefix
326+
duelBaseDetails = prefix
327+
if (hasGameState) {
328+
const stateParts: string[] = []
329+
if (currentDuelRound)
330+
stateParts.push(currentDuelRound)
331+
if (scoreText)
332+
stateParts.push(scoreText)
333+
presenceData.state = stateParts.join(' | ')
334+
duelGameActive = true
335+
}
336+
else {
337+
duelGameActive = false
338+
}
292339
}
340+
293341
async function getMapIconFromInfo(mapInfo: any) {
294342
if (!isConnected() || !mapInfo) {
295343
return
@@ -330,9 +378,12 @@ presence.on('UpdateData', async () => {
330378
return await getMapIconFromInfo(mapInfo)
331379
}
332380

333-
async function setDivisionInfo(divisionName: any = null, rating: any = null) {
381+
async function setDivisionInfo(divisionName: any = null, rating: any = null, appendToDetails: boolean = false) {
334382
if (isUnranked) {
335-
presenceData.state = strings.inUnranked
383+
if (appendToDetails)
384+
presenceData.details = `${duelBaseDetails} | ${strings.unranked}`
385+
else
386+
presenceData.state = strings.inUnranked
336387
presenceData.smallImageKey = divisionIcons.Unranked
337388
presenceData.smallImageText = strings.unranked
338389
return
@@ -356,7 +407,10 @@ presence.on('UpdateData', async () => {
356407
if (!isConnected()) {
357408
return
358409
}
359-
presenceData.state = strings.division.replace('{0}', divisionName)
410+
if (appendToDetails)
411+
presenceData.details = `${duelBaseDetails} | ${divisionName}`
412+
else
413+
presenceData.state = strings.division.replace('{0}', divisionName)
360414
const divisionIcon = divisionIcons[divisionName]
361415
if (divisionIcon) {
362416
presenceData.smallImageKey = divisionIcon
@@ -523,27 +577,30 @@ presence.on('UpdateData', async () => {
523577

524578
if (isRanked) {
525579
presenceData.largeImageKey = (isTeams && gameModeIcons.team_duels) || gameModeIcons.solo_duels
526-
presenceData.state = strings.inRanked
580+
if (!duelGameActive)
581+
presenceData.state = strings.inRanked
527582
delete presenceData.smallImageKey
528583
if (!isTeams) {
529-
setDivisionInfo(soloDivision, soloRatingString)
584+
setDivisionInfo(soloDivision, soloRatingString, duelGameActive)
530585
}
531586
}
532587
else if (gameInfo.options.gameContext.type === 'PartyV2') {
533588
presenceData.smallImageKey = gameModeIcons.party
534589
presenceData.smallImageText = strings.party
535590
presenceData.largeImageKey = (isTeams && gameModeIcons.team_duels) || gameModeIcons.solo_duels
536-
presenceData.state = strings.inParty
591+
if (!duelGameActive)
592+
presenceData.state = strings.inParty
537593
}
538594
else {
539595
presenceData.largeImageKey = (isTeams && gameModeIcons.team_duels) || gameModeIcons.solo_duels
540-
presenceData.state = strings.inUnranked
596+
if (!duelGameActive)
597+
presenceData.state = strings.inUnranked
541598
presenceData.smallImageKey = divisionIcons.Unranked
542599
presenceData.smallImageText = strings.unranked
543600
}
544601
}
545602
}
546-
else if (currentPath[0] && currentPath[0] === 'matchmaking') {
603+
else if (currentPath[0] === 'matchmaking') {
547604
const gameModeTextList = document.querySelectorAll('[class*="game-mode-brand_subTitle___"]')
548605
if (!alreadyFetchedList[currentPath[0]] && gameModeTextList[0]) {
549606
const isTeams = gameModeTextList[0] && gameModeTextList[0].textContent
@@ -627,37 +684,48 @@ presence.on('UpdateData', async () => {
627684
}
628685
}
629686
else if (currentPath[0] === 'multiplayer') {
630-
if (!currentPath[1]) {
687+
if (!currentPath[1] || currentPath[1] === 'duels') {
631688
// Duels (new HUD)
632689
setHealthUI(strings.duels, true)
633690
presenceData.largeImageKey = gameModeIcons.solo_duels
691+
634692
const rankText = document.querySelectorAll('[class^="division-header_title__"]')
635693
const unrankedHeader = document.querySelectorAll('[class^="division-header_unrankedRoot__"]')
694+
const unrankedMatchmaking = document.querySelectorAll('[class^="unranked-matchmaking-layout_"]')
695+
636696
if (unrankedHeader[0]) {
637697
const unrankedHeaderShowing = document.querySelectorAll('[class*="division-header_reveal__"]')
638698
isUnranked = (unrankedHeaderShowing[0] && true) || false
639699
}
700+
else if (unrankedMatchmaking[0]) {
701+
isUnranked = true
702+
}
703+
else if (rankText[0]) {
704+
isUnranked = false
705+
}
706+
640707
if (rankText[0]) {
641708
const divisionString = rankText[0].textContent
642709
const ratingText = document.querySelectorAll('[class^="division-header_rating__"]')
643710
let ratingString: any
644711
if (ratingText[0]) {
645712
ratingString = ratingText[0].textContent
646713
}
647-
setDivisionInfo(divisionString, ratingString)
714+
setDivisionInfo(divisionString, ratingString, duelGameActive)
648715
}
649716
else if (lastPath[0] !== 'multiplayer' || lastPath[1]) {
650717
delete presenceData.smallImageKey
651-
presenceData.state = strings.inRanked
652-
setDivisionInfo(soloDivision, soloRatingString)
718+
if (!duelGameActive)
719+
presenceData.state = isUnranked ? strings.inUnranked : strings.inRanked
720+
setDivisionInfo(soloDivision, soloRatingString, duelGameActive)
653721
}
654722
}
655723
else if (currentPath[1] === 'teams') {
656724
// Duels (new HUD, teams)
657725
isUnranked = false
658726
setHealthUI(strings.teamDuels, true)
659727
presenceData.largeImageKey = gameModeIcons.team_duels
660-
if (isNewURL) {
728+
if (isNewURL && !duelGameActive) {
661729
delete presenceData.smallImageKey
662730
presenceData.state = strings.inRanked
663731
}
@@ -668,8 +736,18 @@ presence.on('UpdateData', async () => {
668736
let ratingString: any
669737
if (ratingText[0]) {
670738
ratingString = ratingText[0].textContent
739+
teamRatingString = ratingString
740+
}
741+
teamDivision = divisionString
742+
setDivisionInfo(divisionString, ratingString, duelGameActive)
743+
}
744+
else if (lastPath[0] !== 'multiplayer' || lastPath[1]) {
745+
delete presenceData.smallImageKey
746+
if (!duelGameActive)
747+
presenceData.state = strings.inRanked
748+
if (teamDivision) {
749+
setDivisionInfo(teamDivision, teamRatingString, duelGameActive)
671750
}
672-
setDivisionInfo(divisionString, ratingString)
673751
}
674752
}
675753
else if (currentPath[1] === 'battle-royale-countries') {
@@ -693,10 +771,12 @@ presence.on('UpdateData', async () => {
693771
presenceData.smallImageText = strings.unranked
694772
}
695773
else {
696-
presenceData.details = strings.multiplayer
774+
presenceData.details = strings.inRanked
697775
presenceData.largeImageKey = logo
698-
delete presenceData.state
699-
delete presenceData.smallImageKey
776+
if (!soloDivision)
777+
await setDivisionInfo()
778+
else
779+
await setDivisionInfo(soloDivision, soloRatingString)
700780
}
701781
}
702782
else if (currentPath[0] === 'party') {
@@ -809,6 +889,14 @@ presence.on('UpdateData', async () => {
809889
}
810890
}
811891
}
892+
else if (currentPath[0] === 'world') {
893+
delete presenceData.buttons
894+
presenceData.state = 'World'
895+
presenceData.largeImageKey = mapAvatarOfficial.world || logo
896+
presenceData.details = strings.viewMap
897+
presenceData.smallImageKey = movementIcons.moving
898+
presenceData.smallImageText = strings.movementMoving
899+
}
812900
else {
813901
presenceData.largeImageKey = logo
814902
presenceData.details = strings.inMenu

0 commit comments

Comments
 (0)