diff --git a/.gitignore b/.gitignore index 0dc5435..a463f20 100644 --- a/.gitignore +++ b/.gitignore @@ -157,3 +157,4 @@ $RECYCLE.BIN/ cream_api.ini steamapps.json +/test.json diff --git a/auto-cream-api.iml b/auto-cream-api.iml index 81ae37b..4599ba8 100644 --- a/auto-cream-api.iml +++ b/auto-cream-api.iml @@ -18,39 +18,16 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index f5203f2..dbc27e5 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,27 @@ + + + + false + + bintray-jerady-maven + bintray + https://dl.bintray.com/jerady/maven + + + + + + false + + bintray-jerady-maven + bintray-plugins + https://dl.bintray.com/jerady/maven + + + com.jfoenix @@ -58,11 +79,6 @@ 8.0.8 compile - org.apache.commons commons-configuration2 @@ -73,11 +89,6 @@ commons-beanutils 1.9.4 - - com.ibasco.agql - agql-steam-webapi - 0.1.7 - de.jensd fontawesomefx-commons @@ -90,5 +101,20 @@ 4.7.0-5 compile + + com.google.code.gson + gson + 2.8.6 + + + org.jsoup + jsoup + 1.12.1 + + + com.konghq + unirest-java + 3.1.02 + \ No newline at end of file diff --git a/src/main/java/Controller.java b/src/main/java/Controller.java index d29c1bc..c8145f4 100644 --- a/src/main/java/Controller.java +++ b/src/main/java/Controller.java @@ -1,39 +1,60 @@ -import com.ibasco.agql.protocols.valve.steam.webapi.pojos.SteamApp; import com.jfoenix.controls.*; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; -import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Tooltip; import javafx.stage.FileChooser; import org.apache.commons.configuration2.ex.ConfigurationException; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import pojo.App; import java.io.File; import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; public class Controller { private CreamApiConfig config = CreamApiConfig.getInstance(); private SteamAppsListCache cache = new SteamAppsListCache(); - @FXML public JFXTextField path_textfield; - @FXML public JFXTextField appId_textfield; - @FXML public JFXTextField game_name_textfield; - @FXML public JFXComboBox language_combobox; - @FXML public JFXTextArea dlc_textarea; - @FXML public JFXCheckBox extra_protection_checkbox; - @FXML public JFXCheckBox offline_checkbox; - @FXML public JFXCheckBox unlock_all_checkbox; - @FXML public JFXButton reset_button; - @FXML public JFXButton save_button; - @FXML public JFXButton getAppId_button; - @FXML public JFXButton path_button; - @FXML public JFXButton retrieveDlcList_button; + @FXML + public JFXTextField path_textfield; + @FXML + public JFXTextField appId_textfield; + @FXML + public JFXTextField game_name_textfield; + @FXML + public JFXComboBox language_combobox; + @FXML + public JFXTextArea dlc_textarea; + @FXML + public JFXCheckBox extra_protection_checkbox; + @FXML + public JFXCheckBox offline_checkbox; + @FXML + public JFXCheckBox unlock_all_checkbox; + @FXML + public JFXButton reset_button; + @FXML + public JFXButton save_button; + @FXML + public JFXButton getAppId_button; + @FXML + public JFXButton path_button; + @FXML + public JFXButton retrieveDlcList_button; - public Controller() {} + public Controller() { + } @FXML public void initialize() { appId_textfield.textProperty().addListener(appIdChangesGameName()); - retrieveDlcList_button.setDisable(true); // WIP + //retrieveDlcList_button.setDisable(true); // WIP generate_tooltips(); fix_dlc_textarea_prompt_text(); read(); @@ -66,7 +87,7 @@ public class Controller { int appId; try { appId = Integer.parseInt(newValue); - final SteamApp game = cache.getGame(appId); + final App game = cache.getGame(appId); if (game != null) { game_name_textfield.setText(game.getName()); } else { @@ -98,72 +119,73 @@ public class Controller { } public void getAppId() { - final SteamApp game = cache.findGame(game_name_textfield.getText()); + final App game = cache.findGame(game_name_textfield.getText()); if (game == null) { appId_textfield.setText("-1"); } else { - appId_textfield.setText(String.valueOf(game.getAppid())); + appId_textfield.setText(String.valueOf(game.getAppId())); } } public void unlockAll_disableDlcTextArea() { dlc_textarea.setDisable(unlock_all_checkbox.isSelected()); + retrieveDlcList_button.setDisable(unlock_all_checkbox.isSelected()); } + /** + * Gets DLC from both the Steam Store and SteamDB, since the latter has a (weird) limit of 64(?) DLCs. SteamDB + * also lists DLC not available for purchase. + */ public void getDlcList() { - // https://github.com/Sak32009/GetDLCInfoFromSteamDB/blob/master/sak32009-get-dlc-info-from-steamdb.user.js - /*async getData() { - // CHECK IF THE APPID HAS DLCs - if (!$("#dlc").length) { - return false; + Map steamStoreDLCs = new HashMap<>(); + Map steamDbDLCs = new HashMap<>(); + //StringBuilder sb = new StringBuilder(); + try { + // Steam Store + Document steamDoc = Jsoup + .connect("https://store.steampowered.com/app/" + appId_textfield.getText() + "/") + .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); } - // SELF - const self = this; - // SET APPID - this.steamDB.appID = $(".scope-app[data-appid]").data("appid"); - // SET APPID NAME - this.steamDB.appIDName = $("td[itemprop='name']").text(); - // GET APPID DLCS FROM TAB - $("tr.app[data-appid]").each((_index, _values) => { - const $this = $(_values); - const appID = $this.data("appid"); - const appIDName = $this.find(`td:nth-of-type(2)`).text().trim(); - // ADD DATA - self.steamDB.appIDDLCs[appID] = { - name: appIDName - }; - // +1 - self.steamDB.appIDDLCsCount += 1; - }); - // GET APPID DLCS FROM REQUEST - await this.getHttpRequest(`${self.info.steamDBLinked + this.steamDB.appID}`, ({ - responseText - }) => { - // APPS - const $apps = $($.parseHTML(responseText)).find("tr.app[data-appid]"); - // FETCH APPS - $apps.each((_index, _values) => { - const $this = $(_values); - const appID = $this.attr("data-appid"); - const appIDType = $this.find("td:nth-of-type(2)").text().trim(); - const appIDName = $this.find("td:nth-of-type(3)").text().trim(); - // CHECK IF EXISTS - if (!(appID in self.steamDB.appIDDLCs) && appIDType === "DLC") { - // ADD DATA - self.steamDB.appIDDLCs[appID] = { - name: appIDName - }; - // +1 - self.steamDB.appIDDLCsCount += 1; + // SteamDB + Document steamDbDoc = Jsoup + .connect("https://steamdb.info/app/" + appId_textfield.getText() + "/dlc/") + .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(); } - }); - // RUN - self.start(); - }); - }*/ + steamDbDLCs.put(Integer.parseInt(dlc_id), dlc_name); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (NullPointerException e) { + // ignore + } + + Map allDLCs = new HashMap<>(steamStoreDLCs); + steamDbDLCs.forEach(allDLCs::putIfAbsent); + StringBuilder sb = new StringBuilder(); + LinkedHashMap collect = allDLCs.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, + (oldValue, newValue) -> oldValue, LinkedHashMap::new)); + collect.forEach((k, v) -> sb.append(k).append("=").append(v).append("\n")); + dlc_textarea.setText(sb.toString()); } - public void openFileChooser(ActionEvent event) { + public void openFileChooser() { FileChooser chooser = new FileChooser(); chooser.setTitle("Choose steam_api(64).dll..."); FileChooser.ExtensionFilter filter = diff --git a/src/main/java/SteamAppsListCache.java b/src/main/java/SteamAppsListCache.java index 81cbe48..62b702d 100644 --- a/src/main/java/SteamAppsListCache.java +++ b/src/main/java/SteamAppsListCache.java @@ -1,58 +1,66 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import com.ibasco.agql.protocols.valve.steam.webapi.SteamWebApiClient; -import com.ibasco.agql.protocols.valve.steam.webapi.interfaces.SteamApps; -import com.ibasco.agql.protocols.valve.steam.webapi.pojos.SteamApp; +import kong.unirest.HttpResponse; +import kong.unirest.Unirest; +import pojo.App; +import pojo.Download; +import pojo.SteamAppsList; import java.io.*; import java.lang.reflect.Type; -import java.text.MessageFormat; import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @SuppressWarnings("WeakerAccess") public class SteamAppsListCache { - static class SteamAppsList { - Instant timestamp; - List steamAppsList; - } - private SteamAppsList list = new SteamAppsList(); private File cacheFile = new File("steamapps.json"); public SteamAppsListCache() { - getListFromFile(); - if (Instant.now().isAfter(list.timestamp.plus(Duration.ofDays(3)))) { - getListFromApi(); + 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; + } + if (!fileFound || Instant.now().isAfter(list.getTimestamp().plus(Duration.ofDays(3)))) { + sync(); + } + } + + private void sync() { + getListFromApi(); + try { saveListToFile(); + } catch (IOException ex) { + ex.printStackTrace(); } } - public SteamApp getGame (int appId) { - for (SteamApp app : list.steamAppsList) { - if (app.getAppid() == appId) { + 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 App findGame(String name) { + for (App app : list.getSteamAppsList()) { + if (app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", "") + .startsWith(name.toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""))) { return app; } } - return null; - } - - public SteamApp getGame (String name) { - for (SteamApp app : list.steamAppsList) { - if (app.getName().equalsIgnoreCase(name)) { - return app; - } - } - return null; - } - - public SteamApp findGame(String name) { - for (SteamApp app : list.steamAppsList) { - if (app.getName().toLowerCase().contains(name.toLowerCase())) { + for (App app : list.getSteamAppsList()) { + if (app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", "") + .contains(name.toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""))) { return app; } } @@ -60,44 +68,30 @@ public class SteamAppsListCache { } private void getListFromApi() { - SteamWebApiClient client = new SteamWebApiClient(); - SteamApps steamApps = new SteamApps(client); - /*SteamStorefront storefront = new SteamStorefront(client); - StoreAppDetails appDetails = storefront.getAppDetails(440).exceptionally(throwable -> { - System.err.println(MessageFormat.format("Error Occurred: {}", throwable)); - return new StoreAppDetails(); - }).join(); - System.out.println(appDetails); - Gson gson = new Gson(); - System.out.println(gson.toJson(appDetails));*/ - list.timestamp = Instant.now(); - list.steamAppsList = steamApps.getAppList().exceptionally(throwable -> { - System.err.println(MessageFormat.format("Error Occurred: {}", throwable)); - return new ArrayList<>(); - }).join(); + HttpResponse httpResponse = + Unirest.get("https://api.steampowered.com/IStoreService/GetAppList/v1/" + + "?key=E427256C579D3CDF1D504810E8F5B948&include_games=1&max_results=50000").asString(); + List apps = new Gson() + .fromJson(httpResponse.getBody(), Download.class) + .getResponse().getApps(); + list.setTimestamp(Instant.now()); + list.setSteamAppsList(apps); } - private void saveListToFile() { + private void saveListToFile() throws IOException { Gson gson = new Gson(); String jsonString = gson.toJson(list); - try { - BufferedWriter fOut = new BufferedWriter(new FileWriter(cacheFile)); - fOut.write(jsonString); - fOut.close(); - } catch (IOException e) { - e.printStackTrace(); - } + BufferedWriter fOut = new BufferedWriter(new FileWriter(cacheFile)); + fOut.write(jsonString); + fOut.close(); } - private void getListFromFile() { - try { - BufferedReader fIn = new BufferedReader(new FileReader(cacheFile)); - String json = fIn.lines().collect(Collectors.joining()); - final Type type = new TypeToken() {}.getType(); - Gson gson = new Gson(); - list = gson.fromJson(json, type); - } catch (IOException e) { - e.printStackTrace(); - } + private void getListFromFile() throws FileNotFoundException { + BufferedReader fIn = new BufferedReader(new FileReader(cacheFile)); + String json = fIn.lines().collect(Collectors.joining()); + final Type type = new TypeToken() { + }.getType(); + Gson gson = new Gson(); + list = gson.fromJson(json, type); } } diff --git a/src/main/java/pojo/App.java b/src/main/java/pojo/App.java new file mode 100644 index 0000000..3130f12 --- /dev/null +++ b/src/main/java/pojo/App.java @@ -0,0 +1,110 @@ +package pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.Objects; + +@SuppressWarnings("unused") +public class App { + + @SerializedName("appid") + @Expose + private Integer appId; + @SerializedName("name") + @Expose + private String name; + @SerializedName("last_modified") + @Expose + private Integer lastModified; + @SerializedName("price_change_number") + @Expose + private Integer priceChangeNumber; + + public Integer getAppId() { + return appId; + } + + public void setAppId(Integer appId) { + this.appId = appId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getLastModified() { + return lastModified; + } + + public void setLastModified(Integer lastModified) { + this.lastModified = lastModified; + } + + public Integer getPriceChangeNumber() { + return priceChangeNumber; + } + + public void setPriceChangeNumber(Integer priceChangeNumber) { + this.priceChangeNumber = priceChangeNumber; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(App.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); + sb.append("appid"); + sb.append('='); + sb.append(((this.appId == null)?"":this.appId)); + sb.append(','); + sb.append("name"); + sb.append('='); + sb.append(((this.name == null)?"":this.name)); + sb.append(','); + sb.append("lastModified"); + sb.append('='); + sb.append(((this.lastModified == null)?"":this.lastModified)); + sb.append(','); + sb.append("priceChangeNumber"); + sb.append('='); + sb.append(((this.priceChangeNumber == null)?"":this.priceChangeNumber)); + sb.append(','); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); + } else { + sb.append(']'); + } + return sb.toString(); + } + + @Override + public int hashCode() { + int result = 1; + result = ((result* 31)+((this.name == null)? 0 :this.name.hashCode())); + result = ((result* 31)+((this.lastModified == null)? 0 :this.lastModified.hashCode())); + result = ((result* 31)+((this.priceChangeNumber == null)? 0 :this.priceChangeNumber.hashCode())); + result = ((result* 31)+((this.appId == null)? 0 :this.appId.hashCode())); + return result; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof App)) { + return false; + } + App rhs = ((App) other); + boolean b1 = Objects.equals(this.name, rhs.name); + boolean b2 = Objects.equals(this.lastModified, rhs.lastModified); + boolean b3 = Objects.equals(this.priceChangeNumber, rhs.priceChangeNumber); + boolean b4 = Objects.equals(this.appId, rhs.appId); + return b1 && b2 && b3 && b4; + } + +} diff --git a/src/main/java/pojo/Download.java b/src/main/java/pojo/Download.java new file mode 100644 index 0000000..384ef0d --- /dev/null +++ b/src/main/java/pojo/Download.java @@ -0,0 +1,58 @@ +package pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.Objects; + +public class Download { + + @SerializedName("response") + @Expose + private Rezponze response; + + public Rezponze getResponse() { + return response; + } + + public void setResponse(Rezponze response) { + this.response = response; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Download.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); + sb.append("response"); + sb.append('='); + sb.append(((this.response == null)?"":this.response)); + sb.append(','); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); + } else { + sb.append(']'); + } + return sb.toString(); + } + + @Override + public int hashCode() { + int result = 1; + result = ((result* 31)+((this.response == null)? 0 :this.response.hashCode())); + return result; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof Download)) { + return false; + } + Download rhs = ((Download) other); + return Objects.equals(this.response, rhs.response); + //return ((this.response == rhs.response)||((this.response!= null)&&this.response.equals(rhs.response))); + } + +} diff --git a/src/main/java/pojo/Rezponze.java b/src/main/java/pojo/Rezponze.java new file mode 100644 index 0000000..d2263dd --- /dev/null +++ b/src/main/java/pojo/Rezponze.java @@ -0,0 +1,60 @@ +package pojo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Rezponze { + + @SerializedName("apps") + @Expose + private List apps = new ArrayList<>(); + + public List getApps() { + return apps; + } + + public void setApps(List apps) { + this.apps = apps; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Rezponze.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); + sb.append("apps"); + sb.append('='); + sb.append(((this.apps == null)?"":this.apps)); + sb.append(','); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); + } else { + sb.append(']'); + } + return sb.toString(); + } + + @Override + public int hashCode() { + int result = 1; + result = ((result* 31)+((this.apps == null)? 0 :this.apps.hashCode())); + return result; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof Rezponze)) { + return false; + } + Rezponze rhs = ((Rezponze) other); + return Objects.equals(this.apps, rhs.apps); + //return ((this.apps == rhs.apps)||((this.apps!= null)&&this.apps.equals(rhs.apps))); + } + +} diff --git a/src/main/java/pojo/SteamAppsList.java b/src/main/java/pojo/SteamAppsList.java new file mode 100644 index 0000000..24cca4a --- /dev/null +++ b/src/main/java/pojo/SteamAppsList.java @@ -0,0 +1,25 @@ +package pojo; + +import java.time.Instant; +import java.util.List; + +public class SteamAppsList { + private Instant timestamp; + private List steamAppsList; + + public Instant getTimestamp() { + return timestamp; + } + + public void setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + } + + public List getSteamAppsList() { + return steamAppsList; + } + + public void setSteamAppsList(List steamAppsList) { + this.steamAppsList = steamAppsList; + } +} diff --git a/src/main/resources/mainWindow.fxml b/src/main/resources/mainWindow.fxml index fbb9b04..92cc63f 100644 --- a/src/main/resources/mainWindow.fxml +++ b/src/main/resources/mainWindow.fxml @@ -48,7 +48,7 @@ - +