mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-10-28 08:29:11 -04:00
Cull dead code. Simplify
This commit is contained in:
1 parent
19a867488b
commit
09be09bd1b
14 files changed
+66
-135
No files matched your search
@@ -82,25 +82,12 @@ public static class LibraryCommands
|
||||
|
||||
return inactive;
|
||||
}
|
||||
catch (AudibleApi.Authentication.LoginFailedException lfEx)
|
||||
{
|
||||
lfEx.SaveFiles(Configuration.Instance.LibationFiles.Location);
|
||||
|
||||
// nuget Serilog.Exceptions would automatically log custom properties
|
||||
// However, it comes with a scary warning when used with EntityFrameworkCore which I'm not yet ready to implement:
|
||||
// https://github.com/RehanSaeed/Serilog.Exceptions
|
||||
// work-around: use 3rd param. don't just put exception object in 3rd param -- info overload: stack trace, etc
|
||||
Log.Logger.Error(lfEx, "Error scanning library. Login failed. {@DebugInfo}", new
|
||||
{
|
||||
lfEx.RequestUrl,
|
||||
ResponseStatusCodeNumber = (int)lfEx.ResponseStatusCode,
|
||||
ResponseStatusCodeDesc = lfEx.ResponseStatusCode,
|
||||
lfEx.ResponseInputFields,
|
||||
lfEx.ResponseBodyFilePaths
|
||||
});
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception lfEx) when (AuthenticationExceptionHelper.IsAuthenticationFailure(lfEx))
|
||||
{
|
||||
Log.Logger.Error(lfEx, "Error scanning library. Authentication failed.");
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error(ex, "Error scanning library");
|
||||
throw;
|
||||
@@ -188,25 +175,12 @@ public static class LibraryCommands
|
||||
|
||||
return (totalCount, newCount);
|
||||
}
|
||||
catch (AudibleApi.Authentication.LoginFailedException lfEx)
|
||||
{
|
||||
lfEx.SaveFiles(Configuration.Instance.LibationFiles.Location);
|
||||
|
||||
// nuget Serilog.Exceptions would automatically log custom properties
|
||||
// However, it comes with a scary warning when used with EntityFrameworkCore which I'm not yet ready to implement:
|
||||
// https://github.com/RehanSaeed/Serilog.Exceptions
|
||||
// work-around: use 3rd param. don't just put exception object in 3rd param -- info overload: stack trace, etc
|
||||
Log.Logger.Error(lfEx, "Error importing library. Login failed. {@DebugInfo}", new
|
||||
{
|
||||
lfEx.RequestUrl,
|
||||
ResponseStatusCodeNumber = (int)lfEx.ResponseStatusCode,
|
||||
ResponseStatusCodeDesc = lfEx.ResponseStatusCode,
|
||||
lfEx.ResponseInputFields,
|
||||
lfEx.ResponseBodyFilePaths
|
||||
});
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception lfEx) when (AuthenticationExceptionHelper.IsAuthenticationFailure(lfEx))
|
||||
{
|
||||
Log.Logger.Error(lfEx, "Error scanning library. Authentication failed.");
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error(ex, "Error importing library");
|
||||
throw;
|
||||
|
||||
@@ -5,13 +5,8 @@ using LibationFileManager;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AudibleUtilities;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using AudibleApi.Authentication;
|
||||
|
||||
namespace AudibleUtilities;
|
||||
|
||||
public static class AuthenticationExceptionHelper
|
||||
@@ -14,7 +12,7 @@ public static class AuthenticationExceptionHelper
|
||||
|
||||
for (var current = ex; current is not null; current = current.InnerException)
|
||||
{
|
||||
if (current is AuthenticationRequiredException or LoginFailedException)
|
||||
if (current is AuthenticationRequiredException)
|
||||
return true;
|
||||
|
||||
if (current is InvalidOperationException { Message: var message }
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using HtmlAgilityPack;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AudibleUtilities;
|
||||
@@ -11,35 +10,39 @@ namespace AudibleUtilities;
|
||||
/// </summary>
|
||||
public static partial class HtmlText
|
||||
{
|
||||
/// <param name="paragraphSeparator">Joins the block-level runs. A single newline matches what
|
||||
/// Audible itself embeds in the description tags of its .aaxc files.</param>
|
||||
public static string ToPlainText(string? html, string paragraphSeparator = "\n")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(html))
|
||||
return "";
|
||||
/// <param name="paragraphSeparator">Joins the block-level runs. A single newline matches what
|
||||
/// Audible itself embeds in the description tags of its .aaxc files.</param>
|
||||
public static string ToPlainText(string? html, string paragraphSeparator = "\n")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(html))
|
||||
return "";
|
||||
|
||||
// Not every summary is marked up. Running the unmarked ones through the parser risks a stray
|
||||
// '<' swallowing the rest of the sentence, and buys nothing.
|
||||
if (!html.Contains('<'))
|
||||
return (HtmlEntity.DeEntitize(html) ?? html).Trim();
|
||||
// Not every summary is marked up. Running the unmarked ones through the parser risks a stray
|
||||
// '<' swallowing the rest of the sentence, and buys nothing.
|
||||
if (!html.Contains('<'))
|
||||
return (WebUtility.HtmlDecode(html) ?? html).Trim();
|
||||
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(BlockBoundary().Replace(html, "\n"));
|
||||
// Replace block-level boundaries with newlines, then strip all remaining tags.
|
||||
var stripped = StripTags().Replace(BlockBoundary().Replace(html, "\n"), "");
|
||||
|
||||
var text = HtmlEntity.DeEntitize(doc.DocumentNode.InnerText) ?? doc.DocumentNode.InnerText;
|
||||
var text = WebUtility.HtmlDecode(stripped) ?? stripped;
|
||||
|
||||
var paragraphs = text
|
||||
.Replace("\r\n", "\n")
|
||||
.Replace('\r', '\n')
|
||||
.Split('\n')
|
||||
.Select(line => line.Trim())
|
||||
.Where(line => line.Length > 0);
|
||||
var paragraphs = text
|
||||
.Replace("\r\n", "\n")
|
||||
.Replace('\r', '\n')
|
||||
.Split('\n')
|
||||
.Select(line => line.Trim())
|
||||
.Where(line => line.Length > 0);
|
||||
|
||||
return string.Join(paragraphSeparator, paragraphs);
|
||||
}
|
||||
return string.Join(paragraphSeparator, paragraphs);
|
||||
}
|
||||
|
||||
/// <summary>Every tag that ends a run of text. A line break counts as a paragraph break because
|
||||
/// Audible's summaries mark up paragraphs and nothing finer.</summary>
|
||||
[GeneratedRegex(@"<\s*br\s*/?\s*>|<\s*/\s*(?:p|div|li|tr|blockquote|h[1-6])\s*>", RegexOptions.IgnoreCase)]
|
||||
private static partial Regex BlockBoundary();
|
||||
/// <summary>Every tag that ends a run of text. A line break counts as a paragraph break because
|
||||
/// Audible's summaries mark up paragraphs and nothing finer.</summary>
|
||||
[GeneratedRegex(@"<\s*br\s*/?\s*>|<\s*/\s*(?:p|div|li|tr|blockquote|h[1-6])\s*>", RegexOptions.IgnoreCase)]
|
||||
private static partial Regex BlockBoundary();
|
||||
|
||||
/// <summary>Matches any HTML/XML tag.</summary>
|
||||
[GeneratedRegex(@"<[^>]+>")]
|
||||
private static partial Regex StripTags();
|
||||
}
|
||||
@@ -79,6 +79,9 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="10.0.400" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="SpicNSpan" AfterTargets="Clean">
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace HangoverAvalonia.ViewModels;
|
||||
|
||||
public partial class MainVM : ViewModelBase
|
||||
{
|
||||
public Func<string, Task<bool>>? ConfirmDbMutationAsync { get; set; }
|
||||
public Func<string, Task<bool>> ConfirmDbMutationAsync { get; set; }
|
||||
|
||||
public MainVM()
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ public class TrashBinViewModel : ViewModelBase, IDisposable
|
||||
item.IsChecked = false;
|
||||
}
|
||||
|
||||
public Func<string, Task<bool>>? ConfirmDbMutationAsync { get; set; }
|
||||
public Func<string, Task<bool>> ConfirmDbMutationAsync { get; set; }
|
||||
|
||||
public async Task RestoreCheckedAsync()
|
||||
{
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
using AudibleApi;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationAvalonia.Dialogs.Login;
|
||||
|
||||
public class AvaloniaLoginCallback : ILoginCallback
|
||||
{
|
||||
public string DeviceName { get; } = "Libation";
|
||||
|
||||
public Task<string> Get2faCodeAsync(string prompt) => throw new System.NotSupportedException();
|
||||
public Task<(string password, string guess)> GetCaptchaAnswerAsync(string password, byte[] captchaImage)
|
||||
=> throw new System.NotSupportedException();
|
||||
public Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig)
|
||||
=> throw new System.NotSupportedException();
|
||||
public Task<(string email, string password)> GetLoginAsync()
|
||||
=> throw new System.NotSupportedException();
|
||||
public Task ShowApprovalNeededAsync() => throw new System.NotSupportedException();
|
||||
}
|
||||
@@ -14,19 +14,17 @@ namespace LibationAvalonia.Dialogs.Login;
|
||||
|
||||
public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
{
|
||||
public ILoginCallback LoginCallback { get; } = new AvaloniaLoginCallback();
|
||||
|
||||
private readonly Account _account;
|
||||
|
||||
public AvaloniaLoginChoiceEager(Account account)
|
||||
{
|
||||
_account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account));
|
||||
_account = ArgumentValidator.EnsureNotNull(account, nameof(account));
|
||||
}
|
||||
|
||||
public async Task<ChoiceOut?> StartAsync(ChoiceIn choiceIn)
|
||||
public async Task<string?> StartAsync(ChoiceIn choiceIn)
|
||||
=> await Dispatcher.UIThread.InvokeAsync(() => StartAsyncInternal(choiceIn));
|
||||
|
||||
private async Task<ChoiceOut?> StartAsyncInternal(ChoiceIn choiceIn)
|
||||
private async Task<string?> StartAsyncInternal(ChoiceIn choiceIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -35,7 +33,7 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
{
|
||||
try
|
||||
{
|
||||
if (await BrowserLoginAsync(choiceIn) is ChoiceOut external)
|
||||
if (await BrowserLoginAsync(choiceIn) is string external)
|
||||
return external;
|
||||
}
|
||||
catch (Exception ex) when (WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex))
|
||||
@@ -65,17 +63,17 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
|
||||
var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl);
|
||||
return await externalDialog.ShowDialogAsync() is DialogResult.OK
|
||||
? ChoiceOut.External(externalDialog.ResponseUrl)
|
||||
? externalDialog.ResponseUrl
|
||||
: null;
|
||||
}
|
||||
|
||||
private async Task<ChoiceOut?> BrowserLoginAsync(ChoiceIn shoiceIn)
|
||||
private async Task<string?> BrowserLoginAsync(ChoiceIn shoiceIn)
|
||||
{
|
||||
// Time-of-use: setting can change before Show (e.g. settings saved) — never open NativeWebView when disabled.
|
||||
if (!Configuration.Instance.UseWebView)
|
||||
return null;
|
||||
|
||||
TaskCompletionSource<ChoiceOut?> tcs = new();
|
||||
TaskCompletionSource<string?> tcs = new();
|
||||
|
||||
NativeWebDialog dialog = new()
|
||||
{
|
||||
@@ -89,7 +87,7 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
{
|
||||
if (e.Request?.AbsolutePath.StartsWith("/ap/maplanding") is true)
|
||||
{
|
||||
tcs.TrySetResult(ChoiceOut.External(e.Request.ToString()));
|
||||
tcs.TrySetResult(e.Request.ToString());
|
||||
dialog.Close();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -103,8 +103,7 @@ internal class LoginExternalOptions : OptionsBase
|
||||
?? AudibleApi.Locale.Empty;
|
||||
}
|
||||
|
||||
internal static bool IsEmptyLocale(AudibleApi.Locale locale)
|
||||
=> string.IsNullOrEmpty(locale.CountryCode);
|
||||
internal static bool IsEmptyLocale(Locale locale) => string.IsNullOrEmpty(locale.CountryCode);
|
||||
|
||||
private sealed class CliLoginExternal : ILoginExternal
|
||||
{
|
||||
@@ -112,8 +111,6 @@ internal class LoginExternalOptions : OptionsBase
|
||||
|
||||
public CliLoginExternal(string? presetResponseUrl) => _presetResponseUrl = presetResponseUrl;
|
||||
|
||||
public string DeviceName => "Libation";
|
||||
|
||||
public string GetResponseUrl(string loginUrl, CookieCollection signInCookies)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_presetResponseUrl))
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
using AudibleApi;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationWinForms.Login;
|
||||
|
||||
public class WinformLoginCallback : ILoginCallback
|
||||
{
|
||||
public string DeviceName { get; } = "Libation";
|
||||
|
||||
public Task<string> Get2faCodeAsync(string prompt) => throw new System.NotSupportedException();
|
||||
public Task<(string password, string guess)> GetCaptchaAnswerAsync(string password, byte[] captchaImage)
|
||||
=> throw new System.NotSupportedException();
|
||||
public Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig)
|
||||
=> throw new System.NotSupportedException();
|
||||
public Task<(string email, string password)> GetLoginAsync()
|
||||
=> throw new System.NotSupportedException();
|
||||
public Task ShowApprovalNeededAsync() => throw new System.NotSupportedException();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using AudibleApi;
|
||||
using AudibleUtilities;
|
||||
using Dinah.Core;
|
||||
using LibationFileManager;
|
||||
using LibationUiBase;
|
||||
using LibationWinForms.Dialogs.Login;
|
||||
@@ -11,20 +12,18 @@ namespace LibationWinForms.Login;
|
||||
|
||||
public class WinformLoginChoiceEager : ILoginChoiceEager
|
||||
{
|
||||
public ILoginCallback LoginCallback { get; } = new WinformLoginCallback();
|
||||
|
||||
private Account _account { get; }
|
||||
private Control Owner { get; }
|
||||
public WinformLoginChoiceEager(Account account, Control owner)
|
||||
{
|
||||
_account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account));
|
||||
Owner = Dinah.Core.ArgumentValidator.EnsureNotNull(owner, nameof(owner));
|
||||
_account = ArgumentValidator.EnsureNotNull(account, nameof(account));
|
||||
Owner = ArgumentValidator.EnsureNotNull(owner, nameof(owner));
|
||||
}
|
||||
|
||||
public Task<ChoiceOut?> StartAsync(ChoiceIn choiceIn)
|
||||
public Task<string?> StartAsync(ChoiceIn choiceIn)
|
||||
=> Owner.Invoke(() => StartAsyncInternal(choiceIn));
|
||||
|
||||
private Task<ChoiceOut?> StartAsyncInternal(ChoiceIn choiceIn)
|
||||
private Task<string?> StartAsyncInternal(ChoiceIn choiceIn)
|
||||
{
|
||||
if (Configuration.Instance.UseWebView && Environment.OSVersion.Version.Major >= 10)
|
||||
{
|
||||
@@ -35,7 +34,7 @@ public class WinformLoginChoiceEager : ILoginChoiceEager
|
||||
{
|
||||
using var weblogin = new WebLoginDialog(_account.AccountId, choiceIn);
|
||||
if (ShowDialog(weblogin))
|
||||
return Task.FromResult(ChoiceOut.External(weblogin.ResponseUrl));
|
||||
return Task.FromResult(weblogin.ResponseUrl);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -49,7 +48,7 @@ public class WinformLoginChoiceEager : ILoginChoiceEager
|
||||
using var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl);
|
||||
return Task.FromResult(
|
||||
ShowDialog(externalDialog)
|
||||
? ChoiceOut.External(externalDialog.ResponseUrl)
|
||||
? externalDialog.ResponseUrl
|
||||
: null);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using AudibleApi;
|
||||
using AudibleApi.Authorization;
|
||||
using AudibleApi.Cryptography;
|
||||
using AudibleUtilities;
|
||||
using Dinah.Core.Security;
|
||||
using LibationFileManager;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
@@ -59,6 +59,7 @@ public class TokenStorageSettingsUiTests
|
||||
{
|
||||
StringAssert.Contains(TokenStorageSettingsUi.ExportConfirmBody, "password");
|
||||
StringAssert.Contains(TokenStorageSettingsUi.ExportButtonToolTip, "Docker");
|
||||
Assert.AreEqual("Export encryption key...", TokenStorageSettingsUi.ExportButtonText);
|
||||
var temp = TokenStorageSettingsUi.ExportButtonText;
|
||||
Assert.AreEqual("Export encryption key...", temp);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user