public static void Initialize(bool verbose = true) { // Set the log handler for when hash mismatches or wrong sizes FileEntry.Log = Log; using (HttpClient client = new HttpClient()) { // Declare for analytics that we are downloading from NXLDownloader client.DefaultRequestHeaders.Add("User-Agent", UserAgent); if (verbose) { Console.WriteLine("Getting list of products"); } // If there's an exception here, we can't recover ProductEntriesList productList = JsonConvert.DeserializeObject <ProductEntriesList>(client.GetStringAsync("http://nexon.ws/api/gms/products").Result); if (verbose) { Console.WriteLine($"Found {productList.Products.Length} products, downloading info"); } Products = productList.Products.Select(c => { try { string productDetails; if (AuthInfo == null) { productDetails = client.GetStringAsync(c.ProductLink).Result; } else { client.DefaultRequestHeaders.Add("Authorization", $"bearer {Convert.ToBase64String(Encoding.UTF8.GetBytes(AuthInfo.access_token))}"); productDetails = client.GetStringAsync($"https://api.nexon.io/products/{c.ProductId}").Result; } return(JsonConvert.DeserializeObject <Product>(productDetails)); } catch (Exception ex) { if (verbose) { Console.WriteLine($"Error downloading product details for {c.ProductId}, skipping"); } return(null); } }).Where(c => c != null).ToArray(); } }
static void GetStuff(string[] args) { Product selected = null; string hash = GetFlagValue(args, "-h"); Manifest manifest = null; string productSelected = GetFlagValue(args, "-p"); bool autoYes = args.Any(c => c.StartsWith("-y")); // Set the log handler for when hash mismatches or wrong sizes FileEntry.Log = Log; HttpClient client = new HttpClient(); Console.WriteLine("Getting list of products"); // If there's an exception here, we can't recover ProductEntriesList productList = JsonConvert.DeserializeObject <ProductEntriesList>(client.GetStringAsync("http://nexon.ws/api/gms/products").Result); Console.WriteLine($"Found {productList.Products.Length} products, downloading info"); Product[] products = productList.Products.Select(c => { try { string productDetails = client.GetStringAsync(c.ProductLink).Result; return(JsonConvert.DeserializeObject <Product>(productDetails)); } catch (Exception ex) { Console.WriteLine($"Error downloading product details for {c.ProductId}, skipping"); return(null); } }).Where(c => c != null).ToArray(); while (selected == null || hash == null) { while (selected == null) { for (int i = 0; i < products.Length; ++i) { Product product = products[i]; Console.WriteLine($"[{i}] {product.ProductId} {product.FriendlyProductName ?? product.ProductName}"); } if (products.Length != 0) { Console.Write($"Enter product number (0-{products.Length-1}): "); } else { Console.WriteLine("Enter product ID: "); } if (string.IsNullOrWhiteSpace(productSelected)) { productSelected = Console.ReadLine().Trim('\r', '\n', ' '); } if (int.TryParse(productSelected, out int productId)) { if (productId < products.Length) { selected = products[productId]; } else { selected = products.FirstOrDefault(c => c.ProductId.Equals(productId.ToString())); } if (selected == null) { Console.WriteLine("Unknown product ID, attempting to download info"); try { string details = client.GetStringAsync($"http://nexon.ws/api/gms/products/{productSelected}").Result; selected = JsonConvert.DeserializeObject <Product>(details); } catch (Exception ex) { Console.WriteLine("Couldn't get product info"); Console.WriteLine(ex.Message); } } } productSelected = null; if (selected == null) { Console.WriteLine("Invalid product selected."); } else { Console.WriteLine($"{selected.FriendlyProductName ?? selected.ProductName} selected."); } } Console.WriteLine("Downloading possible manifest hashes"); KeyValuePair <string, Tuple <string, string> >[] hashes = selected.Details.Branches .SelectMany(c => c.Value) .Append(new KeyValuePair <string, string>("Main", selected.Details.ManifestURL)) .Where(c => c.Value != null) .Select(c => { string manifestHash = null; try { manifestHash = client.GetStringAsync(c.Value).Result; } catch (Exception ex) { Console.WriteLine("Error downloading manifest's hash, skipping"); manifestHash = null; } return(new KeyValuePair <string, Tuple <string, string> >(c.Key, new Tuple <string, string>(manifestHash, c.Value))); }) .Where(c => c.Value.Item1 != null) .ToArray(); while (hash == null) { for (int i = 0; i < hashes.Length; ++i) { KeyValuePair <string, Tuple <string, string> > manifestHash = hashes[i]; Console.WriteLine($"[{i}] {manifestHash.Key} {manifestHash.Value.Item1} @ {manifestHash.Value.Item2}"); } if (hashes.Length == 0) { Console.Write("No manifests found, enter manifest hash to attempt to download: "); } else { Console.Write($"Select manifest (0-{hashes.Length-1}): "); } hash = Console.ReadLine().Trim('\r', '\n', ' '); if (int.TryParse(hash, out int hashIndex)) { hash = hashes[hashIndex].Value.Item1; } else if (string.IsNullOrEmpty(hash)) { hash = null; selected = null; Console.WriteLine("Returning to product selection"); break; } else if (hash.Length != 40) { hash = null; } if (hash == null) { Console.WriteLine("Invalid hash selected"); } else { Console.WriteLine("Downloading manifest"); try { byte[] ManifestCompressed = client.GetByteArrayAsync($"https://download2.nexon.net/Game/nxl/games/{selected.ProductId}/{hash}").Result; // Parse the manifest manifest = Manifest.Parse(ManifestCompressed); } catch (Exception ex) { Console.WriteLine("Error getting manifest"); Console.WriteLine(ex.Message); hash = null; } } } if (manifest != null && !autoYes) { Console.WriteLine($"Selected {manifest.BuiltAt} of {manifest.Product}"); Console.WriteLine($"This download will be {manifest.TotalCompressedSize} and will take up {manifest.TotalUncompressedSize} disk space"); Console.Write("Continue? [Y]/N: "); if (Console.ReadLine().Trim('\r', '\n', ' ').Equals("N", StringComparison.CurrentCultureIgnoreCase)) { hash = null; manifest = null; Console.WriteLine("Returning to hash selection"); } } } client.Dispose(); Download(manifest, selected, hash); }