A Java library that finds 100% off games from Steam, EpicGames, and GOG.
<dependency>
<groupId>io.github.theforbiddenai</groupId>
<artifactId>GameFinder</artifactId>
<version>1.0.0</version>
</dependency>
implementation 'io.github.theforbiddenai:GameFinder:1.0.0'
If you are unable to resolve dependencies from Maven repositories, the GameFinder's jar can be downloaded from the Central Maven Repository.
First, create an instance of the GameFinder
class:
GameFinder gameFinder = new GameFinder();
By default, there are no enabled platforms. To change that do the following:
GameFinderConfiguration config = GameFinderConfiguration.getInstance();
config.getEnabledPlatforms().add(Platform.EPIC_GAMES);
config.getEnabledPlatforms().add(Platform.STEAM);
config.getEnabledPlatforms().add(Platform.GOG);
The above lines will enable all platforms. To retrieve games, there are two options:
The first way (and the recommended way) is to call the retrieveGamesAsync
method.
As the name implies, this will retrieve games asynchronously.
gameFinder.retrieveGamesAsync(gameCollection -> System.out.println(gameCollection), throwable -> System.err.println(throwable));
This method takes in two callbacks: A GameRetrievalCallback and a GameRetrievalErrorCallback. The GameRetrievalErrorCallback is called each time an error is thrown
NOTE: The GameRetrievalCallback will be called one time for each platform.
- This means that each collection will contain games from only ONE platform.
The second way to retrieve games is to call the retrieveGames
method.
This will retrieve games synchronously and return a list containing ALL found games.
List<Game> games = gameFinder.retrieveGames();
Because some information MUST be web-scraped depending on the platform, it is recommended that you use the asynchronous method.
NOTE: The web-scraping portion is still done asynchronously. However, this method waits until all results are ready before it returns any Game objects.
GameFinder returns Game objects. Here is what each Game object contains
title
of the gamedescription
of the game (translated to the language provided in the locale if provided by the game's platform, otherwise English)url
to the game's listing- A boolean (
isDLC
) specifying whether the game object is a DLC or not - The
originalPrice
of the game (In the currency obtained from the locale if provided by the game's platform, otherwise USD) - The
platform
of the game in the form of a Platform enum - A map of store media (
storeMedia
)- This contains store art such as the capsule images and page backgrounds for Steam
- A list of screenshots (
media
) from the game - The
expirationTime
in epoch seconds (If an expiration time cannot be found, this property will be set to -1)
GameFinder has a singleton configuration class named GameFinderConfiguration
.
To access its instance, use the getInstance
method:
GameFinderConfiguration config = GameFinderConfiguration.getInstance();
As stated above, by default, there are no enabled platforms. To change the enabled platforms, you can either call the setEnabledPlatforms
method and pass in a list of Platform enums, or you can call the getEnabledPlatforms
and use the built-in Java list functions
config.setEnabledPlatforms(List.of(Platform.STEAM, Platform.EPIC_GAMES, Platform.GOG));
config.getEnabledPlatforms().add(Platform.EPIC_GAMES);
config.getEnabledPlatforms().add(Platform.STEAM);
config.getEnabledPlatforms().add(Platform.GOG);
By default, GameFinder will return both Games and DLCs. To disable DLCs use the includeDLCs
method
config.includeDLCs(false);
By default, GameFinder will include screenshots marked as mature content on Steam. To disable this, do the following:
config.allowSteamMatureContentScreenshots(false);
NOTE: As stated above, this is ONLY for Steam and ONLY applies to the screenshots that are accessible in the Game object.
By default, GameFinder's locale is set to en-US. To change this use the setLocale
method
config.setLocale(Locale.CANADA);
Restrictions: A locale must have both valid combination of a two-letter language code and a two-letter country code. Otherwise, a LocaleException
will be thrown.
NOTE: If a Game's description is not translated to the language specified in your locale, it will default to English.
By default, all CompletableFutures are executed on threads found in ForkJoinPool.commonPool()
. If you would like to change this you use the setExecutorService
method:
config.setExecutorService(Executors.newFixedThreadPool(5));
By default, GOG will only return USD. To change this, do the following: This is not recommended!
config.useGOGLocaleCookie(true);
If GOG does not support the currency used by the country defined in the locale, it will not return a 0.00.
To combat confusion, the originalPrice
property in the Game object will be set to N/A (Unsupported Locale)
.
Additionally, GOG will sometimes the incorrect currency. I believe this is due to how GOG caches game listings, but I am not sure.
Wherever possible, I try to use publicly accessible APIs provided by each platform. These APIs are usually undocumented and don't always have all the required information.
EpicGames: Nothing
Steam:
- The discount expiration time
GOG:
- The description
- The original price
- The discount expiration end time
- Miscellaneous
storeMedia
andmedia
entries
So much information is web-scraped from GOG because GOG embeds a JSON object inside the HTML of each game listing containing all the necessary data. This data is otherwise spread across several API endpoints, except for the expiration end time (which is only available from the game listing). Furthermore, the price endpoint is historically unreliable and returns blatantly incorrect information on occasion.