diff --git a/PlexRequests.Api/SickrageApi.cs b/PlexRequests.Api/SickrageApi.cs index 9ecc535c2..4caa6033b 100644 --- a/PlexRequests.Api/SickrageApi.cs +++ b/PlexRequests.Api/SickrageApi.cs @@ -1,8 +1,7 @@ #region Copyright - // /************************************************************************ // Copyright (c) 2016 Jamie Rees -// File: CouchPotatoApi.cs +// File: SickrageApi.cs // Created By: Jamie Rees // // Permission is hereby granted, free of charge, to any person obtaining @@ -24,31 +23,28 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ -using Polly; - #endregion +using System.Linq; using System; -using System.ComponentModel; using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; + using NLog; + using PlexRequests.Api.Interfaces; using PlexRequests.Api.Models.SickRage; using PlexRequests.Helpers; -using RestSharp; -using Newtonsoft.Json.Linq; - using PlexRequests.Helpers.Exceptions; +using RestSharp; + namespace PlexRequests.Api { public class SickrageApi : ISickRageApi { - private static Logger Log = LogManager.GetCurrentClassLogger(); + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); public SickrageApi() { @@ -57,22 +53,38 @@ namespace PlexRequests.Api private ApiRequest Api { get; } - - public async Task AddSeries(int tvdbId, int seasonCount, int[] seasons, string quality, string apiKey, - Uri baseUrl) + public SickRageSeasonList VerifyShowHasLoaded(int tvdbId, string apiKey, Uri baseUrl) { + Log.Trace("Entered `VerifyShowHasLoaded({0} <- id)`", tvdbId); + var request = new RestRequest { Resource = "/api/{apiKey}/?cmd=show.seasonlist", Method = Method.GET }; + request.AddUrlSegment("apiKey", apiKey); + request.AddQueryParameter("tvdbid", tvdbId.ToString()); + try + { + var policy = RetryHandler.RetryAndWaitPolicy( + null, + (exception, timespan) => Log.Error(exception, "Exception when calling VerifyShowHasLoaded for SR, Retrying {0}", timespan)); + + var obj = policy.Execute(() => Api.ExecuteJson(request, baseUrl)); + return obj; + } + catch (Exception e) + { + Log.Error(e); + return new SickRageSeasonList(); + } + } + + public async Task AddSeries(int tvdbId, int seasonCount, int[] seasons, string quality, string apiKey, Uri baseUrl) + { var futureStatus = seasons.Length > 0 && !seasons.Any(x => x == seasonCount) ? SickRageStatus.Skipped : SickRageStatus.Wanted; var status = seasons.Length > 0 ? SickRageStatus.Skipped : SickRageStatus.Wanted; Log.Trace("Future Status: {0}", futureStatus); Log.Trace("Current Status: {0}", status); - var request = new RestRequest - { - Resource = "/api/{apiKey}/?cmd=show.addnew", - Method = Method.GET - }; + var request = new RestRequest { Resource = "/api/{apiKey}/?cmd=show.addnew", Method = Method.GET }; request.AddUrlSegment("apiKey", apiKey); request.AddQueryParameter("tvdbid", tvdbId.ToString()); request.AddQueryParameter("status", status); @@ -83,10 +95,11 @@ namespace PlexRequests.Api request.AddQueryParameter("initial", quality); } - var policy = RetryHandler.RetryAndWaitPolicy (null,(exception, timespan) => Log.Error (exception, "Exception when calling AddSeries for SR, Retrying {0}", timespan)); + var policy = RetryHandler.RetryAndWaitPolicy( + null, + (exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for SR, Retrying {0}", timespan)); - - var obj = policy.Execute( () => Api.Execute(request, baseUrl)); + var obj = policy.Execute(() => Api.Execute(request, baseUrl)); Log.Trace("obj Result:"); Log.Trace(obj.DumpJson()); @@ -134,7 +147,7 @@ namespace PlexRequests.Api { Log.Trace("Adding season {0}", s); - var result = await AddSeason(tvdbId, s, apiKey, baseUrl); + var result = await AddSeason(tvdbId, s, apiKey, baseUrl); Log.Trace("SickRage adding season results: "); Log.Trace(result.DumpJson()); } @@ -153,105 +166,61 @@ namespace PlexRequests.Api public SickRagePing Ping(string apiKey, Uri baseUrl) { - var request = new RestRequest - { - Resource = "/api/{apiKey}/?cmd=sb.ping", - Method = Method.GET - }; - - - var policy = RetryHandler.RetryAndWaitPolicy (null,(exception, timespan) => Log.Error (exception, "Exception when calling Ping for SR, Retrying {0}", timespan)); - + var request = new RestRequest { Resource = "/api/{apiKey}/?cmd=sb.ping", Method = Method.GET }; + var policy = RetryHandler.RetryAndWaitPolicy( + null, + (exception, timespan) => Log.Error(exception, "Exception when calling Ping for SR, Retrying {0}", timespan)); request.AddUrlSegment("apiKey", apiKey); - var obj = policy.Execute( () => Api.ExecuteJson(request, baseUrl)); + var obj = policy.Execute(() => Api.ExecuteJson(request, baseUrl)); return obj; } - public SickRageSeasonList VerifyShowHasLoaded(int tvdbId, string apiKey, Uri baseUrl) - { - Log.Trace("Entered `VerifyShowHasLoaded({0} <- id)`", tvdbId); - var request = new RestRequest - { - Resource = "/api/{apiKey}/?cmd=show.seasonlist", - Method = Method.GET - }; - request.AddUrlSegment("apiKey", apiKey); - request.AddQueryParameter("tvdbid", tvdbId.ToString()); - - try - { - var policy = RetryHandler.RetryAndWaitPolicy (null,(exception, timespan) => - Log.Error (exception, "Exception when calling VerifyShowHasLoaded for SR, Retrying {0}", timespan)); - - - var obj = policy.Execute( () => Api.ExecuteJson(request, baseUrl)); - return obj; - } - catch (Exception e) - { - Log.Error(e); - return new SickRageSeasonList(); - } - } - public async Task AddSeason(int tvdbId, int season, string apiKey, Uri baseUrl) { - var request = new RestRequest - { - Resource = "/api/{apiKey}/?cmd=episode.setstatus", - Method = Method.GET - }; + var request = new RestRequest { Resource = "/api/{apiKey}/?cmd=episode.setstatus", Method = Method.GET }; request.AddUrlSegment("apiKey", apiKey); request.AddQueryParameter("tvdbid", tvdbId.ToString()); request.AddQueryParameter("season", season.ToString()); request.AddQueryParameter("status", SickRageStatus.Wanted); await Task.Run(() => Thread.Sleep(2000)); - return await Task.Run(() => - { - - var policy = RetryHandler.RetryAndWaitPolicy (null,(exception, timespan) => - Log.Error (exception, "Exception when calling AddSeason for SR, Retrying {0}", timespan)); + return await Task.Run( + () => + { + var policy = RetryHandler.RetryAndWaitPolicy( + null, + (exception, timespan) => Log.Error(exception, "Exception when calling AddSeason for SR, Retrying {0}", timespan)); - var result = policy.Execute(() => Api.Execute(request, baseUrl)); + var result = policy.Execute(() => Api.Execute(request, baseUrl)); - return result; - }).ConfigureAwait(false); + return result; + }).ConfigureAwait(false); } - public async Task GetShows(string apiKey, Uri baseUrl) + public async Task GetShows(string apiKey, Uri baseUrl) { - var request = new RestRequest - { - Resource = "/api/{apiKey}/?cmd=shows", - Method = Method.GET - }; + var request = new RestRequest { Resource = "/api/{apiKey}/?cmd=shows", Method = Method.GET }; request.AddUrlSegment("apiKey", apiKey); - + return await Task.Run( () => { try { - var policy = RetryHandler.RetryAndWaitPolicy (new TimeSpan[] { - TimeSpan.FromSeconds (5), - TimeSpan.FromSeconds(10), - TimeSpan.FromSeconds(30) - }, (exception, timespan) => - Log.Error (exception, "Exception when calling GetShows for SR, Retrying {0}", timespan)); - - return policy.Execute(() => Api.Execute(request, baseUrl)); + var policy = RetryHandler.RetryAndWaitPolicy( + new[] { TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30) }, + (exception, timespan) => Log.Error(exception, "Exception when calling GetShows for SR, Retrying {0}", timespan)); + return policy.Execute(() => Api.Execute(request, baseUrl)); } catch (ApiRequestException) { Log.Error("There has been a API exception when Getting the Sickrage shows"); return null; } - }).ConfigureAwait(false); } } diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index d7983017c..531f2521e 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -420,6 +420,10 @@ {92433867-2B7B-477B-A566-96C382427525} PlexRequests.Store + + {ebe6fc1c-7b4b-47e9-af54-0ee0604a2be5} + PlexRequests.Updater + diff --git a/PlexRequests.UI/Program.cs b/PlexRequests.UI/Program.cs index 1c1fe1415..a446bda23 100644 --- a/PlexRequests.UI/Program.cs +++ b/PlexRequests.UI/Program.cs @@ -61,6 +61,9 @@ namespace PlexRequests.UI x => x.Port, e => -1); + var updated = result.MapResult(x => x.Updated, e => false); + //TODO + PrintToConsole("Starting Up! Please wait, this can usually take a few seconds.", ConsoleColor.Yellow); Log.Trace("Getting product version"); diff --git a/PlexRequests.UI/Start/StartupOptions.cs b/PlexRequests.UI/Start/StartupOptions.cs index a911a00b3..21b8eef9a 100644 --- a/PlexRequests.UI/Start/StartupOptions.cs +++ b/PlexRequests.UI/Start/StartupOptions.cs @@ -24,7 +24,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion -using System.Text; using CommandLine; @@ -51,6 +50,14 @@ namespace PlexRequests.UI.Start public int Port { get; set; } + /// + /// Gets or sets a value indicating whether this is updated. + /// + /// + /// true if updated; otherwise, false. + /// + [Option('u', "updated", Required = false, HelpText = "This should only be used by the internal application")] + public bool Updated { get; set; } } } \ No newline at end of file diff --git a/PlexRequests.Updater/PlexRequests.Updater.csproj b/PlexRequests.Updater/PlexRequests.Updater.csproj index 433553dc8..86de4fd4a 100644 --- a/PlexRequests.Updater/PlexRequests.Updater.csproj +++ b/PlexRequests.Updater/PlexRequests.Updater.csproj @@ -31,6 +31,7 @@ + @@ -50,5 +51,6 @@ + \ No newline at end of file diff --git a/PlexRequests.Updater/Program.cs b/PlexRequests.Updater/Program.cs index 5703d1f84..98692c11d 100644 --- a/PlexRequests.Updater/Program.cs +++ b/PlexRequests.Updater/Program.cs @@ -7,7 +7,8 @@ namespace PlexRequests.Updater public static void Main (string[] args) { Console.WriteLine ("Starting PlexRequests .Net updater"); - + var s = new Updater(); + s.Start(args[0]); } } } diff --git a/PlexRequests.Updater/Updater.cs b/PlexRequests.Updater/Updater.cs index d1b72b59c..00b62380c 100644 --- a/PlexRequests.Updater/Updater.cs +++ b/PlexRequests.Updater/Updater.cs @@ -1,42 +1,201 @@ -using System; -using PlexRequests.Core; -using System.Net; +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: Updater.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +using System; +using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Net; +using System.Windows.Forms; namespace PlexRequests.Updater { - public class Updater - { - public void Start(){ - var c = new StatusChecker (); - - try { - - var release = c.GetStatus (); - if(!release.UpdateAvailable) - { - Console.WriteLine ("No Update availble, shutting down"); - } - - using(var client = new WebClient()) - using(var ms = new MemoryStream(client.DownloadData(release.DownloadUri), false)) - using(var gz = new GZipStream(ms, CompressionLevel.Optimal)) - { - // TODO decompress stream - } - - - } catch (Exception ex) { - - Console.WriteLine (ex.Message); - Console.WriteLine ("Oops... Looks like we cannot update!"); - Console.ReadLine (); - } - } - - - - } -} + public class Updater + { + private string BackupPath { get; set; } + private bool Error { get; set; } + private string TempPath { get; set; } + + public void RestoreBackup() + { + Console.WriteLine("Update failed, restoring backup"); + using (var archive = ZipFile.OpenRead(BackupPath)) + { + foreach (var entry in archive.Entries) + { + var fullPath = Path.Combine(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath)), entry.FullName); + + if (string.IsNullOrEmpty(entry.Name)) + { + Directory.CreateDirectory(fullPath); + } + else + { + if (entry.Name.Contains("PlexRequests.Updater")) + { + entry.ExtractToFile(fullPath + "_Updated", true); + continue; + } + + entry.ExtractToFile(fullPath, true); + Console.WriteLine("Update failed, restoring backup"); + } + } + } + } + + public void Start(string downloadPath) + { + try + { + BackupCurrentVersion(); + var dir = CreateTempPath(); + TempPath = Path.Combine(dir.FullName, "PlexRequestsUpdate.zip"); + + CheckAndDelete(TempPath); + Console.WriteLine("Downloading new version"); + using (var client = new WebClient()) + { + client.DownloadFile(downloadPath, TempPath); + } + Console.WriteLine("Downloaded!"); + + + // Replace files + using (var archive = ZipFile.OpenRead(TempPath)) + { + foreach (var entry in archive.Entries) + { + var fullname = string.Empty; + if (entry.FullName.Contains("Release/")) // Don't extract the release folder, we are already in there + { + fullname = entry.FullName.Replace("Release/", string.Empty); + } + + var fullPath = Path.Combine(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath)), fullname); + + if (string.IsNullOrEmpty(entry.Name)) + { + Directory.CreateDirectory(fullPath); + } + else + { + if (entry.Name.Contains("PlexRequests.Updater")) + { + entry.ExtractToFile(fullPath + "_Updated", true); + continue; + } + + entry.ExtractToFile(fullPath, true); + Console.WriteLine("Restored {0}", entry.FullName); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Console.WriteLine("Oops... Looks like we cannot update!"); + Console.ReadLine(); + Error = true; + } + finally + { + File.Delete(TempPath); + if (Error) + { + RestoreBackup(); + } + + FinishUpdate(); + } + } + + private void BackupCurrentVersion() + { + Console.WriteLine("Backing up the current version"); + try + { + var dir = Directory.CreateDirectory("BackupSystem"); + var applicationPath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath)); + + var allfiles = Directory.GetFiles(applicationPath, "*.*", SearchOption.AllDirectories); + BackupPath = Path.Combine(dir.FullName, "PlexRequestsBackup.zip"); + + CheckAndDelete(BackupPath); + using (var fileStream = new FileStream(BackupPath, FileMode.CreateNew)) + using (var archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true)) + { + foreach (var file in allfiles) + { + if (file.Contains("BackupSystem")) + continue; + var info = Path.GetFileName(file); + archive.CreateEntryFromFile(file, info); + } + } + Console.WriteLine("All backed up!"); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine(); + Environment.Exit(1); + } + } + + private void CheckAndDelete(string filePath) + { + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + } + + private DirectoryInfo CreateTempPath() + { + try + { + return Directory.CreateDirectory("UpdateTemp"); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine(); + Environment.Exit(1); + return null; + } + } + private void FinishUpdate() + { + var startInfo = new ProcessStartInfo("PlexRequests.exe") { Arguments = Error ? "-u false" : "-u true" }; + Process.Start(startInfo); + + Environment.Exit(0); + } + } +} \ No newline at end of file diff --git a/PlexRequests.Updater/packages.config b/PlexRequests.Updater/packages.config new file mode 100644 index 000000000..4d4f826f4 --- /dev/null +++ b/PlexRequests.Updater/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file