diff --git a/LANCommander.Playnite.Extension/InstallController.cs b/LANCommander.Playnite.Extension/InstallController.cs index 1f621fe..f4b206c 100644 --- a/LANCommander.Playnite.Extension/InstallController.cs +++ b/LANCommander.Playnite.Extension/InstallController.cs @@ -39,19 +39,9 @@ namespace LANCommander.PlaynitePlugin var gameId = Guid.Parse(Game.GameId); var game = Plugin.LANCommander.GetGame(gameId); - string tempDownloadLocation; - - if (Plugin.DownloadCache.ContainsKey(gameId)) - tempDownloadLocation = Plugin.DownloadCache[gameId]; - else - { - tempDownloadLocation = Download(game); - Plugin.DownloadCache[gameId] = tempDownloadLocation; - } - var installDirectory = RetryHelper.RetryOnException(10, TimeSpan.FromMilliseconds(500), "", () => { - return Extract(game, tempDownloadLocation); + return DownloadAndExtract(game); }); if (installDirectory == "") @@ -97,11 +87,51 @@ namespace LANCommander.PlaynitePlugin Plugin.UpdateGame(manifest, gameId); Plugin.DownloadCache.Remove(gameId); - File.Delete(tempDownloadLocation); InvokeOnInstalled(new GameInstalledEventArgs(installInfo)); } + private string DownloadAndExtract(LANCommander.SDK.Models.Game game) + { + if (game == null) + { + throw new Exception("Game failed to download!"); + } + + var destination = Path.Combine(Plugin.Settings.InstallDirectory, game.Title.SanitizeFilename()); + + Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress => + { + Directory.CreateDirectory(destination); + progress.ProgressMaxValue = 100; + progress.CurrentProgressValue = 0; + + using (var gameStream = Plugin.LANCommander.StreamGame(game.Id)) + using (var reader = ReaderFactory.Open(gameStream)) + { + progress.ProgressMaxValue = gameStream.Length; + + gameStream.OnProgress += (pos, len) => + { + progress.CurrentProgressValue = pos; + }; + + reader.WriteAllToDirectory(destination, new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true + }); + } + }, + new GlobalProgressOptions($"Downloading {game.Title}...") + { + IsIndeterminate = false, + Cancelable = false, + }); + + return destination; + } + private string Download(LANCommander.SDK.Models.Game game) { string tempFile = String.Empty; diff --git a/LANCommander.Playnite.Extension/LANCommanderClient.cs b/LANCommander.Playnite.Extension/LANCommanderClient.cs index 787148e..990e825 100644 --- a/LANCommander.Playnite.Extension/LANCommanderClient.cs +++ b/LANCommander.Playnite.Extension/LANCommanderClient.cs @@ -1,7 +1,6 @@ using LANCommander.SDK; using LANCommander.SDK.Models; using RestSharp; -using RestSharp.Extensions; using System; using System.Collections.Generic; using System.ComponentModel; @@ -9,10 +8,7 @@ using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; -using System.Text; using System.Threading.Tasks; -using System.Windows.Media.Converters; -using YamlDotNet.Core; namespace LANCommander.PlaynitePlugin { @@ -64,6 +60,20 @@ namespace LANCommander.PlaynitePlugin return tempFile; } + private TrackableStream StreamRequest(string route) + { + route = route.TrimStart('/'); + + var client = new WebClient(); + var tempFile = Path.GetTempFileName(); + + client.Headers.Add("Authorization", $"Bearer {Token.AccessToken}"); + + var ws = client.OpenRead(new Uri($"{Client.BaseUrl}{route}")); + + return new TrackableStream(ws, true, Convert.ToInt64(client.ResponseHeaders["Content-Length"])); + } + public async Task AuthenticateAsync(string username, string password) { var response = await Client.ExecuteAsync(new RestRequest("/api/Auth", Method.POST).AddJsonBody(new AuthRequest() @@ -166,6 +176,11 @@ namespace LANCommander.PlaynitePlugin return DownloadRequest($"/api/Games/{id}/Download", progressHandler, completeHandler); } + public TrackableStream StreamGame(Guid id) + { + return StreamRequest($"/api/Games/{id}/Download"); + } + public string DownloadArchive(Guid id, Action progressHandler, Action completeHandler) { return DownloadRequest($"/api/Archives/Download/{id}", progressHandler, completeHandler); diff --git a/LANCommander.Playnite.Extension/TrackableStream.cs b/LANCommander.Playnite.Extension/TrackableStream.cs index e7b0c72..cff27f8 100644 --- a/LANCommander.Playnite.Extension/TrackableStream.cs +++ b/LANCommander.Playnite.Extension/TrackableStream.cs @@ -1,13 +1,16 @@ -using System.IO; +using System; +using System.IO; namespace LANCommander.PlaynitePlugin { - internal class TrackableStream : MemoryStream + internal class TrackableStream : MemoryStream, IDisposable { public delegate void OnProgressDelegate(long Position, long Length); public event OnProgressDelegate OnProgress = delegate { }; private long internalStreamProgress = 0; private Stream internalStream; + private bool disposeStream = false; + private long? streamLength; // // Summary: @@ -19,9 +22,11 @@ namespace LANCommander.PlaynitePlugin // Summary: // Initializes a new instance of the TrackableStream class with the contents of stream. // capacity initialized to zero. - public TrackableStream(Stream stream) : base() + public TrackableStream(Stream stream, bool disposeStream = false, long? streamLength = null) : base() { internalStream = stream; + this.disposeStream = disposeStream; + this.streamLength = streamLength; } // @@ -321,5 +326,15 @@ namespace LANCommander.PlaynitePlugin } return r; } + + public void Dispose() + { + if (disposeStream) + { + internalStream.Dispose(); + } + } + + public long Length => streamLength ?? internalStream.Length; } }