Tested on a library with ~5000 podcast episodes on an AMD Ryzen 7700X. Startup time decreases by ~400 ms in Release mode.
107 lines
3.5 KiB
C#
107 lines
3.5 KiB
C#
using DataLayer;
|
|
using Dinah.Core.Collections.Generic;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace LibationUiBase.GridView
|
|
{
|
|
/// <summary>The View Model for a LibraryBook that is ContentType.Parent</summary>
|
|
public class SeriesEntry<TStatus> : GridEntry<TStatus>, ISeriesEntry where TStatus : IEntryStatus
|
|
{
|
|
public List<ILibraryBookEntry> Children { get; }
|
|
public override DateTime DateAdded => Children.Max(c => c.DateAdded);
|
|
|
|
private bool suspendCounting = false;
|
|
public void ChildRemoveUpdate()
|
|
{
|
|
if (suspendCounting) return;
|
|
|
|
var removeCount = Children.Count(c => c.Remove == true);
|
|
|
|
remove = removeCount == 0 ? false : removeCount == Children.Count ? true : null;
|
|
RaisePropertyChanged(nameof(Remove));
|
|
}
|
|
|
|
public override bool? Remove
|
|
{
|
|
get => remove;
|
|
set
|
|
{
|
|
remove = value ?? false;
|
|
|
|
suspendCounting = true;
|
|
|
|
foreach (var item in Children)
|
|
item.Remove = value;
|
|
|
|
suspendCounting = false;
|
|
RaisePropertyChanged(nameof(Remove));
|
|
}
|
|
}
|
|
|
|
public SeriesEntry(LibraryBook parent, LibraryBook child) : this(parent, new[] { child }) { }
|
|
public SeriesEntry(LibraryBook parent, IEnumerable<LibraryBook> children)
|
|
{
|
|
LastDownload = new();
|
|
SeriesIndex = -1;
|
|
|
|
Children = children
|
|
.Select(c => new LibraryBookEntry<TStatus>(c, this))
|
|
.OrderByDescending(c => c.SeriesOrder)
|
|
.ToList<ILibraryBookEntry>();
|
|
|
|
UpdateLibraryBook(parent);
|
|
LoadCover();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates <see cref="SeriesEntry{TStatus}"/> for all episodic series in an enumeration of <see cref="LibraryBook"/>.
|
|
/// </summary>
|
|
/// <remarks>Can be called from any thread, but requires the calling thread's <see cref="SynchronizationContext.Current"/> to be valid.</remarks>
|
|
public static async Task<List<ISeriesEntry>> GetAllSeriesEntriesAsync(IEnumerable<LibraryBook> libraryBooks)
|
|
{
|
|
var seriesEntries = await GetAllProductsAsync(libraryBooks, lb => lb.Book.IsEpisodeParent(), lb => new SeriesEntry<TStatus>(lb, []) as ISeriesEntry);
|
|
var seriesDict = seriesEntries.ToDictionarySafe(s => s.AudibleProductId);
|
|
await GetAllProductsAsync(libraryBooks, lb => lb.Book.IsEpisodeChild(), CreateAndLinkEpisodeEntry);
|
|
|
|
//sort episodes by series order descending and update SeriesEntry
|
|
foreach (var series in seriesEntries)
|
|
{
|
|
series.Children.Sort((a, b) => -a.SeriesOrder.CompareTo(b.SeriesOrder));
|
|
series.UpdateLibraryBook(series.LibraryBook);
|
|
}
|
|
|
|
return seriesEntries.Where(s => s.Children.Count != 0).ToList();
|
|
|
|
//Create a LibraryBookEntry for an episode and link it to its series parent
|
|
LibraryBookEntry<TStatus> CreateAndLinkEpisodeEntry(LibraryBook episode)
|
|
{
|
|
foreach (var s in episode.Book.SeriesLink)
|
|
{
|
|
if (seriesDict.TryGetValue(s.Series.AudibleSeriesId, out var seriesParent))
|
|
{
|
|
var entry = new LibraryBookEntry<TStatus>(episode, seriesParent);
|
|
seriesParent.Children.Add(entry);
|
|
return entry;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void RemoveChild(ILibraryBookEntry lbe)
|
|
{
|
|
Children.Remove(lbe);
|
|
PurchaseDate = GetPurchaseDateString();
|
|
Length = GetBookLengthString();
|
|
}
|
|
|
|
protected override string GetBookTags() => null;
|
|
protected override int GetLengthInMinutes() => Children.Count == 0 ? 0 : Children.Sum(c => c.LibraryBook.Book.LengthInMinutes);
|
|
protected override DateTime GetPurchaseDate() => Children.Count == 0 ? default : Children.Min(c => c.LibraryBook.DateAdded);
|
|
}
|
|
}
|