From 94469cae3d9a70396eb4492cad1eb48ec5e83877 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 15 Dec 2022 16:22:25 -0700 Subject: [PATCH] Add better error messages for license denial #352 --- Source/LibationAvalonia/LogMe.cs | 15 ++-- .../ViewModels/ProcessBookViewModel.cs | 25 +++++- .../ViewModels/ProcessQueueViewModel.cs | 16 +++- .../ProcessQueue/ProcessBook.cs | 23 +++++- .../ProcessQueue/ProcessBookControl.cs | 76 +++++-------------- .../ProcessQueue/ProcessQueueControl.cs | 14 ++++ 6 files changed, 98 insertions(+), 71 deletions(-) diff --git a/Source/LibationAvalonia/LogMe.cs b/Source/LibationAvalonia/LogMe.cs index 19d1304c..07432a19 100644 --- a/Source/LibationAvalonia/LogMe.cs +++ b/Source/LibationAvalonia/LogMe.cs @@ -1,4 +1,5 @@ -using System; +using Avalonia.Threading; +using System; using System.Threading.Tasks; namespace LibationAvalonia @@ -40,19 +41,15 @@ namespace LibationAvalonia private static async void LogMe_LogError(object sender, (Exception, string) tuple) { - await Task.Run(() => LogForm?.WriteLine(tuple.Item2 ?? "Automated backup: error")); - await Task.Run(() => LogForm?.WriteLine("ERROR: " + tuple.Item1.Message)); + await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine(tuple.Item2 ?? "Automated backup: error")); + await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine("ERROR: " + tuple.Item1.Message)); } private static async void LogMe_LogErrorString(object sender, string text) - { - await Task.Run(() => LogForm?.WriteLine(text)); - } + => await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine(text)); private static async void LogMe_LogInfo(object sender, string text) - { - await Task.Run(() => LogForm?.WriteLine(text)); - } + => await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine(text)); public void Info(string text) => LogInfo?.Invoke(this, text); public void Error(string text) => LogErrorString?.Invoke(this, text); diff --git a/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs b/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs index c4008b58..13f23bc8 100644 --- a/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs +++ b/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ApplicationServices; +using AudibleApi; +using AudibleApi.Common; using Avalonia.Media; using Avalonia.Media.Imaging; using DataLayer; @@ -22,7 +24,9 @@ namespace LibationAvalonia.ViewModels ValidationFail, FailedRetry, FailedSkip, - FailedAbort + FailedAbort, + LicenseDenied, + LicenseDeniedPossibleOutage } public enum ProcessBookStatus @@ -80,6 +84,8 @@ namespace LibationAvalonia.ViewModels ProcessBookResult.FailedRetry => "Error, will retry later", ProcessBookResult.FailedSkip => "Error, Skippping", ProcessBookResult.FailedAbort => "Error, Abort", + ProcessBookResult.LicenseDenied => "License Denied", + ProcessBookResult.LicenseDeniedPossibleOutage => "Possible Service Interruption", _ => Status.ToString(), }; @@ -134,18 +140,31 @@ namespace LibationAvalonia.ViewModels return Result = ProcessBookResult.Success; else if (statusHandler.Errors.Contains("Cancelled")) { - Logger.Info($"{procName}: Process was cancelled {LibraryBook.Book}"); + Logger.Info($"{procName}: Process was cancelled - {LibraryBook.Book}"); return Result = ProcessBookResult.Cancelled; } else if (statusHandler.Errors.Contains("Validation failed")) { - Logger.Info($"{procName}: Validation failed {LibraryBook.Book}"); + Logger.Info($"{procName}: Validation failed - {LibraryBook.Book}"); return Result = ProcessBookResult.ValidationFail; } foreach (var errorMessage in statusHandler.Errors) Logger.Error($"{procName}: {errorMessage}"); } + catch (ContentLicenseDeniedException ldex) + { + if (ldex.AYCL?.RejectionReason is null or RejectionReason.GenericError) + { + Logger.Info($"{procName}: Content license was denied, but this error appears to be caused by a temporary interruption of service. - {LibraryBook.Book}"); + return Result = ProcessBookResult.LicenseDeniedPossibleOutage; + } + else + { + Logger.Info($"{procName}: Content license denied. Check your Audible account to see if you have access to this title. - {LibraryBook.Book}"); + return Result = ProcessBookResult.LicenseDenied; + } + } catch (Exception ex) { Logger.Error(ex, procName); diff --git a/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs b/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs index 93521f6d..45631b66 100644 --- a/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs +++ b/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs @@ -163,6 +163,8 @@ namespace LibationAvalonia.ViewModels using var counterTimer = new System.Threading.Timer(CounterTimer_Tick, null, 0, 500); + bool shownServiceOutageMessage = false; + while (Queue.MoveNext()) { var nextBook = Queue.Current; @@ -178,7 +180,19 @@ namespace LibationAvalonia.ViewModels else if (result == ProcessBookResult.FailedAbort) Queue.ClearQueue(); else if (result == ProcessBookResult.FailedSkip) - nextBook.LibraryBook.Book.UpdateBookStatus(DataLayer.LiberatedStatus.Error); + nextBook.LibraryBook.Book.UpdateBookStatus(LiberatedStatus.Error); + else if (result == ProcessBookResult.LicenseDeniedPossibleOutage && !shownServiceOutageMessage) + { + await MessageBox.Show(@$" +You were denied a content license for {nextBook.LibraryBook.Book.Title} + +This error appears to be caused by a temporary interruption of service that sometimes affects Libation's users. This type of error usually resolves itself in 1 to 2 days, and in the meantime you should still be able to access your books through Audible's website or app. +", + "Possible Interruption of Service", + MessageBoxButtons.OK, + MessageBoxIcon.Asterisk); + shownServiceOutageMessage = true; + } } Serilog.Log.Logger.Information("Completed processing queue"); diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBook.cs b/Source/LibationWinForms/ProcessQueue/ProcessBook.cs index fffd0d78..0ff85a9e 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessBook.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessBook.cs @@ -7,6 +7,8 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows.Forms; using ApplicationServices; +using AudibleApi.Common; +using AudibleApi; using DataLayer; using Dinah.Core; using Dinah.Core.ErrorHandling; @@ -24,7 +26,9 @@ namespace LibationWinForms.ProcessQueue ValidationFail, FailedRetry, FailedSkip, - FailedAbort + FailedAbort, + LicenseDenied, + LicenseDeniedPossibleOutage } public enum ProcessBookStatus @@ -108,18 +112,31 @@ namespace LibationWinForms.ProcessQueue return Result = ProcessBookResult.Success; else if (statusHandler.Errors.Contains("Cancelled")) { - Logger.Info($"{procName}: Process was cancelled {LibraryBook.Book}"); + Logger.Info($"{procName}: Process was cancelled - {LibraryBook.Book}"); return Result = ProcessBookResult.Cancelled; } else if (statusHandler.Errors.Contains("Validation failed")) { - Logger.Info($"{procName}: Validation failed {LibraryBook.Book}"); + Logger.Info($"{procName}: Validation failed - {LibraryBook.Book}"); return Result = ProcessBookResult.ValidationFail; } foreach (var errorMessage in statusHandler.Errors) Logger.Error($"{procName}: {errorMessage}"); } + catch (ContentLicenseDeniedException ldex) + { + if (ldex.AYCL?.RejectionReason is null or RejectionReason.GenericError) + { + Logger.Info($"{procName}: Content license was denied, but this error appears to be caused by a temporary interruption of service. - {LibraryBook.Book}"); + return Result = ProcessBookResult.LicenseDeniedPossibleOutage; + } + else + { + Logger.Info($"{procName}: Content license denied. Check your Audible account to see if you have access to this title. - {LibraryBook.Book}"); + return Result = ProcessBookResult.LicenseDenied; + } + } catch (Exception ex) { Logger.Error(ex, procName); diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs index 62062468..3254f5d0 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs @@ -60,68 +60,34 @@ namespace LibationWinForms.ProcessQueue public void SetResult(ProcessBookResult result) { - string statusText = default; - switch (result) + (string statusText, ProcessBookStatus status) = result switch { - case ProcessBookResult.Success: - statusText = "Finished"; - Status = ProcessBookStatus.Completed; - break; - case ProcessBookResult.Cancelled: - statusText = "Cancelled"; - Status = ProcessBookStatus.Cancelled; - break; - case ProcessBookResult.FailedRetry: - statusText = "Error, will retry later"; - Status = ProcessBookStatus.Failed; - break; - case ProcessBookResult.FailedSkip: - statusText = "Error, Skippping"; - Status = ProcessBookStatus.Failed; - break; - case ProcessBookResult.FailedAbort: - statusText = "Error, Abort"; - Status = ProcessBookStatus.Failed; - break; - case ProcessBookResult.ValidationFail: - statusText = "Validion fail"; - Status = ProcessBookStatus.Failed; - break; - case ProcessBookResult.None: - statusText = "UNKNOWN"; - Status = ProcessBookStatus.Failed; - break; - } + ProcessBookResult.Success => ("Finished", ProcessBookStatus.Completed), + ProcessBookResult.Cancelled => ("Cancelled", ProcessBookStatus.Cancelled), + ProcessBookResult.FailedRetry => ("Error, will retry later", ProcessBookStatus.Failed), + ProcessBookResult.FailedSkip => ("Error, Skippping", ProcessBookStatus.Failed), + ProcessBookResult.FailedAbort => ("Error, Abort", ProcessBookStatus.Failed), + ProcessBookResult.ValidationFail => ("Validion fail", ProcessBookStatus.Failed), + ProcessBookResult.LicenseDenied => ("License Denied", ProcessBookStatus.Failed), + ProcessBookResult.LicenseDeniedPossibleOutage => ("Possible Service Interruption", ProcessBookStatus.Failed), + _ => ("UNKNOWN", ProcessBookStatus.Failed), + }; - SetStatus(Status, statusText); + SetStatus(status, statusText); } public void SetStatus(ProcessBookStatus status, string statusText = null) { - Color backColor = default; - switch (status) + Status = status; + + Color backColor = Status switch { - case ProcessBookStatus.Completed: - backColor = SuccessColor; - Status = ProcessBookStatus.Completed; - break; - case ProcessBookStatus.Cancelled: - backColor = CancelledColor; - Status = ProcessBookStatus.Cancelled; - break; - case ProcessBookStatus.Queued: - backColor = QueuedColor; - Status = ProcessBookStatus.Queued; - break; - case ProcessBookStatus.Working: - backColor = QueuedColor; - Status = ProcessBookStatus.Working; - break; - case ProcessBookStatus.Failed: - backColor = FailedColor; - Status = ProcessBookStatus.Failed; - break; - } + ProcessBookStatus.Completed => SuccessColor, + ProcessBookStatus.Cancelled => CancelledColor, + ProcessBookStatus.Queued => QueuedColor, + ProcessBookStatus.Working => QueuedColor, + _ => FailedColor + }; SuspendLayout(); diff --git a/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs b/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs index dfae3673..baf7a8ea 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs @@ -161,6 +161,8 @@ namespace LibationWinForms.ProcessQueue StartingTime = DateTime.Now; counterTimer.Start(); + bool shownServiceOutageMessage = false; + while (Queue.MoveNext()) { var nextBook = Queue.Current; @@ -177,6 +179,18 @@ namespace LibationWinForms.ProcessQueue Queue.ClearQueue(); else if (result == ProcessBookResult.FailedSkip) nextBook.LibraryBook.Book.UpdateBookStatus(DataLayer.LiberatedStatus.Error); + else if (result == ProcessBookResult.LicenseDeniedPossibleOutage && !shownServiceOutageMessage) + { + MessageBox.Show(@$" +You were denied a content license for {nextBook.LibraryBook.Book.Title} + +This error appears to be caused by a temporary interruption of service that sometimes affects Libation's users. This type of error usually resolves itself in 1 to 2 days, and in the meantime you should still be able to access your books through Audible's website or app. +", + "Possible Interruption of Service", + MessageBoxButtons.OK, + MessageBoxIcon.Asterisk); + shownServiceOutageMessage = true; + } } Serilog.Log.Logger.Information("Completed processing queue");