Compare commits

...

17 Commits

Author SHA1 Message Date
Jeddunk
3bf33b0d4c Update 'README.md' 2020-12-30 11:03:47 +00:00
da947e1f51 Code refactoring, improved logging, Drone CI improvements 2020-12-03 00:02:59 +01:00
21a7ec98dd Code changes 2020-10-24 00:45:10 +02:00
992f2fb20c Fixed and enabled SteamDB DLC functionality 2020-10-21 15:47:58 +02:00
26872ec8fb Update CreamAPI to 4.5.0.0 2020-10-21 13:24:58 +02:00
452e78b1ed Disable SteamDB checkbox 2020-10-21 13:14:03 +02:00
cce8bbe513 Fixed an issue where games with an age check could not be parsed 2020-10-21 13:10:42 +02:00
5043ffefff add build status to README.md 2020-10-14 14:37:49 +02:00
032a85600f maven config 2020-10-14 14:32:19 +02:00
4a8ecd32ac updated resources location 2020-10-14 14:02:46 +02:00
6afa33db75 README.md update 2020-10-14 13:46:43 +02:00
7c5329fd54 better logging 2020-10-14 13:43:29 +02:00
b7ec6a62a3 Added toggle for SteamDB DLC
Added custom fonts
2020-10-07 14:42:11 +02:00
bd70c814b9 fixed dumb error 2020-10-07 12:49:54 +02:00
272b1d0833 eh whatevs sry future me 2020-10-07 10:36:37 +02:00
1fdf90da8a code structure changes
drone ci
2020-09-27 17:48:13 +02:00
79bda2b1fd Minor fix 2020-08-30 18:08:28 +02:00
48 changed files with 1244 additions and 603 deletions

40
.drone.yml Normal file
View File

