public static async Task DownloadTitle(string id, string outputDir, string contentType, string version) { #region Setup var workingId = id.ToUpper(); if (contentType == "Patch") { workingId = $"0005000E{workingId.Substring(8)}"; if (Settings.Cemu173Patch) { outputDir = Path.Combine(Settings.BasePatchDir, workingId.Substring(8)); } } if (contentType == "DLC") { workingId = $"0005000C{workingId.Substring(8)}"; if (Settings.Cemu173Patch) { outputDir = Path.Combine(Settings.BasePatchDir, workingId.Substring(8), "aoc"); } } Title title; if ((title = SearchById(workingId)) == null) { throw new Exception("Could not locate the title key"); } var key = title.Key; var name = title.Name; if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(name)) { return; } if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } var str = $"Download {contentType} content to the following location?\n\"{outputDir}\""; var result = MessageBox.Show(str, name, MessageBoxButtons.YesNo); if (result != DialogResult.Yes) { return; } Toolbelt.AppendLog($"Output Directory '{outputDir}'"); #endregion #region TMD Toolbelt.AppendLog(" - Loading TMD..."); TMD tmd = null; var nusUrls = new List <string> { "http://ccs.cdn.wup.shop.nintendo.net/ccs/download/", "http://nus.cdn.shop.wii.com/ccs/download/", "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/" }; foreach (var nusUrl in nusUrls) { string titleUrl = $"{nusUrl}{workingId}/"; tmd = await LoadTmd(id, key, outputDir, titleUrl, version); if (tmd != null) { break; } } if (tmd == null) { TextLog.MesgLog.WriteError("Could not locate TMD. Is this content request valid?"); return; } #endregion #region Ticket Toolbelt.AppendLog("Generating Ticket..."); var tikData = MapleTicket.Create(SearchById(id)); if (tikData == null) { throw new Exception("Invalid ticket data. Verify Title ID."); } var ticket = Ticket.Load(tikData); ticket.Save(Path.Combine(outputDir, "cetk")); #endregion #region Content Toolbelt.AppendLog($"[+] [{contentType}] {name} v{tmd.TitleVersion}"); Toolbelt.SetStatus($"Output Directory: {outputDir}"); foreach (var nusUrl in nusUrls) { var url = nusUrl + workingId; if (await DownloadContent(tmd, outputDir, url) != 1) { continue; } Toolbelt.AppendLog(string.Empty); Toolbelt.AppendLog(" - Decrypting Content"); Toolbelt.AppendLog(" + This may take a minute. Please wait..."); Toolbelt.SetStatus("Decrypting Content. This may take a minute. Please wait...", Color.OrangeRed); if (await Toolbelt.CDecrypt(outputDir) != 0) { CleanUp(outputDir, tmd); Toolbelt.AppendLog($"Error while decrypting {name}"); return; } CleanUp(outputDir, tmd); break; } #endregion Web.ResetDownloadProgressChanged(); Toolbelt.AppendLog($"[+] [{contentType}] {name} v{tmd.TitleVersion} Finished."); Toolbelt.SetStatus($"[+] [{contentType}] {name} v{tmd.TitleVersion} Finished."); }
private static void DownloadTitle(string id, string outputDir, string contentType, string version) { #region Setup var workingId = id.ToUpper(); //download dlc if applicable if (contentType == "DLC") { workingId = $"0005000C{workingId.Substring(8).ToUpper()}"; } //download patch if applicable if (contentType == "Patch") { workingId = $"0005000E{workingId.Substring(8).ToUpper()}"; } var title = Database.FindTitleKey(workingId); if (title.titleKey.Length != 32) { throw new Exception("Could not locate the title key"); } var key = title.titleKey; var name = title.name; if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(name)) { return; } var result = MessageBoxResult.Cancel; var str = $"Download {contentType} content to the following location?\n\"{outputDir}\""; Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { result = MessageBox.Show(Application.Current.MainWindow, str, name, MessageBoxButton.YesNo); })); if (result != MessageBoxResult.Yes) { return; } if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } Toolbelt.AppendLog($"Output Directory '{outputDir}'"); #endregion #region TMD Toolbelt.AppendLog(" - Loading TMD..."); TMD tmd = null; var nusUrls = new List <string> { "http://ccs.cdn.wup.shop.nintendo.net/ccs/download/", "http://nus.cdn.shop.wii.com/ccs/download/", "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/" }; foreach (var nusUrl in nusUrls) { var titleUrl = $"{nusUrl}{workingId}/"; tmd = LoadTmd(workingId, key, outputDir, titleUrl, version); if (tmd != null) { break; } } if (tmd == null) { TextLog.MesgLog.WriteError("Could not locate TMD. Is this content request valid?"); return; } #endregion #region Ticket Toolbelt.AppendLog("Generating Ticket..."); var tikData = MapleTicket.Create(Database.FindTitleKey(workingId)); if (tikData == null) { throw new Exception("Invalid ticket data. Verify Title ID."); } var ticket = Ticket.Load(tikData); ticket.Save(Path.Combine(outputDir, "cetk")); #endregion #region Content Toolbelt.AppendLog($"[+] [{contentType}] {name} v{tmd.TitleVersion}"); Toolbelt.SetStatus($"Output Directory: {outputDir}"); foreach (var nusUrl in nusUrls) { var url = nusUrl + workingId; if (DownloadContent(tmd, outputDir, url) != 1) { continue; } Toolbelt.AppendLog(string.Empty); Toolbelt.AppendLog(" - Decrypting Content"); Toolbelt.AppendLog(" + This may take a minute. Please wait..."); Toolbelt.SetStatus("Decrypting Content. This may take a minute. Please wait...", Color.OrangeRed); if (Toolbelt.CDecrypt(outputDir) != 0) { CleanUp(outputDir, tmd); Toolbelt.AppendLog($"Error while decrypting {name}"); return; } CleanUp(outputDir, tmd); break; } #endregion Web.ResetDownloadProgressChanged(); Toolbelt.AppendLog($"[+] [{contentType}] {name} v{tmd.TitleVersion} Finished."); Toolbelt.SetStatus($"[+] [{contentType}] {name} v{tmd.TitleVersion} Finished."); }
/// <summary> /// Grabs a title from NUS, you can define several store types. /// Leave the title version empty for the latest. /// </summary> /// <param name="titleId"></param> /// <param name="titleVersion"></param> /// <param name="outputDir"></param> /// <param name="storeTypes"></param> public void DownloadTitle(string titleId, string titleVersion, string outputDir, StoreType[] storeTypes) { FireDebug("Downloading Title {0} v{1}...", titleId, (string.IsNullOrEmpty(titleVersion)) ? "[Latest]" : titleVersion); if (storeTypes.Length < 1) { FireDebug(" No store types were defined..."); throw new Exception("You must at least define one store type!"); } var titleInfo = Database.GetTitle(titleId); string titleUrl = $"{nusUrl}{titleId}/"; string titleUrl2 = $"{nusUrl2}{titleId}/"; bool storeEncrypted = false; bool storeDecrypted = false; FireProgress(0); foreach (StoreType st in storeTypes) { switch (st) { case StoreType.DecryptedContent: FireDebug(" [=] Storing Decrypted Content..."); storeDecrypted = true; break; case StoreType.EncryptedContent: FireDebug(" [=] Storing Encrypted Content..."); storeEncrypted = true; break; case StoreType.All: FireDebug(" [=] Storing Decrypted Content..."); FireDebug(" [=] Storing Encrypted Content..."); FireDebug(" [=] Storing WAD..."); storeDecrypted = true; storeEncrypted = true; break; case StoreType.Empty: break; } } FireDebug(" - Checking for Internet connection..."); if (!CheckInet()) { FireDebug(" + Connection not found..."); throw new Exception("You're not connected to the internet!"); } if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } if (!Directory.Exists(Path.Combine(outputDir, titleInfo.Name))) { Directory.CreateDirectory(Path.Combine(outputDir, titleInfo.Name)); } outputDir = Path.Combine(outputDir, titleInfo.Name); string tmdFile = "tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : string.Format(".{0}", titleVersion)); //Download TMD FireDebug(" - Downloading TMD..."); TMD tmd; byte[] tmdFileWithCerts; try { tmdFileWithCerts = wcNus.DownloadData(titleUrl + tmdFile); tmd = TMD.Load(tmdFileWithCerts); } catch (Exception ex) { FireDebug(" + Downloading TMD Failed..."); throw new Exception("Downloading TMD Failed:\n" + ex.Message); } //Parse TMD FireDebug(" - Parsing TMD..."); if (string.IsNullOrEmpty(titleVersion)) { FireDebug(" + Title Version: {0}", tmd.TitleVersion); } FireDebug(" + {0} Contents", tmd.NumOfContents); if (!Directory.Exists(Path.Combine(outputDir, tmd.TitleVersion.ToString()))) { Directory.CreateDirectory(Path.Combine(outputDir, tmd.TitleVersion.ToString())); } outputDir = Path.Combine(outputDir, tmd.TitleVersion.ToString()); titleversion = tmd.TitleVersion; File.WriteAllBytes(Path.Combine(outputDir, tmdFile), tmdFileWithCerts); FireProgress(5); //Download cetk FireDebug(" - Downloading Ticket..."); try { wcNus.DownloadFile(Path.Combine(titleUrl, "cetk"), Path.Combine(outputDir, "cetk")); } catch (Exception ex) { try { if (titleInfo.Ticket == "1") { var cetkUrl = $"{WII_TIK_URL}{titleId.ToLower()}.tik"; wcNus.DownloadFile(cetkUrl, Path.Combine(outputDir, "cetk")); } } catch { continueWithoutTicket = false; if (!continueWithoutTicket || !storeEncrypted) { FireDebug(" + Downloading Ticket Failed..."); throw new Exception("Downloading Ticket Failed:\n" + ex.Message); } if (!(File.Exists(Path.Combine(outputDir, "cetk")))) { storeDecrypted = false; } } } FireProgress(10); // Parse Ticket Ticket tik = new Ticket(); if (File.Exists(Path.Combine(outputDir, "cetk"))) { FireDebug(" + Parsing Ticket..."); tik = Ticket.Load(Path.Combine(outputDir, "cetk")); // DSi ticket? Must make sure to use DSi Key :D if (nusUrl == DSI_NUS_URL) { tik.DSiTicket = true; } } else { FireDebug(" + Ticket Unavailable..."); } string[] encryptedContents = new string[tmd.NumOfContents]; //Download Content for (int i = 0; i < tmd.NumOfContents; i++) { Form1.token.ThrowIfCancellationRequested(); var size = Toolbelt.SizeSuffix(tmd.Contents[i].Size); FireDebug(" - Downloading Content #{0} of {1}... ({2} bytes)", i + 1, tmd.NumOfContents, size); FireProgress(((i + 1) * 60 / tmd.NumOfContents) + 10); var contentPath = Path.Combine(outputDir, tmd.Contents[i].ContentID.ToString("x8")); if (useLocalFiles && Toolbelt.IsValid(tmd.Contents[i], contentPath)) { FireDebug(" + Using Local File, Skipping..."); continue; } try { var downloadUrl = titleUrl + tmd.Contents[i].ContentID.ToString("x8"); var outputdir = Path.Combine(outputDir, tmd.Contents[i].ContentID.ToString("x8")); wcNus.DownloadFile(downloadUrl, outputdir); encryptedContents[i] = tmd.Contents[i].ContentID.ToString("x8"); } catch (Exception ex) { FireDebug(" - Downloading Content #{0} of {1} failed...", i + 1, tmd.NumOfContents); throw new Exception("Downloading Content Failed:\n" + ex.Message); } } //Decrypt Content if (storeDecrypted) { FireDebug(" - Decrypting Content..."); Toolbelt.CDecrypt(this, outputDir); } //Delete not wanted files if (!storeEncrypted) { FireDebug(" - Deleting Encrypted Contents..."); for (int i = 0; i < tmd.Contents.Length; i++) { if (File.Exists(Path.Combine(outputDir, tmd.Contents[i].ContentID.ToString("x8")))) { File.Delete(Path.Combine(outputDir, tmd.Contents[i].ContentID.ToString("x8"))); } } } if (!storeDecrypted && !storeEncrypted) { FireDebug(" - Deleting TMD and Ticket..."); File.Delete(Path.Combine(outputDir, tmdFile)); File.Delete(Path.Combine(outputDir, "cetk")); } FireDebug("Downloading Title {0} v{1} Finished...", titleId, tmd.TitleVersion /*(string.IsNullOrEmpty(titleVersion)) ? "[Latest]" : titleVersion*/); FireProgress(100); }