Java tutorial
package org.crazyt.xgogdownloader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.rmi.AccessException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.jsoup.Jsoup; import org.jsoup.select.Elements; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; /* This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://www.wtfpl.net/ for more details. */ public class Api implements IApi { private final UserDetails user = new UserDetails(); private final ApiConfig config = new ApiConfig(); private boolean error; private String error_message; public Api(String token, String secret) { this.error = false; this.config.oauth_token = token; this.config.oauth_secret = secret; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#init() */ @Override public final boolean init() { boolean res = false; this.getAPIConfig(); // Check if we already have token and secret if ((this.config.oauth_token != null) && (this.config.oauth_secret != "")) { // Test authorization by getting user details res = this.getUserDetails(); } return res; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getAPIConfig() */ @Override public final boolean getAPIConfig() { String url = "https://api.gog.com/en/downloader2/status/stable/"; // Stable // API boolean res = false; String json; try { json = this.getResponse(url); } catch (AccessException e1) { return false; } if (json != "") { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); this.config.oauth_authorize_temp_token = root.get("config").get("oauth_authorize_temp_token") .textValue() + "/"; this.config.oauth_get_temp_token = root.get("config").get("oauth_get_temp_token").textValue() + "/"; this.config.oauth_get_token = root.get("config").get("oauth_get_token").textValue() + "/"; this.config.get_user_games = root.get("config").get("get_user_games").textValue() + "/"; this.config.get_user_details = root.get("config").get("get_user_details").textValue() + "/"; this.config.get_installer_link = root.get("config").get("get_installer_link").textValue() + "/"; this.config.get_game_details = root.get("config").get("get_game_details").textValue() + "/"; this.config.get_extra_link = root.get("config").get("get_extra_link").textValue() + "/"; this.config.set_app_status = root.get("config").get("set_app_status").textValue() + "/"; res = true; } catch (IOException e) { throw new RuntimeException(e); } } else { this.setError("Found nothing in " + url); res = false; } return res; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#login(java.lang.String, * java.lang.String) */ @Override public final boolean login(String email, String password) { boolean res = false; String url; try { password = URLEncoder.encode(password, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } try { email = URLEncoder.encode(email, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } // Get temporary request token url = this.config.oauth_get_temp_token + "?oauth_consumer_key=" + Global.CONSUMER_KEY + "&oauth_consumer_key_secret=" + Global.CONSUMER_SECRET + "&oauth_timestamp=" + (System.currentTimeMillis() / 1000) + "&oauth_nonce=" + UUID.randomUUID() + "&oauth_signature_method=HMAC-SHA1&oauth_version=1.0"; String request_token_resp; try { request_token_resp = this.getResponse(url); } catch (AccessException e) { return false; } // Authorize temporary token and get verifier url = this.config.oauth_authorize_temp_token + "?oauth_consumer_key=" + Global.CONSUMER_KEY + "&oauth_consumer_key_secret=" + Global.CONSUMER_SECRET + "&oauth_timestamp=" + (System.currentTimeMillis() / 1000) + "&oauth_nonce=" + UUID.randomUUID() + "&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&" + request_token_resp + "&username=" + email + "&password=" + password; String authorize_resp; try { authorize_resp = this.getResponse(url); } catch (AccessException e) { return false; } // Get final token and secret url = this.config.oauth_get_token + "" + authorize_resp + "&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_consumer_key=" + Global.CONSUMER_KEY + "&oauth_timestamp=" + (System.currentTimeMillis() / 1000) + "&oauth_nonce=" + UUID.randomUUID() + "&oauth_consumer_key_secret=" + Global.CONSUMER_SECRET; String token_resp; try { token_resp = this.getResponse(url); } catch (AccessException e) { return false; } String[] token_resp_array = token_resp.split("&"); if (token_resp_array.length < 2) { throw new RuntimeException(token_resp); } this.config.oauth_token = token_resp_array[0].replace("oauth_token=", ""); this.config.oauth_secret = token_resp_array[1].replace("oauth_token_secret=", ""); res = true; return res; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getUserDetails() */ @Override public final boolean getUserDetails() { boolean res = false; String url = this.config.get_user_details; String json = this.getResponseOAuth(url); if (json != "") { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(fixjson(json)); this.user.id = root.get("user").get("id").longValue(); this.user.username = root.get("user").get("xywka").textValue(); this.user.email = root.get("user").get("email").textValue(); this.user.avatar_big = root.get("user").get("avatar").get("big").textValue(); this.user.avatar_small = root.get("user").get("avatar").get("small").textValue(); this.user.notifications_forum = root.get("user").get("notifications").get("forum").intValue(); this.user.notifications_games = root.get("user").get("notifications").get("games").intValue(); this.user.notifications_messages = root.get("user").get("notifications").get("messages").intValue(); res = true; } catch (IOException e) { throw new RuntimeException(e); } } else { this.setError("Found nothing in " + url); res = false; } return res; } private String fixjson(String json) { json = json.replaceAll("\"\\{", "{").replaceAll("\\}\"", "}"); Pattern p = Pattern.compile("\"html\":\"<(.+)>\""); Matcher m = p.matcher(json); while (m.find()) { String orgHtml = m.group(1); String html = orgHtml.replace("\"", "\\\""); json = json.replace(orgHtml, html); } return json; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getResponse(java.lang.String) */ @Override public final String getResponse(String url) throws AccessException { String response = ""; try { response = IOUtils.toString(new InputStreamReader(new URL(url).openStream())); } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (IOException e) { throw new AccessException("access to url denied:" + url); } return org.apache.commons.lang3.StringEscapeUtils.unescapeJson(response); } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getResponseOAuth(java.lang.String) */ @Override public final String getResponseOAuth(String url) { String response = ""; String url_oauth = url + "?oauth_consumer_key=" + Global.CONSUMER_KEY + "&oauth_consumer_key_secret=" + Global.CONSUMER_SECRET + "&oauth_token=" + this.config.oauth_token + "&oauth_token_secret=" + this.config.oauth_secret + "&oauth_timestamp=" + (System.currentTimeMillis() / 1000) + "&oauth_nonce=" + UUID.randomUUID() + "&oauth_signature_method=HMAC-SHA1&oauth_version=1.0"; try { response = this.getResponse(url_oauth); } catch (AccessException e) { return ""; } return response; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getGameDetails(java.lang.String, int, * int, boolean) */ @Override public final GameDetails getGameDetails(String game_name, int type, int lang, boolean useDuplicateHandler) { String url; GameDetails game = new GameDetails(); url = this.config.get_game_details + game_name + "/" + "installer_win_en"; // can't get game details without file id, // any file id seems to return all // details which is good for us String json = this.getResponseOAuth(url); if (!json.isEmpty()) { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); game.gamename = game_name; game.title = root.get("game").get("title").textValue(); game.icon = root.get("game").get("icon").textValue(); // Installer details // Create a list of installers from JSON // java.util.ArrayList<std.pair<Json.Value,Integer>> installers // = new java.util.ArrayList<std.pair<Json.Value,Integer>>(); List<Installer> installers = new ArrayList<Installer>(); for (int i = 0; i < GlobalConstants.PLATFORMS.size(); ++i) { if ((type & GlobalConstants.PLATFORMS.get(i).platformId) != 0) { String installer = "installer_" + GlobalConstants.PLATFORMS.get(i).platformCode + "_"; for (int j = 0; j < GlobalConstants.LANGUAGES.size(); ++j) { if ((lang & GlobalConstants.LANGUAGES.get(j).languageId) != 0) { if (installer != null) { JsonNode installerNode = root.get("game") .get(installer + GlobalConstants.LANGUAGES.get(j).languageCode); for (JsonNode node : installerNode) { installers.add(new Installer(node.get("id").textValue(), node.get("name").textValue(), node.get("link").textValue(), node.get("size").asLong(), GlobalConstants.LANGUAGES.get(j).languageId, node.get("notificated").asBoolean(), node.get("silent").asInt())); } } } } } } // Check for duplicate installers in different languages // and add languageId of duplicate installer to the original // installer // https://secure.gog.com/forum/general/introducing_the_beta_release_of_the_new_gogcom_downloader/post1483 if (useDuplicateHandler) { Iterator<Installer> it1 = installers.iterator(); while (it1.hasNext()) { Installer installer = it1.next(); Iterator<Installer> it2 = installers.iterator(); while (it2.hasNext()) { Installer installer2 = it2.next(); if (installer != installer2) { if (installer.getUrl().equals(installer2.getUrl())) { it2.remove(); } } } } } for (Installer installer : installers) { game.installers.add(new GameFile(installer.getNotificated(), installer.getId(), installer.getName(), installer.getUrl(), installer.getSize(), installer.getLanguageId(), installer.getSilent())); } // Extra details JsonNode extras = root.get("game").get("extras"); for (int index = 0; index < extras.size(); ++index) { JsonNode extra = extras.get(index); game.extras.add(new GameFile(false, extra.get("id").textValue(), extra.get("name").textValue(), extra.get("link").textValue(), extra.get("size_mb").asLong(), 0, 0)); // extras don't have "updated" // flag } // Patch details for (int i = 0; i < GlobalConstants.LANGUAGES.size(); ++i) { // Check // against // the // specified // languages if ((lang & GlobalConstants.LANGUAGES.get(i).languageId) != 0) { // Try to find a patch int patch_number = 0; final int maxTries = 8; java.util.ArrayList<String> patchnames = new java.util.ArrayList<String>(); while (patch_number < maxTries) { int patch_number_file = 0; while (patch_number_file < maxTries) { String patchname = GlobalConstants.LANGUAGES.get(i).languageCode + patch_number + "patch" + patch_number_file; /* * if (root.get("game").isMember(patchname)) // * Check that patch node exists { * patchnames.add(patchname); } */ patch_number_file++; } patch_number++; } if (patchnames.size() > 0) // found at least one patch { for (int j = 0; j < patchnames.size(); ++j) { JsonNode patchnode = root.get("game").get(patchnames.get(j)); if (patchnode.isArray()) // Patch has multiple // files { for (int index = 0; index < patchnode.size(); ++index) { JsonNode patch = patchnode.get(index); game.patches.add(new GameFile(false, patch.get("id").textValue(), patch.get("name").textValue(), patch.get("link").textValue(), patch.get("size").asLong(), GlobalConstants.LANGUAGES.get(j).languageId, 0)); // patches // don't // have // "updated" // flag } } else // Patch is a single file { game.patches.add(new GameFile(false, patchnode.get("id").textValue(), patchnode.get("name").textValue(), patchnode.get("link").textValue(), patchnode.get("size").asLong(), GlobalConstants.LANGUAGES.get(j).languageId, 0)); // patches don't have // "updated" flag } } } } } // Language pack details for (int i = 0; i < GlobalConstants.LANGUAGES.size(); ++i) { // Check // against // the // specified // languages if ((lang & GlobalConstants.LANGUAGES.get(i).languageId) != 0) { // Try to find a language pack int lang_pack_number = 0; final int maxTries = 4; java.util.ArrayList<String> langpacknames = new java.util.ArrayList<String>(); while (lang_pack_number < maxTries) { int lang_pack_number_file = 0; while (lang_pack_number_file < maxTries) { String langpackname = GlobalConstants.LANGUAGES.get(i).languageCode + lang_pack_number + "langpack" + lang_pack_number_file; /* * if (root.get("game").isMember(langpackname)) * // Check that language pack node exists { * langpacknames.add(langpackname); } */ lang_pack_number_file++; } lang_pack_number++; } if (langpacknames.size() > 0) // found at least one // language pack { for (int j = 0; j < langpacknames.size(); ++j) { JsonNode langpack = root.get("game").get(langpacknames.get(j)); game.languagepacks.add(new GameFile(false, langpack.get("id").textValue(), langpack.get("name").textValue(), langpack.get("link").textValue(), langpack.get("size").asLong(), GlobalConstants.LANGUAGES.get(j).languageId, 0)); // language // packs // don't // have // "updated" // flag } } } } } catch (IOException e) { throw new RuntimeException(e); } } else { this.setError("Found nothing in " + url); } return game; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getInstallerLink(java.lang.String, * java.lang.String) */ @Override public final String getInstallerLink(String game_name, String id) { String url; String link = ""; url = this.config.get_installer_link + game_name + "/" + id + "/"; String json = this.getResponseOAuth(url); if (json != "") { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); int available = root.get("file").get("available").intValue(); if (available != 0) { link = root.get("file").get("link").textValue(); } } catch (IOException e) { throw new RuntimeException(e); } } else { this.setError("Found nothing in " + url); } return link; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getExtraLink(java.lang.String, * java.lang.String) */ @Override public final String getExtraLink(String game_name, String id) { String url; String link = ""; url = this.config.get_extra_link + game_name + "/" + id + "/"; String json = this.getResponseOAuth(url); if (json != "") { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); int available = root.get("file").get("available").intValue(); if (available != 0) { link = root.get("file").get("link").textValue(); } } catch (IOException e) { throw new RuntimeException(e); } } else { this.setError("Found nothing in " + url); } return link; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getPatchLink(java.lang.String, * java.lang.String) */ @Override public final String getPatchLink(String game_name, String id) { return this.getInstallerLink(game_name, id); } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getLanguagePackLink(java.lang.String, * java.lang.String) */ @Override public final String getLanguagePackLink(String game_name, String id) { return this.getInstallerLink(game_name, id); } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getXML(java.lang.String, * java.lang.String) */ @Override public final String getXML(String game_name, String id) { String url = ""; String XML = ""; url = this.config.get_installer_link + game_name + "/" + id + "/crc/"; String json = this.getResponseOAuth(url); if (json != "") { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); int available = root.get("file").get("available").intValue(); if (available != 0) { url = root.get("file").get("link").textValue(); XML = this.getResponse(url); } } catch (IOException e) { throw new RuntimeException(e); } } else { this.setError("Found nothing in " + url); } return XML; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#clearError() */ @Override public final void clearError() { this.error = false; this.error_message = ""; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#setError(java.lang.String) */ @Override public final void setError(String err) { this.error = true; if (this.error_message == null) { this.error_message = err; } else { this.error_message += "\n" + err; } } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getError() */ @Override public final boolean getError() { return this.error; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getErrorMessage() */ @Override public final String getErrorMessage() { return this.error_message; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getToken() */ @Override public final String getToken() { return this.config.oauth_token; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getSecret() */ @Override public final String getSecret() { return this.config.oauth_secret; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#searchGames(java.lang.String) */ @Override public List<Game> searchGames(String search) { if ((search == null) || (search.isEmpty())) { throw new RuntimeException("wrong search parameter!"); } try { String url = "http://www.gog.com/games/ajax?a=search&f=%7B%22search%22%3A%22" + URLEncoder.encode(URLEncoder.encode(search, "UTF-8"), "UTF-8") + "%22%2C%22sort%22%3A%22rating%22%7D&p=1&t=all"; ObjectMapper mapper = new ObjectMapper(); String json = this.getResponse(url); json = json.replaceAll("\\=\"([^\"]+)\"", "=\\\\\"$1\\\\\""); JsonNode root = mapper.readTree(json); JsonNode result = root.get("result"); String html = result.get("html").textValue(); org.jsoup.nodes.Document doc = Jsoup.parse(html); Elements links = doc.select("div.gog-price.game-owned"); List<Game> games = new ArrayList<>(); for (org.jsoup.nodes.Element link : links) { String game = link.attr("data-gameindex"); String id = link.attr("data-gameid"); if (game != "" && id != "") { games.add(new Game(id, game)); } } return games; } catch (IOException e) { throw new RuntimeException("Wrong search parameter or output!", e); } } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getFreeGames() */ @Override public final List<Game> getFreeGames() { List<Game> games = new ArrayList<Game>(); try { JsonNode root; ObjectMapper jsonparser = new ObjectMapper(); String json = this.getResponse( "https://secure.gog.com/games/ajax?a=search&f={\"price\":[\"free\"],\"sort\":\"title\"}&p=1&t=all"); // Parse JSON root = jsonparser.readTree(fixjson(json)); String html = root.get("result").get("html").textValue(); // Parse HTML to get game names org.jsoup.nodes.Document doc = Jsoup.parse(html); Elements links = doc.select("span.gog-price"); for (org.jsoup.nodes.Element link : links) { String game = link.attr("data-gameindex"); String id = link.attr("data-gameid"); if (game != "" && id != "") { games.add(new Game(id, game)); } } } catch (IOException e) { throw new RuntimeException(e); } return games; } /* * (non-Javadoc) * * @see org.crazyt.xgogdownloader.IApi#getGames() */ @Override public final List<Game> getGames() { List<Game> games = new ArrayList<Game>(); JsonNode root; ObjectMapper jsonparser = new ObjectMapper(); int i = 1; String html = ""; String page_html = ""; do { try { String response = this.getResponse( "https://secure.gog.com/en/account/ajax?a=gamesShelfMore&s=title&q=&t=0&p=" + i); root = jsonparser.readTree(response); // Parse JSON page_html = root.get("html").textValue(); html += page_html; i++; } catch (IOException e) { throw new RuntimeException(e); } } while (page_html != ""); // Parse HTML to get game names org.jsoup.nodes.Document doc = Jsoup.parse(html); Elements links = doc.select("div.shelf_game"); for (org.jsoup.nodes.Element link : links) { String game = link.attr("data-gameindex"); String gameid = link.attr("data-gameid"); if (game != "" && gameid != "") { games.add(new Game(gameid, game)); } } return games; } @Override public UserDetails getUser() { return user; } }