@ -0,0 +1,40 @@
kind: pipeline
type: docker
name: default
steps:
- name: build
image: maven:3-amazoncorretto-8
commands:
- mvn install
- name: gitea_release
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_token
base_url: https://git.jeddunk.xyz
files:
- auto-cream-api-*.zip
checksum:
- md5
- sha1
- sha256
- sha512
- adler32
- crc32
when:
event:
- tag
- name: discord_webhook
image: appleboy/drone-discord
settings:
webhook_id:
from_secret: discord_webhook_id
webhook_token:
from_secret: discord_webhook_token
message: >
{{#success build.status}}
build {{build.number}} succeeded.
{{else}}
build {{build.number}} failed.
{{/success}}

5
.gitignore vendored
View File

@ -159,5 +159,6 @@ $RECYCLE.BIN/
/steamapps.json /steamapps.json
/test.json /test.json
/steam_api.md5 /steam_api.md5
/src/main/java/util/env/Default.java /src/main/java/xyz/jeddunk/autocreamapi/util/env/Default.java
/src/main/java/GetListOfDlc.java /src/main/java/xyz/jeddunk/autocreamapi/GetListOfDlc.java
dist/

View File

@ -0,0 +1,6 @@
This folder contains libraries copied from the "auto-cream-api" project.
It is managed by the CheckStyle-IDEA IDE plugin.
Do not modify this folder while the IDE is running.
When the IDE is stopped, you may delete this folder at any time. It will be recreated as needed.
In order to prevent the CheckStyle-IDEA IDE plugin from creating this folder,
uncheck the "Copy libraries from project directory" option in the CheckStyle-IDEA settings dialog.

View File

@ -13,7 +13,7 @@
<component name="ProjectKey"> <component name="ProjectKey">
<option name="state" value="project://e79810c8-c5c8-43b1-b19c-90c1f4095425" /> <option name="state" value="project://e79810c8-c5c8-43b1-b19c-90c1f4095425" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8 (amazon)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -1,5 +1,10 @@
# Auto-CreamAPI # Auto-CreamAPI
## Development is continuing [here](https://git.jeddunk.xyz/jeddunk/auto-creamapi-2)! However you're still welcome to use this version.
[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/H2H4330U3)
[![Build Status](https://ci.jeddunk.xyz/api/badges/jeddunk/auto-cream-api/status.svg)](https://ci.jeddunk.xyz/jeddunk/auto-cream-api)
Set your game automatically up for use with CreamAPI. Set your game automatically up for use with CreamAPI.
![](https://jeddunk.xyz/javaw_nLB130vOCY.png) ![](https://jeddunk.xyz/javaw_nLB130vOCY.png)
@ -38,7 +43,7 @@ Download the latest release and extract it into any folder (e.g. `%USERPROFILE%\
* Select a language and tick the options if needed. * Select a language and tick the options if needed.
* Click on *"Save"*. * Click on *"Save"*.
### Java 11 ### Java 11/Java 14
*WIP* *WIP*
@ -54,7 +59,15 @@ The following dependencies are licensed under the Apache License 2.0:
* gson * gson
* Apache Commons BeanUtils * Apache Commons BeanUtils
* Apache Commons Configuration * Apache Commons Configuration
* The Roboto font family
The following dependencies are licensed under the MIT License: The following dependencies are licensed under the MIT License:
* jsoup * jsoup
* Unirest-Java * Unirest-Java
* slf4j
* Copy Rename Maven Plugin
The following dependencies are licensed under the GPL2 License:
* fuzzywuzzy
Logback is dual-licensed under the EPL v1.0 and the LGPL 2.1.

View File

@ -12,11 +12,11 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: me.xdrop:fuzzywuzzy:1.3.1" level="project" />
<orderEntry type="library" name="Maven: com.jfoenix:jfoenix:8.0.8" level="project" /> <orderEntry type="library" name="Maven: com.jfoenix:jfoenix:8.0.8" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-configuration2:2.6" level="project" /> <orderEntry type="library" name="Maven: org.apache.commons:commons-configuration2:2.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.9" level="project" /> <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.9" level="project" />
@ -36,5 +36,67 @@
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpasyncclient:4.1.4" level="project" /> <orderEntry type="library" name="Maven: org.apache.httpcomponents:httpasyncclient:4.1.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore-nio:4.4.10" level="project" /> <orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore-nio:4.4.10" level="project" />
<orderEntry type="library" name="Maven: me.xdrop:fuzzywuzzy:1.3.1" level="project" /> <orderEntry type="library" name="Maven: me.xdrop:fuzzywuzzy:1.3.1" level="project" />
<orderEntry type="library" name="Maven: com.coderplus.maven.plugins:copy-rename-maven-plugin:1.0.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-model:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-project:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-settings:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-profile:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-artifact-manager:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-registry:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1" level="project" />
<orderEntry type="library" name="Maven: junit:junit:3.8.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-core:2.0.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-file:1.0-beta-2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-parameter-documenter:2.0.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-webdav:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: slide:slide-webdavlib:2.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: commons-httpclient:commons-httpclient:2.0.2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: jdom:jdom:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: de.zeigermann.xml:xml-im-exporter:1.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-http-lightweight:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-http-shared:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: jtidy:jtidy:4aug2000r7-dev" level="project" />
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.0.b2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven.reporting:maven-reporting-api:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven.doxia:doxia-sink-api:1.0-alpha-10" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven.wagon:wagon-provider-api:1.0-beta-2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-repository-metadata:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-error-diagnostics:2.0.9" level="project" />
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-ssh-external:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-ssh-common:1.0-beta-2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-descriptor:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-interactivity-api:1.0-alpha-4" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-monitor:2.0.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-ssh:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.jcraft:jsch:0.1.27" level="project" />
<orderEntry type="library" name="Maven: classworlds:classworlds:1.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-api:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-artifact:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-utils:1.5.8" level="project" />
<orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-build-api:0.0.7" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.fusesource.jansi:jansi:1.18" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit:2.44.0" level="project" />
<orderEntry type="library" name="Maven: xalan:xalan:2.7.2" level="project" />
<orderEntry type="library" name="Maven: xalan:serializer:2.7.2" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit-core-js:2.44.0" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:neko-htmlunit:2.44.0" level="project" />
<orderEntry type="library" name="Maven: xerces:xercesImpl:2.12.0" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit-cssparser:1.6.0" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.8.0" level="project" />
<orderEntry type="library" name="Maven: commons-net:commons-net:3.7.1" level="project" />
<orderEntry type="library" name="Maven: org.brotli:dec:0.1.2" level="project" />
<orderEntry type="library" name="Maven: com.shapesecurity:salvation2:3.0.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.32.v20200930" level="project" />
</component> </component>
</module> </module>

108
pom.xml
View File

@ -21,16 +21,28 @@
<groupId>xyz.jeddunk</groupId> <groupId>xyz.jeddunk</groupId>
<artifactId>auto-cream-api</artifactId> <artifactId>auto-cream-api</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.2.2</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<dist>${project.basedir}/dist</dist>
</properties> </properties>
<build> <build>
<plugins> <plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
<filesets>
<fileset>
<directory>dist</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin> <plugin>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>2.4</version> <version>2.4</version>
@ -42,11 +54,11 @@
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version> <version>2.2.2</version>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
<mainClass>Main</mainClass> <mainClass>xyz.jeddunk.autocreamapi.Main</mainClass>
</manifest> </manifest>
</archive> </archive>
<descriptorRefs> <descriptorRefs>
@ -63,6 +75,72 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0.1</version>
<executions>
<execution>
<id>install-copy</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<overWrite>true</overWrite>
<fileSets>
<fileSet>
<sourceFile>${project.build.directory}/${project.artifactId}-${project.version}-jar-with-dependencies.jar</sourceFile>
<destinationFile>${dist}/${project.artifactId}.jar</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/README.md</sourceFile>
<destinationFile>${dist}/README.md</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/steam_api.dll</sourceFile>
<destinationFile>${dist}/steam_api.dll</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/steam_api64.dll</sourceFile>
<destinationFile>${dist}/steam_api64.dll</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/version.txt</sourceFile>
<destinationFile>${dist}/version.txt</destinationFile>
</fileSet>
</fileSets>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>install-zip</id>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<zip destfile="${project.basedir}/${project.artifactId}-${project.version}.zip" basedir="${dist}"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
@ -72,7 +150,7 @@
<enabled>false</enabled> <enabled>false</enabled>
</snapshots> </snapshots>
<id>bintray-jerady-maven</id> <id>bintray-jerady-maven</id>
<name>bintray</name> <name>bintray-jerady</name>
<url>https://dl.bintray.com/jerady/maven</url> <url>https://dl.bintray.com/jerady/maven</url>
</repository> </repository>
</repositories> </repositories>
@ -82,7 +160,7 @@
<enabled>false</enabled> <enabled>false</enabled>
</snapshots> </snapshots>
<id>bintray-jerady-maven</id> <id>bintray-jerady-maven</id>
<name>bintray-plugins</name> <name>bintray-jerady-plugins</name>
<url>https://dl.bintray.com/jerady/maven</url> <url>https://dl.bintray.com/jerady/maven</url>
</pluginRepository> </pluginRepository>
</pluginRepositories> </pluginRepositories>
@ -136,5 +214,25 @@
<artifactId>fuzzywuzzy</artifactId> <artifactId>fuzzywuzzy</artifactId>
<version>1.3.1</version> <version>1.3.1</version>
</dependency> </dependency>
<dependency>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.44.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,191 +0,0 @@
/*
* Auto-CreamAPI
* Copyright (C) 2020 Jeddunk
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
package util;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import me.xdrop.fuzzywuzzy.FuzzySearch;
import me.xdrop.fuzzywuzzy.model.BoundExtractedResult;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import pojo.App;
import pojo.SteamAppsList;
import util.env.MainEnv;
import java.io.*;
import java.lang.reflect.Type;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
public class SteamAppsListCache {
private SteamAppsList list = new SteamAppsList();
private final File cacheFile = new File("steamapps.json");
private MainEnv env;
//private String key;
public SteamAppsListCache() {
try {
Class<?> envDefault = Class.forName("util.env.Default");
env = (MainEnv) envDefault.newInstance();
// System.out.println(env.getKey());
} catch (ClassNotFoundException e) {
env = new MainEnv();
} catch (IllegalAccessException | InstantiationException e) {
// Only thrown by newInstance()
e.printStackTrace();
}
//boolean fileFound = true;
try {
getListFromFile();
} catch (FileNotFoundException e) {
System.err.println("File does not exist, trying to create steamapps.json for the first time...");
//fileFound = false;
sync();
} catch (JsonSyntaxException e) {
System.err.println("File seems to be corrupt, trying to recreate steamapps.json...");
//fileFound = false;
sync();
}
if (Instant.now().isAfter(list.getTimestamp().plus(Duration.ofDays(3)))) {
System.err.println("List in file is not recent!");
sync();
}
}
private void sync() {
getListFromApi();
try {
saveListToFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public App getGame(int appId) {
return list.getSteamAppsList().stream().filter(app -> app.getAppId() == appId).findFirst().orElse(null);
}
@SuppressWarnings("unused")
public App getGame(String name) {
return list.getSteamAppsList().stream()
.filter(app -> app.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
}
public List<App> findListOfGames(String name) {
List<BoundExtractedResult<App>> match = FuzzySearch.extractSorted(name, list.getSteamAppsList(), app ->
app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""), 80);
List<App> collect = match.stream().map(BoundExtractedResult::getReferent).collect(Collectors.toList());
for (App app : collect) {
if (app.getName().replaceAll("[^a-zA-Z0-9\\s+]", "")
.equalsIgnoreCase(name.replaceAll("[^a-zA-Z0-9\\s+]", ""))) {
collect = new ArrayList<>();
collect.add(app);
break;
}
}
return collect;
}
private void getListFromApi() {
System.out.println("Trying to get SteamAppList from API...");
List<App> apps = getApps();
list.setTimestamp(Instant.now());
list.setSteamAppsList(apps);
}
private List<App> getApps() {
HttpResponse<String> httpResponse =
Unirest.get("https://api.steampowered.com/IStoreService/GetAppList/v1/" +
"?key=" + env.getKey() + "&include_games=1&max_results=50000").asString();
return new Gson()
.fromJson(httpResponse.getBody(), App.Rezponze.Download.class)
.getResponse().getApps();
}
private void saveListToFile() throws IOException {
System.out.println("Trying to save SteamAppList to file (" + cacheFile.getAbsolutePath() + ")...");
Gson gson = new Gson();
String jsonString = gson.toJson(list);
BufferedWriter fOut = new BufferedWriter(new FileWriter(cacheFile));
fOut.write(jsonString);
fOut.close();
System.out.println("Successfully saved SteamAppList to file (" + cacheFile.getAbsolutePath() + ")...");
}
private void getListFromFile() throws FileNotFoundException, JsonSyntaxException {
System.out.println("Trying to get SteamAppList from file (" + cacheFile.getAbsolutePath() + ")...");
BufferedReader fIn = new BufferedReader(new FileReader(cacheFile));
String json = fIn.lines().collect(Collectors.joining());
final Type type = new TypeToken<SteamAppsList>() {
}.getType();
Gson gson = new Gson();
list = gson.fromJson(json, type);
System.out.println("Successfully got SteamAppList from file (" + cacheFile.getAbsolutePath() + ")...");
}
public LinkedHashMap<Number, String> getDlcMap(String appId) throws IOException{
Map<Integer, String> steamStoreDLCs = new HashMap<>();
Map<Integer, String> steamDbDLCs = new HashMap<>();
//StringBuilder sb = new StringBuilder();
try {
// Steam Store
Document steamDoc = Jsoup
.connect("https://store.steampowered.com/app/" + appId + "/")
.get();
Elements steamDLCs = steamDoc.getElementsByClass("game_area_dlc_row");
for (Element dlc : steamDLCs) {
String dlc_id = dlc.attr("data-ds-appid");
String dlc_name = dlc
.getElementsByClass("game_area_dlc_name")
.text().replace("\n", "").trim();
steamStoreDLCs.put(Integer.parseInt(dlc_id), dlc_name);
}
// SteamDB
Document steamDbDoc = Jsoup
.connect("https://steamdb.info/app/" + appId + "/dlc/")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0")
.get();
Element steamDbDlcSection = steamDbDoc.getElementById("dlc");
Elements steamDbDLCElements = steamDbDlcSection.getElementsByClass("app");
for (Element dlc : steamDbDLCElements) {
String dlc_id = dlc.attr("data-appid");
String dlc_name = "Unknown DLC " + dlc_id;
Elements td = dlc.getElementsByTag("td");
if (!td.isEmpty()) {
dlc_name = td.get(1).text().replace("\n", "").trim();
}
steamDbDLCs.put(Integer.parseInt(dlc_id), dlc_name);
}
} catch (NullPointerException e) {
// ignore
}
Map<Integer, String> allDLCs = new HashMap<>(steamStoreDLCs);
steamDbDLCs.forEach(allDLCs::putIfAbsent);
return allDLCs.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
}
}

View File

@ -13,6 +13,8 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package xyz.jeddunk.autocreamapi;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView; import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -32,13 +34,15 @@ import javafx.scene.control.*;
import javafx.stage.*; import javafx.stage.*;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.configuration2.ex.ConfigurationException;
import org.jsoup.HttpStatusException; import org.slf4j.Logger;
import pojo.App; import org.slf4j.LoggerFactory;
import util.CreamApiConfig; import xyz.jeddunk.autocreamapi.pojo.App;
import util.CreamApiDllHandler; import xyz.jeddunk.autocreamapi.util.CreamApiConfig;
import util.SteamAppsListCache; import xyz.jeddunk.autocreamapi.util.CreamApiDllHandler;
import xyz.jeddunk.autocreamapi.util.SteamAppsListCache;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
@ -51,31 +55,29 @@ import java.util.stream.Stream;
public class Controller implements Initializable { public class Controller implements Initializable {
final Logger logger = LoggerFactory.getLogger(Controller.class);
private static final String GLYPH_FAILURE = "TIMES";
private static final String GLYPH_SUCCESS = "CHECK";
private static final Color COLOR_FAILURE = Color.web("#E53935");
private static final Color COLOR_SUCCESS = Color.web("#43A047");
private static final String REGEX = "(?<steamApiDll>steam_api(?:64)?.dll)$"; private static final String REGEX = "(?<steamApiDll>steam_api(?:64)?.dll)$";
public Label creamApiDllApplied;
public Label creamApiConfigExists;
public FontAwesomeIconView creamApiDllAppliedIcon;
public FontAwesomeIconView creamApiConfigExistsIcon;
private CreamApiDllHandler handler = null; private CreamApiDllHandler handler = null;
private final CreamApiConfig config = CreamApiConfig.getInstance();
private final SteamAppsListCache cache = new SteamAppsListCache();
private boolean is64Bit; private boolean is64Bit;
private boolean isSameFile; private boolean isSameFile;
{
try {
handler = CreamApiDllHandler.getInstance();
} catch (IOException e) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("CreamAPI DLLs missing!");
alert.setHeaderText("CreamAPI DLL files can't be found!");
alert.setContentText("Please download CreamAPI and extract the non-log " +
"version in the same folder as Auto-CreamAPI!\nThe program will now close.");
alert.showAndWait();
System.exit(10);
}
}
private final CreamApiConfig config = CreamApiConfig.getInstance(); @FXML
private final SteamAppsListCache cache = new SteamAppsListCache(); public Label creamApiDllApplied;
@FXML
public Label creamApiConfigExists;
@FXML
public FontAwesomeIconView creamApiDllAppliedIcon;
@FXML
public FontAwesomeIconView creamApiConfigExistsIcon;
@FXML @FXML
public Label state_label; public Label state_label;
@FXML @FXML
@ -95,6 +97,8 @@ public class Controller implements Initializable {
@FXML @FXML
public CheckBox unlock_all_checkbox; public CheckBox unlock_all_checkbox;
@FXML @FXML
public CheckBox steamdb_dlc_checkbox;
@FXML
public Button reset_button; public Button reset_button;
@FXML @FXML
public Button save_button; public Button save_button;
@ -103,15 +107,32 @@ public class Controller implements Initializable {
@FXML @FXML
public Button path_button; public Button path_button;
@FXML @FXML
public Button retrieveDlcList_button; public Button getDlcList_button;
private String steamApiPathString; private String steamApiPathString;
{
try {
handler = CreamApiDllHandler.getInstance();
} catch (FileNotFoundException e) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("CreamAPI DLLs missing!");
alert.setHeaderText("CreamAPI DLL files can't be found!");
alert.setContentText("Please download CreamAPI and extract the non-log " +
"version in the same folder as Auto-CreamAPI!\nThe program will now close.");
alert.showAndWait();
System.exit(2);
} catch (IOException e) {
e.printStackTrace();
}
}
public Controller() { public Controller() {
} }
@FXML @FXML
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
steamdb_dlc_checkbox.setSelected(true);
appId_textfield.textProperty().addListener(appIdChangesGameName()); appId_textfield.textProperty().addListener(appIdChangesGameName());
game_name_textfield.setOnKeyReleased(event -> { game_name_textfield.setOnKeyReleased(event -> {
KeyCode code = event.getCode(); KeyCode code = event.getCode();
@ -123,10 +144,22 @@ public class Controller implements Initializable {
language_combobox.setTooltip(new Tooltip()); language_combobox.setTooltip(new Tooltip());
language_combobox.setEditable(false); language_combobox.setEditable(false);
new ComboBoxAutoComplete<>(language_combobox); new ComboBoxAutoComplete<>(language_combobox);
//retrieveDlcList_button.setDisable(true); // WIP dlc_textarea.setPromptText("List of DLC...\r0000 = DLC Name");
generate_tooltips(); generate_tooltips();
fix_dlc_textarea_prompt_text();
reset(true); reset(true);
state_label.setText("Ready.");
}
private void generate_tooltips() {
Tooltip extra_protection_tooltip = new Tooltip("\"extra protection\"");
extra_protection_checkbox.setTooltip(extra_protection_tooltip);
Tooltip.install(extra_protection_checkbox, extra_protection_tooltip);
Tooltip steamdb_dlc_tooltip = new Tooltip("Additionally get DLC data from SteamDB.\n" +
"Especially useful for DLC that is not listed on the Steam Store.\n" +
"This sometimes doesn't work because SteamDB may block access for scrapers.");
steamdb_dlc_checkbox.setTooltip(steamdb_dlc_tooltip);
Tooltip.install(steamdb_dlc_checkbox, steamdb_dlc_tooltip);
} }
private void read() { private void read() {
@ -141,8 +174,8 @@ public class Controller implements Initializable {
} }
private void emptyFields() { private void emptyFields() {
creamApiDllAppliedIcon.setGlyphName("TIMES"); /*setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_FAILURE, GLYPH_FAILURE);
creamApiConfigExistsIcon.setGlyphName("TIMES"); setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_FAILURE, GLYPH_FAILURE);*/
appId_textfield.setText(""); appId_textfield.setText("");
dlc_textarea.setText(""); dlc_textarea.setText("");
game_name_textfield.setText(""); game_name_textfield.setText("");
@ -152,16 +185,6 @@ public class Controller implements Initializable {
unlockAll_disableDlcTextArea(); unlockAll_disableDlcTextArea();
} }
private void fix_dlc_textarea_prompt_text() {
dlc_textarea.setPromptText("List of DLC...\r0000 = DLC Name");
}
private void generate_tooltips() {
Tooltip extra_protection_tooltip = new Tooltip("\"extra protection\"");
extra_protection_checkbox.setTooltip(extra_protection_tooltip);
Tooltip.install(extra_protection_checkbox, extra_protection_tooltip);
}
private ChangeListener<String> appIdChangesGameName() { private ChangeListener<String> appIdChangesGameName() {
return (observable, oldValue, newValue) -> { return (observable, oldValue, newValue) -> {
int appId; int appId;
@ -192,10 +215,10 @@ public class Controller implements Initializable {
state_label.setText("Successfully reset all fields!"); state_label.setText("Successfully reset all fields!");
} }
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
System.err.println("Error reading cream_api.ini! " + logger.warn("Error reading cream_api.ini! " +
"This can be ignored if setting up CreamAPI for the first time."); "This can be ignored if setting up CreamAPI for the first time.");
} catch (NullPointerException e) { } catch (NullPointerException e) {
System.err.println("Can't fill out fields, no configuration file set!"); logger.warn("Can't fill out fields, no configuration file set!");
if (!silent) { if (!silent) {
state_label.setText("Could not reset fields, no configuration file set!"); state_label.setText("Could not reset fields, no configuration file set!");
} }
@ -204,8 +227,6 @@ public class Controller implements Initializable {
} }
private void updateIndicators() { private void updateIndicators() {
Color colorSuccess = Color.web("#43A047");
Color colorFailure = Color.web("#E53935");
try { try {
is64Bit = false; is64Bit = false;
if (!steamApiPathString.isEmpty()) { if (!steamApiPathString.isEmpty()) {
@ -217,91 +238,48 @@ public class Controller implements Initializable {
String md5 = DigestUtils.md5Hex(is); String md5 = DigestUtils.md5Hex(is);
isSameFile = Objects.equals(md5, handler.getDllMd5(is64Bit)); isSameFile = Objects.equals(md5, handler.getDllMd5(is64Bit));
if (isSameFile) { if (isSameFile) {
creamApiDllApplied.setTextFill(colorSuccess); setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_SUCCESS, GLYPH_SUCCESS);
creamApiDllAppliedIcon.setFill(colorSuccess);
creamApiDllAppliedIcon.setGlyphName("CHECK");
} else { } else {
creamApiDllApplied.setTextFill(colorFailure); setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_FAILURE, GLYPH_FAILURE);
creamApiDllAppliedIcon.setFill(colorFailure);
creamApiDllAppliedIcon.setGlyphName("TIMES");
} }
Path configPath = Paths.get(config.getPath()); Path configPath = Paths.get(config.getPath());
if (Files.exists(configPath) && Files.size(configPath) > 0L) { if (Files.exists(configPath) && Files.size(configPath) > 0L) {
creamApiConfigExists.setTextFill(colorSuccess); setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_SUCCESS, GLYPH_SUCCESS);
creamApiConfigExistsIcon.setFill(colorSuccess);
creamApiConfigExistsIcon.setGlyphName("CHECK");
} else { } else {
creamApiConfigExists.setTextFill(colorFailure); setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_FAILURE, GLYPH_FAILURE);
creamApiConfigExistsIcon.setFill(colorFailure);
creamApiConfigExistsIcon.setGlyphName("TIMES");
} }
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println("Error! Resetting visual indicators!"); logger.warn("Resetting visual indicators!");
creamApiDllApplied.setTextFill(colorFailure); setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_FAILURE, GLYPH_FAILURE);
creamApiDllAppliedIcon.setFill(colorFailure); setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_FAILURE, GLYPH_FAILURE);
creamApiDllAppliedIcon.setGlyphName("TIMES");
creamApiConfigExists.setTextFill(colorFailure);
creamApiConfigExistsIcon.setFill(colorFailure);
creamApiConfigExistsIcon.setGlyphName("TIMES");
} }
} }
private void setIndicator(Label label, FontAwesomeIconView icon, Color color, String glyphName) {
label.setTextFill(color);
icon.setFill(color);
icon.setGlyphName(glyphName);
}
public void save() { public void save() {
Service<Void> s = new Service<Void>() { saveService().start();
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() {
try {
setUpCreamApi();
config.setDlcListFromString(dlc_textarea.getText());
config.setAppId(Integer.parseInt(appId_textfield.getText()));
config.setExtraProtection(extra_protection_checkbox.isSelected());
config.setForceOffline(offline_checkbox.isSelected());
config.setUnlockAll(unlock_all_checkbox.isSelected());
config.setLanguage(language_combobox.getValue());
config.sync();
} catch (IOException | ConfigurationException e) {
e.printStackTrace();
cancel();
} catch (NullPointerException e) {
System.err.println("No configuration file set!");
cancel();
}
updateIndicators();
return null;
}
};
}
};
s.setOnRunning(event -> {
setDisableAllButtons(true);
state_label.setText("Saving...");
});
s.setOnSucceeded(event -> {
setDisableAllButtons(false);
state_label.setText("Saved successfully!");
});
s.setOnCancelled(event -> {
setDisableAllButtons(false);
state_label.setText("Could not save configuration file!");
});
s.start();
} }
public void getAppId() { public void getAppId() {
final List<App> games = cache.findListOfGames(game_name_textfield.getText()); final List<App> games = cache.findListOfGames(game_name_textfield.getText());
if (games.isEmpty()) { if (games.isEmpty()) {
logger.info("No game name was given, setting AppID to \"-1\"!");
appId_textfield.setText("-1"); appId_textfield.setText("-1");
} else if (games.size() == 1) { } else if (games.size() == 1) {
App game = games.get(0); App game = games.get(0);
game_name_textfield.setText(game.getName()); game_name_textfield.setText(game.getName());
appId_textfield.setText(String.valueOf(game.getAppId())); appId_textfield.setText(String.valueOf(game.getAppId()));
} else { } else {
logger.info("Multiple results found, opening search result window!");
try { try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("searchResultWindow.fxml")); URL resource = ClassLoader.getSystemResource("xyz/jeddunk/autocreamapi/searchResultWindow.fxml");
FXMLLoader fxmlLoader = new FXMLLoader(resource);
Parent root1 = fxmlLoader.load(); Parent root1 = fxmlLoader.load();
SearchResultWindowController c = fxmlLoader.getController(); SearchResultWindowController c = fxmlLoader.getController();
@ -322,7 +300,7 @@ public class Controller implements Initializable {
public void unlockAll_disableDlcTextArea() { public void unlockAll_disableDlcTextArea() {
dlc_textarea.setDisable(unlock_all_checkbox.isSelected()); dlc_textarea.setDisable(unlock_all_checkbox.isSelected());
retrieveDlcList_button.setDisable(unlock_all_checkbox.isSelected()); getDlcList_button.setDisable(unlock_all_checkbox.isSelected());
} }
/** /**
@ -330,6 +308,99 @@ public class Controller implements Initializable {
* also lists DLC not available for purchase. * also lists DLC not available for purchase.
*/ */
public void getDlcList() { public void getDlcList() {
getDlcListService().start();
}
public void openFileChooser() {
FileChooser chooser = new FileChooser();
chooser.setTitle("Choose steam_api(64).dll...");
FileChooser.ExtensionFilter filter =
new FileChooser.ExtensionFilter("Steam API DLL",
"steam_api.dll", "steam_api64.dll");
chooser.getExtensionFilters().add(filter);
File file = chooser.showOpenDialog(path_button.getScene().getWindow());
try {
config.setConfig(file.getParent() + "\\cream_api.ini");
path_textfield.setText(file.getParent());
steamApiPathString = file.getAbsolutePath();
} catch (ConfigurationException | IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
logger.warn("Could not set config file location! Did you cancel the file chooser?");
}
emptyFields();
reset(true);
logger.info("File chosen: " + steamApiPathString);
logger.info("Ready.");
state_label.setText("Ready.");
}
/**
* Check if CreamAPI version of DLL is there, if not, rename original to steam_api(64)_o.dll and copy
* CreamAPI DLL to the path. Also looks for alternative Steam DLL (which means it patches both 64 and 32 bit
* DLLs at once if found)
*
* @throws IOException If file is missing or not accessible/modifiable.
*/
private void setUpCreamApi() throws IOException {
logger.info("Setting up DLL...");
Path path = Paths.get(steamApiPathString);
copyDllFile(path, isSameFile);
findAdditionalDll(path);
logger.info("Set up DLL successfully!");
}
private void findAdditionalDll(Path path) throws IOException {
String aDllString = is64Bit ? "\\steam_api.dll" : "\\steam_api64.dll";
Path dir = path.getParent();
Path aDll = Paths.get(dir.toString() + aDllString);
if (Files.exists(aDll)) {
logger.info("Additional DLL found: (" + aDll.toString() + ")!");
InputStream is = Files.newInputStream(aDll);
String md5 = DigestUtils.md5Hex(is);
boolean aIsSameFile = Objects.equals(md5, handler.getDllMd5(!is64Bit));
copyDllFile(aDll, aIsSameFile);
}
}
private void copyDllFile(Path path, boolean isSameFile) throws IOException {
if (!isSameFile) {
String pathOrigString = steamApiPathString;
String replacement = is64Bit ? "steam_api64_o.dll" : "steam_api_o.dll";
pathOrigString =
pathOrigString
.replaceFirst(REGEX, replacement);
Path pathOrig = Paths.get(pathOrigString);
if (!Files.exists(pathOrig)) {
logger.info("Renaming " + path.toString() + " to " + replacement + "...");
Files.move(path, pathOrig);
} else {
logger.info(pathOrigString + " already exists!");
String pathBakString = steamApiPathString;
pathBakString =
pathBakString
.replaceFirst(REGEX, is64Bit ? "steam_api64.dll.backup" : "steam_api.dll.backup");
Path pathBak = Paths.get(pathBakString);
Files.move(path, pathBak, StandardCopyOption.REPLACE_EXISTING);
}
logger.info("Copying CreamAPI DLL to " + path.toString() + " ...");
Files.copy(handler.getDllPath(is64Bit), path);
}
}
private void setDisableAllButtons(boolean b) {
reset_button.setDisable(b);
save_button.setDisable(b);
getAppId_button.setDisable(b);
path_button.setDisable(b);
getDlcList_button.setDisable(b);
}
public void resetFromButton() {
reset(false);
}
private Service<Void> saveService() {
Service<Void> s = new Service<Void>() { Service<Void> s = new Service<Void>() {
@Override @Override
protected Task<Void> createTask() { protected Task<Void> createTask() {
@ -337,22 +408,54 @@ public class Controller implements Initializable {
@Override @Override
protected Void call() { protected Void call() {
try { try {
Map<Number, String> collect = cache.getDlcMap(appId_textfield.getText()); setUpCreamApi();
config.setDlcListFromString(dlc_textarea.getText());
config.setAppId(Integer.parseInt(appId_textfield.getText()));
config.setExtraProtection(extra_protection_checkbox.isSelected());
config.setForceOffline(offline_checkbox.isSelected());
config.setUnlockAll(unlock_all_checkbox.isSelected());
config.setLanguage(language_combobox.getValue());
config.sync();
} catch (IOException | ConfigurationException e) {
e.printStackTrace();
cancel();
} catch (NullPointerException e) {
logger.warn("No configuration file set!");
cancel();
}
updateIndicators();
return null;
}
};
}
};
s.setOnRunning(event -> {
setDisableAllButtons(true);
state_label.setText("Saving...");
});
s.setOnSucceeded(event -> {
setDisableAllButtons(false);
state_label.setText("Saved successfully!");
});
s.setOnCancelled(event -> {
setDisableAllButtons(false);
state_label.setText("Could not save configuration file!");
});
return s;
}
private Service<Void> getDlcListService() {
Service<Void> s = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() {
Map<Integer, String> collect =
cache.getDlcMap(appId_textfield.getText(), steamdb_dlc_checkbox.isSelected());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
collect.forEach((k, v) -> sb.append(k).append("=").append(v).append("\n")); collect.forEach((k, v) -> sb.append(k).append("=").append(v).append("\n"));
dlc_textarea.setText(sb.toString()); dlc_textarea.setText(sb.toString());
} catch (HttpStatusException e) {
if (e.getStatusCode() == 404) {
System.err.println("App ID empty or not found! (HTTP Status Code: 404)");
} else {
// e.printStackTrace();
System.err.println("STATUS CODE: " + e.getStatusCode());
}
cancel();
} catch (IOException e) {
e.printStackTrace();
cancel();
}
return null; return null;
} }
}; };
@ -370,89 +473,7 @@ public class Controller implements Initializable {
setDisableAllButtons(false); setDisableAllButtons(false);
state_label.setText("Could not get list of DLCs!"); state_label.setText("Could not get list of DLCs!");
}); });
s.start(); return s;
}
public void openFileChooser() {
FileChooser chooser = new FileChooser();
chooser.setTitle("Choose steam_api(64).dll...");
FileChooser.ExtensionFilter filter =
new FileChooser.ExtensionFilter("Steam API DLL",
"steam_api.dll", "steam_api64.dll");
chooser.getExtensionFilters().add(filter);
final File file = chooser.showOpenDialog(path_button.getScene().getWindow());
try {
config.setConfig(file.getParent() + "\\cream_api.ini");
} catch (ConfigurationException | IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
System.err.println("Could not set config file location! Did you cancel the file chooser?");
}
path_textfield.setText(file.getParent());
steamApiPathString = file.getAbsolutePath();
emptyFields();
reset(true);
state_label.setText("Ready.");
}
/**
* Check if CreamAPI version of DLL is there, if not, rename original to steam_api(64)_o.dll and copy
* CreamAPI DLL to the path. Also looks for alternative Steam DLL (which means it patches both 64 and 32 bit
* DLLs at once if found)
*
* @throws IOException If file is missing or not accessible/modifiable.
*/
private void setUpCreamApi() throws IOException {
Path path = Paths.get(steamApiPathString);
copyDllFile(path, isSameFile);
findAdditionalDll(path);
}
private void findAdditionalDll(Path path) throws IOException {
String secondDllString = is64Bit ? "\\steam_api.dll" : "\\steam_api64.dll";
Path dir = path.getParent();
Path secondDll = Paths.get(dir.toString() + secondDllString);
if (Files.exists(secondDll)) {
System.out.println("Alternative DLL found!");
InputStream is = Files.newInputStream(secondDll);
String md5 = DigestUtils.md5Hex(is);
boolean isSameFile1 = Objects.equals(md5, handler.getDllMd5(!is64Bit));
copyDllFile(secondDll, isSameFile1);
}
}
private void copyDllFile(Path path, boolean isSameFile) throws IOException {
if (!isSameFile) {
String pathOrigString = steamApiPathString;
pathOrigString =
pathOrigString
.replaceFirst(REGEX, is64Bit ? "steam_api64_o.dll" : "steam_api_o.dll");
Path pathOrig = Paths.get(pathOrigString);
if (!Files.exists(pathOrig)) {
Files.move(path, pathOrig);
} else {
String pathBakString = steamApiPathString;
pathBakString =
pathBakString
.replaceFirst(REGEX, is64Bit ? "steam_api64.dll.backup" : "steam_api.dll.backup");
Path pathBak = Paths.get(pathBakString);
Files.move(path, pathBak, StandardCopyOption.REPLACE_EXISTING);
}
//Files.deleteIfExists(path);
Files.copy(handler.getDllPath(is64Bit), path);
}
}
private void setDisableAllButtons(boolean b) {
reset_button.setDisable(b);
save_button.setDisable(b);
getAppId_button.setDisable(b);
path_button.setDisable(b);
retrieveDlcList_button.setDisable(b);
}
public void resetFromButton() {
reset(false);
} }
static class ComboBoxAutoComplete<T> { static class ComboBoxAutoComplete<T> {

View File

@ -13,6 +13,8 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package xyz.jeddunk.autocreamapi;
import javafx.application.Application; import javafx.application.Application;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
@ -22,13 +24,13 @@ import javafx.stage.Stage;
public class Main extends Application { public class Main extends Application {
private static final int MIN_WIDTH = 905; private static final int MIN_WIDTH = 905;
private static final int MIN_HEIGHT = 400; private static final int MIN_HEIGHT = 450;
private static final int PREF_WIDTH = 1200; private static final int PREF_WIDTH = 1200;
private static final int PREF_HEIGHT = 600; private static final int PREF_HEIGHT = 600;
@Override @Override
public void start(Stage primaryStage) throws Exception { public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(ClassLoader.getSystemResource("mainWindow.fxml")); Parent root = FXMLLoader.load(ClassLoader.getSystemResource("xyz/jeddunk/autocreamapi/mainWindow.fxml"));
primaryStage.setTitle("Auto CreamAPI"); primaryStage.setTitle("Auto CreamAPI");
primaryStage.setMinWidth(MIN_WIDTH + 25); primaryStage.setMinWidth(MIN_WIDTH + 25);
primaryStage.setMinHeight(MIN_HEIGHT + 50); primaryStage.setMinHeight(MIN_HEIGHT + 50);

View File

@ -13,21 +13,27 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
import javafx.fxml.FXML; package xyz.jeddunk.autocreamapi;import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.control.cell.TreeItemPropertyValueFactory; import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.input.MouseButton; import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.stage.Stage; import javafx.stage.Stage;
import pojo.App; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.jeddunk.autocreamapi.pojo.App;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import static java.text.MessageFormat.format;
public class SearchResultWindowController implements Initializable { public class SearchResultWindowController implements Initializable {
final Logger logger = LoggerFactory.getLogger(SearchResultWindowController.class);
@FXML @FXML
public Button okButton; public Button okButton;
@FXML @FXML
@ -62,6 +68,7 @@ public class SearchResultWindowController implements Initializable {
public void confirm() { public void confirm() {
App app = gameTable.getSelectionModel().getSelectedItem().getValue(); App app = gameTable.getSelectionModel().getSelectedItem().getValue();
logger.info(format("Game selected: {0} ({1})!", app.getName(), app.getAppId()));
parent.game_name_textfield.setText(app.getName()); parent.game_name_textfield.setText(app.getName());
parent.appId_textfield.setText(String.valueOf(app.getAppId())); parent.appId_textfield.setText(String.valueOf(app.getAppId()));
Stage current = (Stage) okButton.getScene().getWindow(); Stage current = (Stage) okButton.getScene().getWindow();
@ -69,8 +76,9 @@ public class SearchResultWindowController implements Initializable {
} }
public void cancel() { public void cancel() {
parent.game_name_textfield.setText(""); logger.info("Closing window without setting game!");
parent.appId_textfield.setText("-1"); /*parent.game_name_textfield.setText("");
parent.appId_textfield.setText("-1");*/
Stage current = (Stage) cancelButton.getScene().getWindow(); Stage current = (Stage) cancelButton.getScene().getWindow();
current.close(); current.close();
} }
@ -89,11 +97,12 @@ public class SearchResultWindowController implements Initializable {
} }
lastTime = currentTime; lastTime = currentTime;
if (isDblClicked) { if (isDblClicked) {
App app = gameTable.getSelectionModel().getSelectedItem().getValue(); /*App app = gameTable.getSelectionModel().getSelectedItem().getValue();
parent.game_name_textfield.setText(app.getName()); parent.game_name_textfield.setText(app.getName());
parent.appId_textfield.setText(String.valueOf(app.getAppId())); parent.appId_textfield.setText(String.valueOf(app.getAppId()));
Stage current = (Stage) gameTable.getScene().getWindow(); Stage current = (Stage) gameTable.getScene().getWindow();
current.close(); current.close();*/
confirm();
} }
} }
} }

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package pojo; package xyz.jeddunk.autocreamapi.pojo;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package pojo; package xyz.jeddunk.autocreamapi.pojo;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;

View File

@ -13,18 +13,24 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package util; package xyz.jeddunk.autocreamapi.util;
import org.apache.commons.configuration2.*; import org.apache.commons.configuration2.*;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Configurations; import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.configuration2.ex.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*; import java.io.*;
import java.text.MessageFormat;
import java.util.*; import java.util.*;
import static java.text.MessageFormat.format;
public class CreamApiConfig { public class CreamApiConfig {
final Logger logger = LoggerFactory.getLogger(CreamApiConfig.class);
private static CreamApiConfig configInstance; private static CreamApiConfig configInstance;
private static final Configurations CONFIGS = new Configurations(); private static final Configurations CONFIGS = new Configurations();
@ -48,7 +54,7 @@ public class CreamApiConfig {
config = CONFIGS.ini(path); config = CONFIGS.ini(path);
config.setCommentLeadingCharsUsedInInput(";"); config.setCommentLeadingCharsUsedInInput(";");
} catch (ConfigurationException e) { } catch (ConfigurationException e) {
System.err.println("No config file found in default location!"); logger.warn("No config file found!");
//e.printStackTrace(); //e.printStackTrace();
} }
@ -88,10 +94,10 @@ public class CreamApiConfig {
try { try {
read(); read();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
System.err.println("Error reading cream_api.ini! " + logger.warn("Error reading cream_api.ini! " +
"This can be ignored if setting up CreamAPI for the first time."); "This can be ignored if setting up CreamAPI for the first time.");
} catch (NullPointerException e) { } catch (NullPointerException e) {
System.err.println("Can't fill out fields, no configuration file set!"); logger.warn("Can't fill out fields, no configuration file set!");
} }
} }
@ -103,6 +109,7 @@ public class CreamApiConfig {
} }
public void read() throws NullPointerException, NoSuchElementException { public void read() throws NullPointerException, NoSuchElementException {
logger.info("Reading config file...");
appId = config.getInt("steam.appid"); appId = config.getInt("steam.appid");
language = config.getString("steam.language"); language = config.getString("steam.language");
if (language == null) { if (language == null) {
@ -113,9 +120,11 @@ public class CreamApiConfig {
forceOffline = config.getBoolean("steam.forceoffline"); forceOffline = config.getBoolean("steam.forceoffline");
final SubnodeConfiguration dlc_section = config.getSection("dlc"); final SubnodeConfiguration dlc_section = config.getSection("dlc");
dlc_section.getKeys().forEachRemaining(k -> dlc.put(Integer.parseInt(k), dlc_section.getString(k))); dlc_section.getKeys().forEachRemaining(k -> dlc.put(Integer.parseInt(k), dlc_section.getString(k)));
logger.info("Successfully read config file!");
} }
public void sync() throws ConfigurationException { public void sync() throws ConfigurationException {
logger.info("Saving config file...");
FileBasedConfigurationBuilder<INIConfiguration> builder = CONFIGS.iniBuilder(path); FileBasedConfigurationBuilder<INIConfiguration> builder = CONFIGS.iniBuilder(path);
config = builder.getConfiguration(); config = builder.getConfiguration();
config.setCommentLeadingCharsUsedInInput(";"); config.setCommentLeadingCharsUsedInInput(";");
@ -136,6 +145,7 @@ public class CreamApiConfig {
config.setProperty("steam_misc.disableuserinterface", false); config.setProperty("steam_misc.disableuserinterface", false);
builder.save(); builder.save();
logger.info("Saved successfully!");
} }
// DLC list parsing // DLC list parsing
@ -151,7 +161,7 @@ public class CreamApiConfig {
Arrays.stream(str.split("\\R+")).forEach(line -> { Arrays.stream(str.split("\\R+")).forEach(line -> {
final String[] split = line.split("\\s*=\\s*", 2); final String[] split = line.split("\\s*=\\s*", 2);
if (split.length == 2) dlc.put(Integer.parseInt(split[0]), split[1]); if (split.length == 2) dlc.put(Integer.parseInt(split[0]), split[1]);
else System.err.println(MessageFormat.format("Error while splitting line: \"{0}\"", line)); else logger.error(format("Error while splitting line: \"{0}\"", line));
}); });
} }
@ -204,9 +214,9 @@ public class CreamApiConfig {
public void setConfig(String path) throws ConfigurationException, IOException { public void setConfig(String path) throws ConfigurationException, IOException {
File file = new File(path); File file = new File(path);
if (file.createNewFile()) { if (file.createNewFile()) {
System.out.println("New config file created!"); logger.info("New config file created!");
} else { } else {
System.out.println("Using existing config file!"); logger.info("Using existing config file!");
} }
this.config = CONFIGS.ini(path); this.config = CONFIGS.ini(path);
this.config.setCommentLeadingCharsUsedInInput(";"); this.config.setCommentLeadingCharsUsedInInput(";");

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package util; package xyz.jeddunk.autocreamapi.util;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
@ -31,10 +31,8 @@ public class CreamApiDllHandler {
private final String steamApi64DllMd5; private final String steamApi64DllMd5;
private CreamApiDllHandler() throws IOException { private CreamApiDllHandler() throws IOException {
String steamApiDllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApiDllPath)); this.steamApiDllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApiDllPath));
String steamApi64DllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApi64DllPath)); this.steamApi64DllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApi64DllPath));
this.steamApiDllMd5 = steamApiDllMd5;
this.steamApi64DllMd5 = steamApi64DllMd5;
} }
public static synchronized CreamApiDllHandler getInstance() throws IOException { public static synchronized CreamApiDllHandler getInstance() throws IOException {

View File

@ -0,0 +1,279 @@
/*
* Auto-CreamAPI
* Copyright (C) 2020 Jeddunk
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
package xyz.jeddunk.autocreamapi.util;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.util.Cookie;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import me.xdrop.fuzzywuzzy.FuzzySearch;
import me.xdrop.fuzzywuzzy.model.BoundExtractedResult;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.jeddunk.autocreamapi.pojo.App;
import xyz.jeddunk.autocreamapi.pojo.SteamAppsList;
import xyz.jeddunk.autocreamapi.util.env.MainEnv;
import java.io.*;
import java.lang.reflect.Type;
import java.net.URL;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
public class SteamAppsListCache {
final Logger logger = LoggerFactory.getLogger(SteamAppsListCache.class);
private SteamAppsList list = new SteamAppsList();
private final File cacheFile = new File("steamapps.json");
private MainEnv env;
private String cfduid = "";
public SteamAppsListCache() {
try {
Class<?> envDefault = Class.forName("xyz.jeddunk.autocreamapi.util.env.Default");
env = (MainEnv) envDefault.newInstance();
// System.out.println(env.getKey());
} catch (ClassNotFoundException e) {
logger.debug("Default environment missing, using main environemnt...");
env = new MainEnv();
} catch (IllegalAccessException | InstantiationException e) {
// Only thrown by newInstance()
e.printStackTrace();
}
//boolean fileFound = true;
try {
getListFromFile();
} catch (FileNotFoundException e) {
logger.info("File does not exist, trying to create steamapps.json for the first time...");
//fileFound = false;
sync();
} catch (JsonSyntaxException e) {
logger.warn("File seems to be corrupt, trying to recreate steamapps.json...");
//fileFound = false;
sync();
}
if (Instant.now().isAfter(list.getTimestamp().plus(Duration.ofDays(3)))) {
logger.info("List in file is not recent!");
sync();
}
}
private void sync() {
getListFromApi();
try {
saveListToFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public App getGame(int appId) {
return list.getSteamAppsList().stream().filter(app -> app.getAppId() == appId).findFirst().orElse(null);
}
@SuppressWarnings("unused")
public App getGame(String name) {
return list.getSteamAppsList().stream()
.filter(app -> app.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
}
public List<App> findListOfGames(String name) {
List<BoundExtractedResult<App>> match = FuzzySearch.extractSorted(name, list.getSteamAppsList(), app ->
app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""), 80);
List<App> collect = match.stream().map(BoundExtractedResult::getReferent).collect(Collectors.toList());
for (App app : collect) {
if (app.getName().replaceAll("[^a-zA-Z0-9\\s+]", "")
.equalsIgnoreCase(name.replaceAll("[^a-zA-Z0-9\\s+]", ""))) {
collect = new ArrayList<>();
collect.add(app);
break;
}
}
return collect;
}
private void getListFromApi() {
logger.info("Trying to get SteamAppList from API...");
List<App> apps = getApps();
list.setTimestamp(Instant.now());
list.setSteamAppsList(apps);
}
private List<App> getApps() {
HttpResponse<String> httpResponse =
Unirest.get("https://api.steampowered.com/IStoreService/GetAppList/v1/" +
"?key=" + env.getKey() + "&include_games=1&max_results=50000").asString();
return new Gson()
.fromJson(httpResponse.getBody(), App.Rezponze.Download.class)
.getResponse().getApps();
}
private void saveListToFile() throws IOException {
logger.info("Trying to save SteamAppList to file \"" + cacheFile.getAbsolutePath() + "\"...");
Gson gson = new Gson();
String jsonString = gson.toJson(list);
BufferedWriter fOut = new BufferedWriter(new FileWriter(cacheFile));
fOut.write(jsonString);
fOut.close();
logger.info("Successfully saved SteamAppList to file \"" + cacheFile.getAbsolutePath() + "\"...");
}
private void getListFromFile() throws FileNotFoundException, JsonSyntaxException {
logger.info("Trying to get SteamAppList from file \"" + cacheFile.getAbsolutePath() + "\"...");
BufferedReader fIn = new BufferedReader(new FileReader(cacheFile));
String json = fIn.lines().collect(Collectors.joining());
final Type type = new TypeToken<SteamAppsList>() {
}.getType();
Gson gson = new Gson();
list = gson.fromJson(json, type);
logger.info("Successfully got SteamAppList from file \"" + cacheFile.getAbsolutePath() + "\"...");
}
public Map<Integer, String> getDlcMap(String appId, boolean use_steamdb) {
logger.info("Getting list of DLC for AppID: " + appId + "...");
Map<Integer, String> steamStoreDLCs = new HashMap<>();
Map<Integer, String> steamDbDLCs = new HashMap<>();
// Steam Store
try {
logger.info("Trying to get DLC from Steam store page...");
Document steamDoc = Jsoup
.connect("https://store.steampowered.com/app/" + appId + "/")
.cookie("birthtime", "470703601")
.cookie("wants_mature_content", "1")
.get();
Elements steamDLCs = steamDoc.getElementsByClass("game_area_dlc_row");
for (Element dlc : steamDLCs) {
String dlc_id = dlc.attr("data-ds-appid");
String dlc_name = dlc
.getElementsByClass("game_area_dlc_name")
.text().replace("\n", "").trim();
steamStoreDLCs.put(Integer.parseInt(dlc_id), dlc_name);
}
logger.info("Got DLC from Steam store page successfully.");
} catch (HttpStatusException e) {
logger.error(e.getUrl());
if (e.getStatusCode() == 404) {
logger.error("App ID empty or not found! (HTTP Status Code: 404)");
} else {
logger.error("Error occurred while trying to get list of DLCs " +
"(HTTP Status Code: " + e.getStatusCode() + ")");
}
} catch (NullPointerException | IOException e) {
// ignore
}
// SteamDB
if (use_steamdb) {
logger.info("Trying to get DLC from SteamDB...");
if (cfduid.equals("")) {
logger.info("Missing CF cookie, trying to get it...");
WebClient client = new WebClient(BrowserVersion.CHROME);
client.getOptions().setCssEnabled(false);
client.getOptions().setJavaScriptEnabled(false);
client.getOptions().setThrowExceptionOnFailingStatusCode(false);
client.getOptions().setRedirectEnabled(true);
client.getCache().setMaxSize(0);
/*client.waitForBackgroundJavaScript(10000);
client.setJavaScriptTimeout(10000);
client.waitForBackgroundJavaScriptStartingBefore(10000);*/
try {
String urlString = "https://steamdb.info/";
HtmlPage page = client.getPage(urlString);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (page) {
page.wait(8000);
}
//Print cookies for test purposes. Comment out in production.
URL url = new URL(urlString);
for (Cookie c : client.getCookies(url)) {
//System.out.println(c.getName() +"="+c.getValue());
if (c.getName().equals("__cfduid")) {
cfduid = c.getValue();
logger.info("Got CF cookie successfully.");
}
}
//This prints the content after bypassing Cloudflare.
// System.out.println(client.getPage(url).getWebResponse().getContentAsString());
} catch (FailingHttpStatusCodeException | IOException | InterruptedException e) {
// e.printStackTrace();
logger.error("Could not get CF cookie, skipping SteamDB DLC list...");
}
}
if ((!(cfduid.equals(""))) && (!(cfduid.equals("N/A")))) {
try {
Document steamDbDoc = Jsoup
.connect("https://steamdb.info/app/" + appId + "/dlc/")
.cookie("__cfduid", cfduid)
.userAgent(BrowserVersion.CHROME.getUserAgent())
.get();
Element steamDbDlcSection = steamDbDoc.getElementById("dlc");
Elements steamDbDLCElements = steamDbDlcSection.getElementsByClass("app");
for (Element dlc : steamDbDLCElements) {
String dlc_id = dlc.attr("data-appid");
String dlc_name = "Unknown DLC " + dlc_id;
Elements td = dlc.getElementsByTag("td");
if (!td.isEmpty()) {
dlc_name = td.get(1).text().replace("\n", "").trim();
}
steamDbDLCs.put(Integer.parseInt(dlc_id), dlc_name);
}
logger.info("Got DLC from SteamDB successfully.");
} catch (HttpStatusException e) {
logger.error(e.getUrl());
if (e.getStatusCode() == 404) {
logger.error("App ID empty or not found! (HTTP Status Code: 404)");
} else {
logger.error("Error occurred while trying to get list of DLCs " +
"(HTTP Status Code: " + e.getStatusCode() + ")");
}
} catch (NullPointerException | IOException e) {
// ignore
}
}
}
logger.info("Merging both DLC lists...");
Map<Integer, String> allDLCs = new HashMap<>(steamStoreDLCs);
steamDbDLCs.forEach(allDLCs::putIfAbsent);
logger.info("DLC list is done!");
return allDLCs.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
}
}

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
package util.env; package xyz.jeddunk.autocreamapi.util.env;
public class MainEnv { public class MainEnv {
String key = ""; String key = "";

View File

@ -1 +1 @@
Main-Class: Main Main-Class: xyz.jeddunk.autocreamapi.Main

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Auto-CreamAPI
~ Copyright (C) 2020 Jeddunk
~
~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
~ License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
~ version.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License along with this program. If not, see
~ <https://www.gnu.org/licenses/>.
-->
<configuration>
<property name="PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n"/>
<!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
the key "bySecond" into the logger context. This value will be
available to all subsequent configuration elements. -->
<timestamp key="bySecond" datePattern="yyyy'_'MM'_'dd'-'HH'_'mm'_'ss"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--withJansi>true</withJansi-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- use the previously created timestamp to create a uniquely
named log file -->
<file>autocreamapi_${bySecond}.log</file>
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<logger name="com.base22" level="TRACE"/>
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>

View File

@ -1,151 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXCheckBox?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<!--
~ Auto-CreamAPI
~ Copyright (C) 2020 Jeddunk
~
~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
~ License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
~ version.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License along with this program. If not, see
~ <https://www.gnu.org/licenses/>.
-->
<?import java.net.URL?>
<BorderPane prefHeight="361.0" prefWidth="693.0" xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
<center>
<GridPane hgap="10.0" minHeight="360.0" minWidth="655.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity"
prefWidth="375.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<JFXTextField fx:id="path_textfield" promptText="Path to game's steam_api(64).dll..."
GridPane.columnSpan="2"/>
<JFXButton fx:id="path_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
minHeight="-Infinity" minWidth="-Infinity" onAction="#openFileChooser" ripplerFill="BLACK"
GridPane.columnIndex="2">
<graphic>
<FontAwesomeIconView glyphName="FOLDER_OPEN" glyphSize="24"/>
</graphic>
</JFXButton>
<JFXTextField fx:id="game_name_textfield" promptText="Game..." GridPane.rowIndex="1"/>
<JFXButton fx:id="getAppId_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
minHeight="-Infinity" minWidth="-Infinity" onAction="#getAppId" ripplerFill="BLACK"
GridPane.columnIndex="1" GridPane.rowIndex="1">
<graphic>
<FontAwesomeIconView glyphName="SEARCH" glyphSize="24"/>
</graphic>
</JFXButton>
<JFXTextField fx:id="appId_textfield" prefWidth="299.0" promptText="Steam AppID..." GridPane.columnIndex="2"
GridPane.rowIndex="1"/>
<JFXComboBox fx:id="language_combobox" editable="true" promptText="Language"
GridPane.columnSpan="2147483647"
GridPane.rowIndex="2"/>
<JFXCheckBox fx:id="offline_checkbox" text="Force offline mode" GridPane.columnSpan="2147483647"
GridPane.rowIndex="3"/>
<JFXCheckBox fx:id="extra_protection_checkbox" text="Try to bypass game-specific protection"
GridPane.columnSpan="2147483647" GridPane.rowIndex="4"/>
<JFXCheckBox fx:id="unlock_all_checkbox" onAction="#unlockAll_disableDlcTextArea"
text="Unlock all DLC (if possible)" GridPane.columnSpan="2147483647" GridPane.rowIndex="5"/>
<JFXTextArea fx:id="dlc_textarea" promptText="List of DLC..." GridPane.columnSpan="2147483647"
GridPane.rowIndex="6"/>
<JFXButton fx:id="retrieveDlcList_button" maxHeight="1.7976931348623157E308" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" onAction="#getDlcList" ripplerFill="BLACK"
text="Get DLCs for AppID" GridPane.rowIndex="7"/>
<JFXButton fx:id="save_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
minHeight="-Infinity" minWidth="-Infinity" onAction="#save" ripplerFill="BLACK"
text="Save" GridPane.columnIndex="1" GridPane.rowIndex="7"/>
<JFXButton fx:id="reset_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
minHeight="-Infinity" minWidth="-Infinity" onAction="#resetFromButton" ripplerFill="BLACK"
text="Reset" GridPane.columnIndex="2" GridPane.rowIndex="7"/>
<BorderPane.margin>
<Insets/>
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</GridPane>
</center>
<bottom>
<Label fx:id="state_label" maxWidth="1.7976931348623157E308" minHeight="25.0" minWidth="-Infinity" text="Ready."
textFill="#555555" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets/>
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</Label>
</bottom>
<right>
<GridPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="250.0"
BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<Label maxHeight="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity"
text="CreamAPI DLL applied" fx:id="creamApiDllApplied">
<font>
<Font size="14.0"/>
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiDllAppliedIcon" glyphName="TIMES" size="20"/>
</graphic>
</Label>
<Label layoutX="20.0" layoutY="20.0" maxHeight="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" text="CreamAPI configuration file exists" GridPane.rowIndex="1"
fx:id="creamApiConfigExists">
<font>
<Font size="14.0"/>
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiConfigExistsIcon" glyphName="TIMES" size="20"/>
</graphic>
</Label>
</GridPane>
</right>
<stylesheets>
<URL value="@stylesheet.css"/>
</stylesheets>
</BorderPane>

View File

@ -1,23 +0,0 @@
/*
* Auto-CreamAPI
* Copyright (C) 2020 Jeddunk
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
JFXButton {
-fx-background-color: #ddd;
}
#state_label {
-fx-background-color: #ddd;
-fx-border-color: #aaa;
}

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXCheckBox?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<!--
~ Auto-CreamAPI
~ Copyright (C) 2020 Jeddunk
~
~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
~ License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
~ version.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License along with this program. If not, see
~ <https://www.gnu.org/licenses/>.
-->
<BorderPane prefHeight="450.0" prefWidth="705.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.jeddunk.autocreamapi.Controller">
<center>
<GridPane hgap="10.0" minHeight="410.0" minWidth="655.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity" prefWidth="375.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<TitledPane animated="false" collapsible="false" maxHeight="1.7976931348623157E308" styleClass="dlcSettings"
text="DLC Settings" GridPane.columnSpan="2147483647" GridPane.rowIndex="5">
<GridPane hgap="10.0" maxHeight="1.7976931348623157E308" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints/>
<RowConstraints/>
<RowConstraints maxHeight="1.7976931348623157E308"/>
</rowConstraints>
<JFXCheckBox fx:id="unlock_all_checkbox" onAction="#unlockAll_disableDlcTextArea"
text="Unlock all DLC (if possible)" GridPane.columnSpan="2147483647"/>
<JFXTextArea fx:id="dlc_textarea" maxHeight="1.7976931348623157E308" prefHeight="999999.0"
promptText="List of DLC..." GridPane.columnSpan="2147483647" GridPane.rowIndex="2"
GridPane.rowSpan="2147483647"/>
<JFXCheckBox fx:id="steamdb_dlc_checkbox" text="Additionally use SteamDB for DLCs"
GridPane.rowIndex="1"/>
</GridPane>
</TitledPane>
<JFXTextField fx:id="path_textfield" promptText="Path to game's steam_api(64).dll..." GridPane.columnSpan="2" />
<JFXButton fx:id="path_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#openFileChooser" ripplerFill="BLACK" GridPane.columnIndex="2">
<graphic>
<FontAwesomeIconView glyphName="FOLDER_OPEN" glyphSize="24" />
</graphic>
</JFXButton>
<JFXTextField fx:id="game_name_textfield" promptText="Game..." GridPane.rowIndex="1" />
<JFXButton fx:id="getAppId_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#getAppId" ripplerFill="BLACK" GridPane.columnIndex="1" GridPane.rowIndex="1">
<graphic>
<FontAwesomeIconView glyphName="SEARCH" glyphSize="24" />
</graphic>
</JFXButton>
<JFXTextField fx:id="appId_textfield" prefWidth="299.0" promptText="Steam AppID..." GridPane.columnIndex="2" GridPane.rowIndex="1" />
<JFXComboBox fx:id="language_combobox" editable="true" promptText="Language" GridPane.columnSpan="2147483647" GridPane.rowIndex="2" />
<JFXCheckBox fx:id="offline_checkbox" text="Force offline mode" GridPane.columnSpan="2147483647" GridPane.rowIndex="3" />
<JFXCheckBox fx:id="extra_protection_checkbox" text="Try to bypass game-specific protection" GridPane.columnSpan="2147483647" GridPane.rowIndex="4" />
<JFXButton fx:id="getDlcList_button" maxHeight="1.7976931348623157E308" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onAction="#getDlcList" ripplerFill="BLACK" text="Get DLCs for AppID" GridPane.rowIndex="6" />
<JFXButton fx:id="save_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#save" ripplerFill="BLACK" text="Save" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<JFXButton fx:id="reset_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#resetFromButton" ripplerFill="BLACK" text="Reset" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</GridPane>
</center>
<bottom>
<Label fx:id="state_label" maxWidth="1.7976931348623157E308" minHeight="25.0" minWidth="-Infinity" prefWidth="905.0" text="Ready." textFill="#555555" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</Label>
</bottom>
<right>
<GridPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="250.0" BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<Label fx:id="creamApiDllApplied" maxHeight="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" text="CreamAPI DLL applied">
<font>
<Font size="14.0" />
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiDllAppliedIcon" glyphName="TIMES" size="20" />
</graphic>
</Label>
<Label fx:id="creamApiConfigExists" layoutX="20.0" layoutY="20.0" maxHeight="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" text="CreamAPI configuration file exists" GridPane.rowIndex="1">
<font>
<Font size="14.0" />
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiConfigExistsIcon" glyphName="TIMES" size="20" />
</graphic>
</Label>
</GridPane>
</right>
<stylesheets>
<URL value="@stylesheet.css" />
</stylesheets>
</BorderPane>

View File

@ -24,7 +24,7 @@
~ <https://www.gnu.org/licenses/>. ~ <https://www.gnu.org/licenses/>.
--> -->
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="655.0" prefWidth="420.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="SearchResultWindowController"> <VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="655.0" prefWidth="420.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.jeddunk.autocreamapi.SearchResultWindowController">
<opaqueInsets> <opaqueInsets>
<Insets /> <Insets />
</opaqueInsets> </opaqueInsets>

View File

@ -0,0 +1,71 @@
/*
* Auto-CreamAPI
* Copyright (C) 2020 Jeddunk
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
@font-face {
font-family: 'Roboto Condensed', sans-serif;
src: url("fonts/roboto-condensed/RobotoCondensed-Regular.ttf");
}
@font-face {
font-family: 'Roboto Condensed', sans-serif;
font-weight: bold;
src: url("fonts/roboto-condensed/RobotoCondensed-Bold.ttf");
}
@font-face {
font-family: 'Roboto Condensed', sans-serif;
font-weight: italic;
src: url("fonts/roboto-condensed/RobotoCondensed-Italic.ttf");
}
@font-face {
font-family: 'Roboto Mono', monospace;
src: url("fonts/roboto-mono/RobotoMono-Regular.ttf");
}
@font-face {
font-family: 'Roboto Mono', monospace;
font-weight: bold;
src: url("fonts/roboto-mono/RobotoMono-Bold.ttf");
}
@font-face {
font-family: 'Roboto Mono', monospace;
font-weight: italic;
src: url("fonts/roboto-mono/RobotoMono-Italic.ttf");
}
* {
-fx-font-size: 14;
-fx-font-family: 'Roboto Condensed', sans-serif;
}
JFXButton {
-fx-background-color: #ddd;
}
#state_label {
-fx-background-color: #ddd;
-fx-border-color: #aaa;
}
#dlc_textarea {
-fx-font-family: 'Roboto Mono', sans-serif;
}
.dlcSettings > .title {
-fx-background-color: #ddd;
}

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
4.4.0.0 4.5.0.0