diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index 24e80a01..5f9f57a8 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -577,7 +577,7 @@ namespace ApplicationServices // must be here instead of in db layer due to AaxcExists public static LiberatedStatus Liberated_Status(Book book) - => book.Audio_Exists() ? book.UserDefinedItem.BookStatus + => book.AudioExists ? book.UserDefinedItem.BookStatus : AudibleFileStorage.AaxcExists(book.AudibleProductId) ? LiberatedStatus.PartialDownload : LiberatedStatus.NotLiberated; @@ -645,7 +645,7 @@ namespace ApplicationServices var pdfResults = libraryBooks .AsParallel() - .Where(lb => lb.Book.HasPdf()) + .Where(lb => lb.Book.HasPdf) .Select(lb => new { absent = lb.AbsentFromLastScan, status = Pdf_Status(lb.Book) }) .ToList(); diff --git a/Source/ApplicationServices/LibraryExporter.cs b/Source/ApplicationServices/LibraryExporter.cs index 7ec92f0b..50c0c317 100644 --- a/Source/ApplicationServices/LibraryExporter.cs +++ b/Source/ApplicationServices/LibraryExporter.cs @@ -150,12 +150,12 @@ namespace ApplicationServices Locale = a.Book.Locale, Title = a.Book.Title, Subtitle = a.Book.Subtitle, - AuthorNames = a.Book.AuthorNames(), - NarratorNames = a.Book.NarratorNames(), + AuthorNames = a.Book.AuthorNames, + NarratorNames = a.Book.NarratorNames, LengthInMinutes = a.Book.LengthInMinutes, Description = a.Book.Description, Publisher = a.Book.Publisher, - HasPdf = a.Book.HasPdf(), + HasPdf = a.Book.HasPdf, SeriesNames = a.Book.SeriesNames(), SeriesOrder = a.Book.SeriesLink.Any() ? a.Book.SeriesLink?.Select(sl => $"{sl.Order} : {sl.Series.Name}").Aggregate((a, b) => $"{a}, {b}") : "", CommunityRatingOverall = a.Book.Rating?.OverallRating.ZeroIsNull(), diff --git a/Source/DataLayer/EntityExtensions.cs b/Source/DataLayer/EntityExtensions.cs index 9bfe1aff..1c53ee83 100644 --- a/Source/DataLayer/EntityExtensions.cs +++ b/Source/DataLayer/EntityExtensions.cs @@ -13,69 +13,74 @@ namespace DataLayer .Where(a => a.Role == role) .OrderBy(a => a.Order); - public static string TitleSortable(this Book book) => Formatters.GetSortName(book.Title + book.Subtitle); - public static string AuthorNames(this Book book) => string.Join(", ", book.Authors.Select(a => a.Name)); - public static string NarratorNames(this Book book) => string.Join(", ", book.Narrators.Select(n => n.Name)); + extension(Book book) + { + public string SeriesSortable() => Formatters.GetSortName(book.SeriesNames(true)); + public string TitleSortable() => Formatters.GetSortName(book.Title + book.Subtitle); - /// True if IsLiberated or Error. False if NotLiberated - public static bool Audio_Exists(this Book book) => book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated; - /// True if exists and IsLiberated. Else false - public static bool PDF_Exists(this Book book) => book.UserDefinedItem.PdfStatus == LiberatedStatus.Liberated; + public string AuthorNames => string.Join(", ", book.Authors.Select(a => a.Name)); + public string NarratorNames => string.Join(", ", book.Narrators.Select(n => n.Name)); + /// True if IsLiberated or Error. False if NotLiberated + public bool AudioExists => book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated or LiberatedStatus.Error; + /// True if exists and IsLiberated. Else false + public bool PdfExists => book.UserDefinedItem.PdfStatus == LiberatedStatus.NotLiberated; + /// Whether the book has any supplements + public bool HasPdf => book.Supplements.Any(); - public static string SeriesSortable(this Book book) => Formatters.GetSortName(book.SeriesNames(true)); - public static bool HasPdf(this Book book) => book.Supplements.Any(); - public static string SeriesNames(this Book book, bool includeIndex = false) - { - if (book.SeriesLink is null) - return ""; + public string SeriesNames(bool includeIndex = false) + { + if (book.SeriesLink is null) + return ""; - // first: alphabetical by name - var withNames = book.SeriesLink - .Where(s => !string.IsNullOrWhiteSpace(s.Series.Name)) - .Select(getSeriesNameString) - .OrderBy(a => a) - .ToList(); - // then un-named are alpha by series id - var nullNames = book.SeriesLink - .Where(s => string.IsNullOrWhiteSpace(s.Series.Name)) - .Select(s => s.Series.AudibleSeriesId) - .OrderBy(a => a) - .ToList(); + // first: alphabetical by name + var withNames = book.SeriesLink + .Where(s => !string.IsNullOrWhiteSpace(s.Series.Name)) + .Select(getSeriesNameString) + .OrderBy(a => a) + .ToList(); + // then un-named are alpha by series id + var nullNames = book.SeriesLink + .Where(s => string.IsNullOrWhiteSpace(s.Series.Name)) + .Select(s => s.Series.AudibleSeriesId) + .OrderBy(a => a) + .ToList(); - var all = withNames.Union(nullNames).ToList(); - return string.Join(", ", all); + var all = withNames.Union(nullNames).ToList(); + return string.Join(", ", all); - string getSeriesNameString(SeriesBook sb) - => includeIndex && !string.IsNullOrWhiteSpace(sb.Order) && sb.Order != "-1" - ? $"{sb.Series.Name} (#{sb.Order})" - : sb.Series.Name; + string getSeriesNameString(SeriesBook sb) + => includeIndex && !string.IsNullOrWhiteSpace(sb.Order) && sb.Order != "-1" + ? $"{sb.Series.Name} (#{sb.Order})" + : sb.Series.Name; + } + + public string[] LowestCategoryNames() + => book.CategoriesLink?.Any() is not true ? Array.Empty() + : book + .CategoriesLink + .Select(cl => cl.CategoryLadder.Categories.LastOrDefault()?.Name) + .Where(c => c is not null) + .Distinct() + .ToArray(); + + public string[] AllCategoryNames() + => book.CategoriesLink?.Any() is not true ? Array.Empty() + : book + .CategoriesLink + .SelectMany(cl => cl.CategoryLadder.Categories) + .Select(c => c.Name) + .ToArray(); + + public string[] AllCategoryIds() + => book.CategoriesLink?.Any() is not true ? null + : book + .CategoriesLink + .SelectMany(cl => cl.CategoryLadder.Categories) + .Select(c => c.AudibleCategoryId) + .ToArray(); } - public static string[] LowestCategoryNames(this Book book) - => book.CategoriesLink?.Any() is not true ? Array.Empty() - : book - .CategoriesLink - .Select(cl => cl.CategoryLadder.Categories.LastOrDefault()?.Name) - .Where(c => c is not null) - .Distinct() - .ToArray(); - - public static string[] AllCategoryNames(this Book book) - => book.CategoriesLink?.Any() is not true ? Array.Empty() - : book - .CategoriesLink - .SelectMany(cl => cl.CategoryLadder.Categories) - .Select(c => c.Name) - .ToArray(); - - public static string[] AllCategoryIds(this Book book) - => book.CategoriesLink?.Any() is not true ? null - : book - .CategoriesLink - .SelectMany(cl => cl.CategoryLadder.Categories) - .Select(c => c.AudibleCategoryId) - .ToArray(); public static string AggregateTitles(this IEnumerable libraryBooks, int max = 5) { @@ -93,7 +98,7 @@ namespace DataLayer return titlesAgg; } - public static float FirstScore(this Rating rating) + public static float FirstScore(this Rating rating) => rating.OverallRating > 0 ? rating.OverallRating : rating.PerformanceRating > 0 ? rating.PerformanceRating : rating.StoryRating; diff --git a/Source/FileLiberator/DownloadDecryptBook.cs b/Source/FileLiberator/DownloadDecryptBook.cs index 97ba1e16..48ab08c8 100644 --- a/Source/FileLiberator/DownloadDecryptBook.cs +++ b/Source/FileLiberator/DownloadDecryptBook.cs @@ -28,7 +28,7 @@ namespace FileLiberator /// public DownloadOptions.LicenseInfo? LicenseInfo { get; set; } - public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists(); + public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.AudioExists; public override async Task CancelAsync() { if (abDownloader is not null) await abDownloader.CancelAsync(); @@ -43,7 +43,7 @@ namespace FileLiberator try { - if (libraryBook.Book.Audio_Exists()) + if (libraryBook.Book.AudioExists) return new StatusHandler { "Cannot find decrypt. Final audio file already exists" }; DownloadValidation(libraryBook); diff --git a/Source/FileLiberator/DownloadPdf.cs b/Source/FileLiberator/DownloadPdf.cs index 52646fcc..4e5cb20a 100644 --- a/Source/FileLiberator/DownloadPdf.cs +++ b/Source/FileLiberator/DownloadPdf.cs @@ -18,7 +18,7 @@ namespace FileLiberator public override string Name => "Download Pdf"; public override bool Validate(LibraryBook libraryBook) => !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook)) - && !libraryBook.Book.PDF_Exists(); + && !libraryBook.Book.PdfExists; public override async Task ProcessAsync(LibraryBook libraryBook) { diff --git a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs index 6ddf944f..ac89cfed 100644 --- a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs @@ -115,16 +115,16 @@ namespace LibationAvalonia.Dialogs var title = string.IsNullOrEmpty(Book.Subtitle) ? Book.Title : $"{Book.Title}\r\n {Book.Subtitle}"; //init book details - DetailsText = @$" -Title: {title} -Author(s): {Book.AuthorNames()} -Narrator(s): {Book.NarratorNames()} -Length: {(Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min")} -Category: {string.Join(", ", Book.LowestCategoryNames())} -Purchase Date: {libraryBook.DateAdded:d} -Language: {Book.Language} -Audible ID: {Book.AudibleProductId} -".Trim(); + DetailsText = $""" + Title: {title} + Author(s): {Book.AuthorNames} + Narrator(s): {Book.NarratorNames} + Length: {(Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min")} + Category: {string.Join(", ", Book.LowestCategoryNames())} + Purchase Date: {libraryBook.DateAdded:d} + Language: {Book.Language} + Audible ID: {Book.AudibleProductId} + """; var seriesNames = libraryBook.Book.SeriesNames(); if (!string.IsNullOrWhiteSpace(seriesNames)) diff --git a/Source/LibationAvalonia/ViewModels/MainVM.Import.cs b/Source/LibationAvalonia/ViewModels/MainVM.Import.cs index a31b7db9..6082e690 100644 --- a/Source/LibationAvalonia/ViewModels/MainVM.Import.cs +++ b/Source/LibationAvalonia/ViewModels/MainVM.Import.cs @@ -15,7 +15,6 @@ namespace LibationAvalonia.ViewModels public partial class MainVM { private int _numAccountsScanning = 2; - private int _accountsCount = 0; public string LocateAudiobooksTip => Configuration.GetHelpText("LocateAudiobooks"); /// Auto scanning accounts is enables diff --git a/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs b/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs index b9790273..1a45f6e8 100644 --- a/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs +++ b/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs @@ -38,7 +38,7 @@ namespace LibationAvalonia.ViewModels { if (ProcessQueue.QueueDownloadDecrypt(libraryBooks)) setQueueCollapseState(false); - else if (libraryBooks.Length == 1 && libraryBooks[0].Book.Audio_Exists()) + else if (libraryBooks.Length == 1 && libraryBooks[0].Book.AudioExists) { // liberated: open explorer to file var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId); diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs index aeaa4c92..6c25f5f6 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs @@ -327,7 +327,7 @@ namespace LibationAvalonia.Views { //No need to persist these changes. They only needs to last long for the files to start downloading entry4.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated; - if (entry4.Book.HasPdf()) + if (entry4.Book.HasPdf) entry4.Book.UserDefinedItem.SetPdfStatus(LiberatedStatus.NotLiberated); LiberateClicked?.Invoke(this, [entry4.LibraryBook]); }) diff --git a/Source/LibationSearchEngine/SearchEngine.cs b/Source/LibationSearchEngine/SearchEngine.cs index 3a3ee68e..5f2bede1 100644 --- a/Source/LibationSearchEngine/SearchEngine.cs +++ b/Source/LibationSearchEngine/SearchEngine.cs @@ -37,8 +37,8 @@ namespace LibationSearchEngine { FieldType.ID, lb => lb.Book.AudibleProductId.ToLowerInvariant(), nameof(Book.AudibleProductId), "ProductId", "Id", "ASIN" }, { FieldType.Raw, lb => lb.Book.AudibleProductId, _ID_ }, { FieldType.String, lb => lb.Book.TitleWithSubtitle, "Title", "ProductId", "Id", "ASIN" }, - { FieldType.String, lb => lb.Book.AuthorNames(), "AuthorNames", "Author", "Authors" }, - { FieldType.String, lb => lb.Book.NarratorNames(), "NarratorNames", "Narrator", "Narrators" }, + { FieldType.String, lb => lb.Book.AuthorNames, "AuthorNames", "Author", "Authors" }, + { FieldType.String, lb => lb.Book.NarratorNames, "NarratorNames", "Narrator", "Narrators" }, { FieldType.String, lb => lb.Book.Publisher, nameof(Book.Publisher) }, { FieldType.String, lb => lb.Book.SeriesNames(), "SeriesNames", "Narrator", "Series" }, { FieldType.String, lb => string.Join(", ", lb.Book.SeriesLink.Select(s => s.Series.AudibleSeriesId)), "SeriesId" }, @@ -48,7 +48,7 @@ namespace LibationSearchEngine { FieldType.String, lb => lb.Book.Locale, "Locale", "Region" }, { FieldType.String, lb => lb.Account, "Account", "Email" }, { FieldType.String, lb => lb.Book.UserDefinedItem.LastDownloadedFormat?.CodecString, "Codec", "DownloadedCodec" }, - { FieldType.Bool, lb => lb.Book.HasPdf().ToString(), "HasDownloads", "HasDownload", "Downloads" , "Download", "HasPDFs", "HasPDF" , "PDFs", "PDF" }, + { FieldType.Bool, lb => lb.Book.HasPdf.ToString(), "HasDownloads", "HasDownload", "Downloads" , "Download", "HasPDFs", "HasPDF" , "PDFs", "PDF" }, { FieldType.Bool, lb => (lb.Book.UserDefinedItem.Rating.OverallRating > 0f).ToString(), "IsRated", "Rated" }, { FieldType.Bool, lb => isAuthorNarrated(lb.Book).ToString(), "IsAuthorNarrated", "AuthorNarrated" }, { FieldType.Bool, lb => lb.Book.IsAbridged.ToString(), nameof(Book.IsAbridged), "Abridged" }, diff --git a/Source/LibationUiBase/GridView/GridContextMenu.cs b/Source/LibationUiBase/GridView/GridContextMenu.cs index 115912d6..43e9733c 100644 --- a/Source/LibationUiBase/GridView/GridContextMenu.cs +++ b/Source/LibationUiBase/GridView/GridContextMenu.cs @@ -60,7 +60,7 @@ public class GridContextMenu .UpdateUserDefinedItemAsync(udi => { udi.BookStatus = LiberatedStatus.Liberated; - if (udi.Book.HasPdf()) + if (udi.Book.HasPdf) udi.SetPdfStatus(LiberatedStatus.Liberated); }); } @@ -71,7 +71,7 @@ public class GridContextMenu .UpdateUserDefinedItemAsync(udi => { udi.BookStatus = LiberatedStatus.NotLiberated; - if (udi.Book.HasPdf()) + if (udi.Book.HasPdf) udi.SetPdfStatus(LiberatedStatus.NotLiberated); }); } diff --git a/Source/LibationUiBase/GridView/GridEntry.cs b/Source/LibationUiBase/GridView/GridEntry.cs index acb7e6fd..d2162bb7 100644 --- a/Source/LibationUiBase/GridView/GridEntry.cs +++ b/Source/LibationUiBase/GridView/GridEntry.cs @@ -98,8 +98,8 @@ namespace LibationUiBase.GridView RaiseAndSetIfChanged(ref _myRating, Book.UserDefinedItem.Rating, nameof(MyRating)); PurchaseDate = GetPurchaseDateString(); ProductRating = Book.Rating ?? new Rating(0, 0, 0); - Authors = Book.AuthorNames(); - Narrators = Book.NarratorNames(); + Authors = Book.AuthorNames; + Narrators = Book.NarratorNames; Category = string.Join(", ", Book.LowestCategoryNames()); Misc = GetMiscDisplay(libraryBook); LastDownload = new(Book.UserDefinedItem); @@ -306,7 +306,7 @@ namespace LibationUiBase.GridView details.Add($"Account: {locale} - {acct}"); - if (libraryBook.Book.HasPdf()) + if (libraryBook.Book.HasPdf) details.Add("Has PDF"); if (libraryBook.Book.IsAbridged) details.Add("Abridged"); diff --git a/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs b/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs index afd0a63c..c416cfa9 100644 --- a/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs +++ b/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs @@ -100,8 +100,8 @@ public class ProcessBookViewModel : ReactiveObject LibraryBook = libraryBook; Title = LibraryBook.Book.TitleWithSubtitle; - Author = LibraryBook.Book.AuthorNames(); - Narrator = LibraryBook.Book.NarratorNames(); + Author = LibraryBook.Book.AuthorNames; + Narrator = LibraryBook.Book.NarratorNames; (bool isDefault, byte[] picture) = PictureStorage.GetPicture(new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._80x80)); @@ -296,8 +296,8 @@ public class ProcessBookViewModel : ReactiveObject LogInfo($"{Environment.NewLine}{processable.Name} Step, Begin: {libraryBook.Book}"); Title = libraryBook.Book.TitleWithSubtitle; - Author = libraryBook.Book.AuthorNames(); - Narrator = libraryBook.Book.NarratorNames(); + Author = libraryBook.Book.AuthorNames; + Narrator = libraryBook.Book.NarratorNames; } private async void Processable_Completed(object? sender, LibraryBook libraryBook) @@ -375,8 +375,8 @@ public class ProcessBookViewModel : ReactiveObject details = $""" Title: {libraryBook.Book.TitleWithSubtitle} ID: {libraryBook.Book.AudibleProductId} - Author: {trunc(libraryBook.Book.AuthorNames())} - Narr: {trunc(libraryBook.Book.NarratorNames())} + Author: {trunc(libraryBook.Book.AuthorNames)} + Narr: {trunc(libraryBook.Book.NarratorNames)} """; } catch diff --git a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs index 88eec862..d7f7a5b8 100644 --- a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs +++ b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs @@ -45,16 +45,16 @@ namespace LibationWinForms.Dialogs this.coverPb.Image = WinFormsUtil.TryLoadImageOrDefault(picture, PictureSize._80x80); var title = string.IsNullOrEmpty(Book.Subtitle) ? Book.Title : $"{Book.Title}\r\n {Book.Subtitle}"; - var t = @$" -Title: {title} -Author(s): {Book.AuthorNames()} -Narrator(s): {Book.NarratorNames()} -Length: {(Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min")} -Category: {string.Join(", ", Book.LowestCategoryNames())} -Purchase Date: {_libraryBook.DateAdded:d} -Language: {Book.Language} -Audible ID: {Book.AudibleProductId} -".Trim(); + var t = $""" + Title: {title} + Author(s): {Book.AuthorNames} + Narrator(s): {Book.NarratorNames} + Length: {(Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min")} + Category: {string.Join(", ", Book.LowestCategoryNames())} + Purchase Date: {_libraryBook.DateAdded:d} + Language: {Book.Language} + Audible ID: {Book.AudibleProductId} + """; var seriesNames = Book.SeriesNames(); if (!string.IsNullOrWhiteSpace(seriesNames)) diff --git a/Source/LibationWinForms/Form1.ProcessQueue.cs b/Source/LibationWinForms/Form1.ProcessQueue.cs index e9c7b2a3..ab5ca9c9 100644 --- a/Source/LibationWinForms/Form1.ProcessQueue.cs +++ b/Source/LibationWinForms/Form1.ProcessQueue.cs @@ -31,7 +31,7 @@ namespace LibationWinForms { if (processBookQueue1.ViewModel.QueueDownloadDecrypt(libraryBooks)) SetQueueCollapseState(false); - else if (libraryBooks.Length == 1 && libraryBooks[0].Book.Audio_Exists()) + else if (libraryBooks.Length == 1 && libraryBooks[0].Book.AudioExists) { // liberated: open explorer to file var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId); diff --git a/Source/LibationWinForms/GridView/ProductsDisplay.cs b/Source/LibationWinForms/GridView/ProductsDisplay.cs index b8458049..c39bcaa9 100644 --- a/Source/LibationWinForms/GridView/ProductsDisplay.cs +++ b/Source/LibationWinForms/GridView/ProductsDisplay.cs @@ -219,7 +219,7 @@ namespace LibationWinForms.GridView { //No need to persist these changes. They only needs to last long for the files to start downloading entry4.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated; - if (entry4.Book.HasPdf()) + if (entry4.Book.HasPdf) entry4.Book.UserDefinedItem.SetPdfStatus(LiberatedStatus.NotLiberated); LiberateClicked?.Invoke(s, [entry4.LibraryBook]);