DownloadManager.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using UnityEngine;
  7. using UnityEngine.UI;
  8. namespace ZenFulcrum.EmbeddedBrowser {
  9. /**
  10. * Helper class for tracking and managing downloads.
  11. * You can manage and handle downloads without this, but you may find it useful for dealing with the more
  12. * common file downloading use cases.
  13. *
  14. * Usage: create one and call manager.ManageDownloads(browser) on a browser you want it to handle.
  15. * or throw one in the scene and set "manageAllBrowsers" to true (before loading the scene) for it
  16. * to automatically hook into all browsers that start in the scene.
  17. */
  18. public class DownloadManager : MonoBehaviour {
  19. [Tooltip("If true, this will find all the browser in the scene at startup and take control of their downloads.")]
  20. public bool manageAllBrowsers = false;
  21. [Tooltip("If true, a \"Save as\" style dialog will be given for all downloads.")]
  22. public bool promptForFileNames;
  23. [Tooltip("Where to save files. If null or blank, defaults to the user's downloads directory.")]
  24. public string saveFolder;
  25. [Tooltip("If given this text element will be updated with download status info.")]
  26. public Text statusBar;
  27. public class Download {
  28. public Browser browser;
  29. public int downloadId;
  30. public string name;
  31. public string path;
  32. public int speed;
  33. public int percent;
  34. public string status;
  35. }
  36. public List<Download> downloads = new List<Download>();
  37. public void Awake() {
  38. if (manageAllBrowsers) {
  39. foreach (var browser in FindObjectsOfType<Browser>()) {
  40. ManageDownloads(browser);
  41. }
  42. }
  43. }
  44. public void ManageDownloads(Browser browser) {
  45. browser.onDownloadStarted = (id, info) => {
  46. HandleDownloadStarted(browser, id, info);
  47. };
  48. browser.onDownloadStatus += (id, info) => {
  49. HandleDownloadStatus(browser, id, info);
  50. };
  51. }
  52. private void HandleDownloadStarted(Browser browser, int downloadId, JSONNode info) {
  53. //Debug.Log("Download requested: " + info.AsJSON);
  54. var download = new Download {
  55. browser = browser,
  56. downloadId = downloadId,
  57. name = info["suggestedName"],
  58. };
  59. if (promptForFileNames) {
  60. browser.DownloadCommand(downloadId, BrowserNative.DownloadAction.Begin, null);
  61. } else {
  62. DirectoryInfo downloadFolder;
  63. if (string.IsNullOrEmpty(saveFolder)) {
  64. downloadFolder = new DirectoryInfo(GetUserDownloadFolder());
  65. } else {
  66. downloadFolder = new DirectoryInfo(saveFolder);
  67. if (!downloadFolder.Exists) downloadFolder.Create();
  68. }
  69. var filePath = downloadFolder.FullName + "/" + new FileInfo(info["suggestedName"]).Name;
  70. while (File.Exists(filePath)) {
  71. var ext = Path.GetExtension(filePath);
  72. var left = Path.GetFileNameWithoutExtension(filePath);
  73. var time = DateTime.Now.ToString("yyyy-MM-dd hh_mm_ss");
  74. filePath = downloadFolder.FullName + "/" + left + " " + time + ext;
  75. }
  76. browser.DownloadCommand(downloadId, BrowserNative.DownloadAction.Begin, filePath);
  77. }
  78. downloads.Add(download);
  79. }
  80. private void HandleDownloadStatus(Browser browser, int downloadId, JSONNode info) {
  81. //Debug.Log("Download status: " + info.AsJSON);
  82. for (int i = 0; i < downloads.Count; i++) {
  83. if (downloads[i].browser != browser || downloads[i].downloadId != downloadId) continue;
  84. var download = downloads[i];
  85. download.status = info["status"];
  86. download.speed = info["speed"];
  87. download.percent = info["percentComplete"];
  88. if (!string.IsNullOrEmpty(info["fullPath"])) download.name = Path.GetFileName(info["fullPath"]);
  89. break;
  90. }
  91. }
  92. public void Update() {
  93. if (statusBar) {
  94. statusBar.text = Status;
  95. }
  96. }
  97. public void PauseAll() {
  98. for (int i = 0; i < downloads.Count; i++) {
  99. if (downloads[i].status == "working") {
  100. downloads[i].browser.DownloadCommand(downloads[i].downloadId, BrowserNative.DownloadAction.Pause);
  101. }
  102. }
  103. }
  104. public void ResumeAll() {
  105. for (int i = 0; i < downloads.Count; i++) {
  106. if (downloads[i].status == "working") {
  107. downloads[i].browser.DownloadCommand(downloads[i].downloadId, BrowserNative.DownloadAction.Resume);
  108. }
  109. }
  110. }
  111. public void CancelAll() {
  112. for (int i = 0; i < downloads.Count; i++) {
  113. if (downloads[i].status == "working") {
  114. downloads[i].browser.DownloadCommand(downloads[i].downloadId, BrowserNative.DownloadAction.Cancel);
  115. }
  116. }
  117. }
  118. public void ClearAll() {
  119. CancelAll();
  120. downloads.Clear();
  121. }
  122. private StringBuilder sb = new StringBuilder();
  123. /** Returns a string summarizing things that are downloading. */
  124. public string Status {
  125. get {
  126. if (downloads.Count == 0) return "";
  127. sb.Length = 0;
  128. var rate = 0;
  129. for (int i = downloads.Count - 1; i >= 0; i--) {
  130. if (sb.Length > 0) sb.Append(", ");
  131. sb.Append(downloads[i].name);
  132. if (downloads[i].status == "working") {
  133. if (downloads[i].percent >= 0) sb.Append(" (").Append(downloads[i].percent).Append("%)");
  134. else sb.Append(" (??%)");
  135. rate += downloads[i].speed;
  136. } else {
  137. sb.Append(" (").Append(downloads[i].status).Append(")");
  138. }
  139. }
  140. var ret = "Downloads";
  141. if (rate > 0) {
  142. ret += " (" + Mathf.Round(rate / (1024f * 1024) * 100) / 100f + "MiB/s)";
  143. }
  144. return ret + ": " + sb.ToString();
  145. }
  146. }
  147. /** Gets the user's download folder, creating it if needed. */
  148. public static string GetUserDownloadFolder() {
  149. switch (System.Environment.OSVersion.Platform) {
  150. case PlatformID.Win32NT: {
  151. IntPtr path;
  152. var r = SHGetKnownFolderPath(
  153. new Guid("{374DE290-123F-4565-9164-39C4925E467B}"), //downloads
  154. 0x8000, //KF_FLAG_CREATE
  155. IntPtr.Zero, //current user
  156. out path
  157. );
  158. if (r == 0) {
  159. var ret = Marshal.PtrToStringUni(path);
  160. Marshal.FreeCoTaskMem(path);
  161. return ret;
  162. } else {
  163. throw new Exception(
  164. "Failed to get user download directory",
  165. new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())
  166. );
  167. }
  168. }
  169. case PlatformID.Unix: {
  170. var path = System.Environment.GetEnvironmentVariable("HOME") + "/Downloads";
  171. var di = new DirectoryInfo(path);
  172. if (!di.Exists) di.Create();
  173. return path;
  174. }
  175. case PlatformID.MacOSX:
  176. throw new NotImplementedException();
  177. default:
  178. throw new NotImplementedException();
  179. }
  180. }
  181. [DllImport("Shell32.dll")]
  182. private static extern int SHGetKnownFolderPath(
  183. [MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags, IntPtr hToken,
  184. out IntPtr ppszPath
  185. );
  186. }
  187. }