auto-creamapi/src/main/java/Controller.java

253 lines
9.5 KiB
Java

import com.jfoenix.controls.*;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.scene.control.Tooltip;
import javafx.stage.FileChooser;
import org.apache.commons.codec.digest.DigestUtils;
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 util.CreamApiConfig;
import util.SteamAppsListCache;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public class Controller {
private static final String X86_MD5_HASH = "c6f267a2d10b891ed352ed849a28d69b";
private static final String X64_MD5_HASH = "645c728a6117946294130d07cf6c0cae";
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<String> 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;
private String steamApiPathString;
public Controller() {
}
@FXML
public void initialize() {
appId_textfield.textProperty().addListener(appIdChangesGameName());
//retrieveDlcList_button.setDisable(true); // WIP
generate_tooltips();
fix_dlc_textarea_prompt_text();
read();
}
private void read() {
appId_textfield.setText(config.getAppId().toString());
dlc_textarea.setText(config.getDlcListAsString());
game_name_textfield.setText(cache.getGame(config.getAppId()).getName());
extra_protection_checkbox.setSelected(config.getExtraProtection());
offline_checkbox.setSelected(config.getForceOffline());
unlock_all_checkbox.setSelected(config.getUnlockAll());
language_combobox.setItems(FXCollections.observableArrayList(config.getLanguages()));
language_combobox.getSelectionModel().select(config.getLanguage());
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() {
return (observable, oldValue, newValue) -> {
int appId;
try {
appId = Integer.parseInt(newValue);
final App game = cache.getGame(appId);
if (game != null) {
game_name_textfield.setText(game.getName());
} else {
game_name_textfield.setText("");
}
} catch (NumberFormatException e) {
game_name_textfield.setText("");
}
};
}
public void reset() {
config.read();
read();
}
public void save() {
try {
setUpCreamApi();
} catch (IOException e) {
e.printStackTrace();
}
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());
try {
config.sync();
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
public void getAppId() {
final App game = cache.findGame(game_name_textfield.getText());
if (game == null) {
appId_textfield.setText("-1");
} else {
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() {
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_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);
}
// 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();
}
steamDbDLCs.put(Integer.parseInt(dlc_id), dlc_name);
}
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
// ignore
}
Map<Integer, String> allDLCs = new HashMap<>(steamStoreDLCs);
steamDbDLCs.forEach(allDLCs::putIfAbsent);
StringBuilder sb = new StringBuilder();
LinkedHashMap<Number, String> 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() {
FileChooser chooser = new FileChooser();
chooser.setTitle("Choose steam_api(64).dll...");
FileChooser.ExtensionFilter filter =
new FileChooser.ExtensionFilter("steam_api(64).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");
path_textfield.setText(file.getParent());
steamApiPathString = file.getAbsolutePath();
} catch (ConfigurationException | IOException e) {
e.printStackTrace();
}
}
/**
* check if creamapi version of dll is there, if not, rename original to steam_api(64)_o.dll and copy
* creamapi one to the path.
*
* @throws IOException If file is missing or not accessible/modifiable.
*/
private void setUpCreamApi() throws IOException {
boolean is64Bit = false;
if (!steamApiPathString.isEmpty()) {
Path path = Paths.get(steamApiPathString);
if (path.endsWith("steam_api64.dll")) {
is64Bit = true;
}
InputStream is = Files.newInputStream(path);
String md5 = DigestUtils.md5Hex(is);
boolean isSameFile = Objects.equals(md5, is64Bit ? X64_MD5_HASH : X86_MD5_HASH);
if (!isSameFile) {
String pathOrigString = steamApiPathString;
pathOrigString =
pathOrigString
.replaceFirst("(?<steamApiDll>steam_api(?:64)?.dll)$",
is64Bit ? "steam_api64_o.dll" : "steam_api_o.dll");
Path pathOrig = Paths.get(pathOrigString);
if (!Files.exists(pathOrig)) {
Files.move(path, pathOrig);
}
Files.deleteIfExists(path);
Files.copy(Paths.get(is64Bit ? "steam_api64.dll" : "steam_api.dll"), path);
}
}
}
}