@@ -3,15 +3,61 @@ import { chromium } from 'patchright';
33import chalk from 'chalk' ;
44import { resolve , jsonDb , datetime , filenamify , prompt , confirm , notify , html_game_list , handleSIGINT } from './src/util.js' ;
55import { cfg } from './src/config.js' ;
6+ import { gpUrlToStoreUrls } from './src/gp.js' ;
67
78const screenshot = ( ...a ) => resolve ( cfg . dir . screenshots , 'gog' , ...a ) ;
89
910const URL_CLAIM = 'https://www.gog.com/en' ;
11+ const GAMERPOWER_API_URL = 'https://www.gamerpower.com/api/giveaways?platform=gog&type=game' ;
1012
1113console . log ( datetime ( ) , 'started checking gog' ) ;
1214
1315const db = await jsonDb ( 'gog.json' , { } ) ;
1416
17+ function isGpGameAlreadyClaimed ( storeUrl ) {
18+ // GOG URLs look like: https://www.gog.com/en/game/game-name
19+ const match = storeUrl . match ( / \/ g a m e \/ ( [ ^ / ? ] + ) / ) ;
20+ const game_id = match ? match [ 1 ] : storeUrl . split ( '/' ) . pop ( ) ;
21+
22+ // Check if any user has claimed this game (GOG db uses title as key)
23+ for ( const [ username , games ] of Object . entries ( db . data ) ) {
24+ for ( const [ title , info ] of Object . entries ( games ) ) {
25+ if ( info . url ?. includes ( game_id ) && ( info . status === 'claimed' || info . status === 'existed' ) ) {
26+ console . log ( `[GamerPower] Already claimed by ${ username } : ${ storeUrl } ` ) ;
27+ return true ;
28+ }
29+ }
30+ }
31+
32+ return false ;
33+ }
34+
35+ async function getUnclaimedGpUrls ( ) {
36+ if ( ! cfg . gog_check_gp ) return [ ] ;
37+
38+ // gpUrlToStoreUrls handles fetching API and resolving URLs (opens browser only if needed)
39+ const allGpGames = await gpUrlToStoreUrls ( GAMERPOWER_API_URL ) ;
40+
41+ // Filter to GOG store URLs only
42+ const gogGames = allGpGames . filter ( g => g . storeUrl . includes ( 'gog.com' ) ) ;
43+ console . log ( `[GamerPower] ${ gogGames . length } GOG store URLs` ) ;
44+
45+ // Filter out already claimed games
46+ const unclaimed = gogGames . filter ( g => ! isGpGameAlreadyClaimed ( g . storeUrl ) ) ;
47+ console . log ( `[GamerPower] ${ unclaimed . length } unclaimed games` ) ;
48+
49+ return unclaimed . map ( g => g . storeUrl ) ;
50+ }
51+
52+ // Check GamerPower first (before starting browser)
53+ const gpUrls = await getUnclaimedGpUrls ( ) ;
54+
55+ // If GOG_CHECK_GP is enabled and no unclaimed games, exit early without opening browser
56+ if ( cfg . gog_check_gp && gpUrls . length === 0 ) {
57+ console . log ( 'No unclaimed GamerPower giveaways. Exiting.' ) ;
58+ process . exit ( 0 ) ;
59+ }
60+
1561if ( cfg . width < 1280 ) { // otherwise 'Sign in' and #menuUsername are hidden (but attached to DOM), see https://github.com/vogler/free-games-claimer/issues/335
1662 console . error ( `Window width is set to ${ cfg . width } but needs to be at least 1280 for GOG!` ) ;
1763 process . exit ( 1 ) ;
@@ -117,6 +163,24 @@ try {
117163 const title = match_all [ 1 ] ? match_all [ 1 ] : match_all [ 2 ] ;
118164 const url = await banner . locator ( 'a' ) . first ( ) . getAttribute ( 'href' ) ;
119165 console . log ( `Current free game: ${ chalk . blue ( title ) } - ${ url } ` ) ;
166+
167+ // GamerPower games - verify they are included in the current giveaway
168+ if ( cfg . gog_check_gp && gpUrls . length > 0 ) {
169+ console . log ( `Verifying ${ gpUrls . length } GamerPower giveaways match GOG's current giveaway...` ) ;
170+ for ( const gpUrl of gpUrls ) {
171+ // Normalize URLs for comparison (extract game slug)
172+ const gpMatch = gpUrl . match ( / \/ g a m e \/ ( [ ^ / ? ] + ) / ) ;
173+ const gpSlug = gpMatch ? gpMatch [ 1 ] : gpUrl . split ( '/' ) . pop ( ) ;
174+ const found = url && url . includes ( gpSlug ) ;
175+ if ( ! found ) {
176+ console . error ( `[GamerPower] ERROR: ${ gpUrl } does NOT match GOG's current giveaway!` ) ;
177+ console . error ( `[GamerPower] GOG's current giveaway: ${ url } ` ) ;
178+ } else {
179+ console . log ( `[GamerPower] OK: ${ gpUrl } ` ) ;
180+ }
181+ }
182+ }
183+
120184 db . data [ user ] [ title ] ||= { title, time : datetime ( ) , url } ;
121185 if ( cfg . dryrun ) process . exit ( 1 ) ;
122186 if ( cfg . interactive && ! await confirm ( ) ) process . exit ( 0 ) ;
0 commit comments