mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-01-02 19:08:39 -05:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a80a0cc06 | ||
|
|
aebefac7e6 | ||
|
|
b2d0ee41f2 | ||
|
|
9c20250b0a | ||
|
|
b196836fca | ||
|
|
d9fbcc615a | ||
|
|
fb247fb33f | ||
|
|
61f4dbd896 | ||
|
|
2c86571818 | ||
|
|
1b2ec67726 | ||
|
|
845af854bd | ||
|
|
15b6a66d98 | ||
|
|
c95ba0764b | ||
|
|
42c0648ba7 | ||
|
|
0a6e55dcb7 | ||
|
|
99b77decff | ||
|
|
9e2ca4e586 | ||
|
|
2e8acfdeef | ||
|
|
630096e06d | ||
|
|
d92d892dc7 | ||
|
|
a8f41841bd | ||
|
|
76954b5a0a | ||
|
|
c57b184a09 | ||
|
|
20ca4e0739 | ||
|
|
a972ed5e2e | ||
|
|
2b15bc6ebb | ||
|
|
562496cfaa | ||
|
|
8283f19d6b | ||
|
|
242909b542 | ||
|
|
a7b83ad5e0 | ||
|
|
ed66019d9a | ||
|
|
bc0009be6c | ||
|
|
c88f47eed4 | ||
|
|
59de048ced |
@@ -217,40 +217,47 @@ namespace AaxDecrypter
|
||||
{
|
||||
var downloadPosition = WritePosition;
|
||||
var nextFlush = downloadPosition + DATA_FLUSH_SZ;
|
||||
|
||||
var buff = new byte[DOWNLOAD_BUFF_SZ];
|
||||
do
|
||||
|
||||
try
|
||||
{
|
||||
var bytesRead = _networkStream.Read(buff, 0, DOWNLOAD_BUFF_SZ);
|
||||
_writeFile.Write(buff, 0, bytesRead);
|
||||
|
||||
downloadPosition += bytesRead;
|
||||
|
||||
if (downloadPosition > nextFlush)
|
||||
do
|
||||
{
|
||||
_writeFile.Flush();
|
||||
WritePosition = downloadPosition;
|
||||
Update();
|
||||
nextFlush = downloadPosition + DATA_FLUSH_SZ;
|
||||
downloadedPiece.Set();
|
||||
}
|
||||
var bytesRead = _networkStream.Read(buff, 0, DOWNLOAD_BUFF_SZ);
|
||||
_writeFile.Write(buff, 0, bytesRead);
|
||||
|
||||
} while (downloadPosition < ContentLength && !IsCancelled);
|
||||
downloadPosition += bytesRead;
|
||||
|
||||
_writeFile.Close();
|
||||
_networkStream.Close();
|
||||
WritePosition = downloadPosition;
|
||||
Update();
|
||||
if (downloadPosition > nextFlush)
|
||||
{
|
||||
_writeFile.Flush();
|
||||
WritePosition = downloadPosition;
|
||||
Update();
|
||||
nextFlush = downloadPosition + DATA_FLUSH_SZ;
|
||||
downloadedPiece.Set();
|
||||
}
|
||||
|
||||
downloadedPiece.Set();
|
||||
downloadEnded.Set();
|
||||
} while (downloadPosition < ContentLength && !IsCancelled);
|
||||
|
||||
if (!IsCancelled && WritePosition < ContentLength)
|
||||
throw new WebException($"Downloaded size (0x{WritePosition:X10}) is less than {nameof(ContentLength)} (0x{ContentLength:X10}).");
|
||||
_writeFile.Close();
|
||||
_networkStream.Close();
|
||||
WritePosition = downloadPosition;
|
||||
Update();
|
||||
|
||||
if (WritePosition > ContentLength)
|
||||
throw new WebException($"Downloaded size (0x{WritePosition:X10}) is greater than {nameof(ContentLength)} (0x{ContentLength:X10}).");
|
||||
downloadedPiece.Set();
|
||||
downloadEnded.Set();
|
||||
|
||||
if (!IsCancelled && WritePosition < ContentLength)
|
||||
throw new WebException($"Downloaded size (0x{WritePosition:X10}) is less than {nameof(ContentLength)} (0x{ContentLength:X10}).");
|
||||
|
||||
if (WritePosition > ContentLength)
|
||||
throw new WebException($"Downloaded size (0x{WritePosition:X10}) is greater than {nameof(ContentLength)} (0x{ContentLength:X10}).");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Error(ex, "An error was encountered while downloading {Uri}", Uri);
|
||||
IsCancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<Version>7.9.0.1</Version>
|
||||
<Version>7.10.2.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AudibleApi;
|
||||
using AudibleApi.Common;
|
||||
@@ -118,31 +119,38 @@ namespace AudibleUtilities
|
||||
private async Task<List<Item>> getItemsAsync(LibraryOptions libraryOptions, bool importEpisodes)
|
||||
{
|
||||
var items = new List<Item>();
|
||||
#if DEBUG
|
||||
//// this will not work for multi accounts
|
||||
//var library_json = "library.json";
|
||||
//library_json = System.IO.Path.GetFullPath(library_json);
|
||||
//if (System.IO.File.Exists(library_json))
|
||||
//{
|
||||
// items = AudibleApi.Common.Converter.FromJson<List<Item>>(System.IO.File.ReadAllText(library_json));
|
||||
//}
|
||||
#endif
|
||||
|
||||
Serilog.Log.Logger.Debug("Begin initial library scan");
|
||||
Serilog.Log.Logger.Debug("Beginning library scan.");
|
||||
|
||||
if (!items.Any())
|
||||
items = await Api.GetAllLibraryItemsAsync(libraryOptions);
|
||||
List<Task<List<Item>>> getChildEpisodesTasks = new();
|
||||
|
||||
Serilog.Log.Logger.Debug("Initial library scan complete. Begin episode scan");
|
||||
int count = 0, maxConcurrentEpisodeScans = 5;
|
||||
using SemaphoreSlim concurrencySemaphore = new(maxConcurrentEpisodeScans);
|
||||
|
||||
await manageEpisodesAsync(items, importEpisodes);
|
||||
await foreach (var item in Api.GetLibraryItemAsyncEnumerable(libraryOptions))
|
||||
{
|
||||
if (item.IsEpisodes && importEpisodes)
|
||||
{
|
||||
//Get child episodes asynchronously and await all at the end
|
||||
getChildEpisodesTasks.Add(getChildEpisodesAsync(concurrencySemaphore, item));
|
||||
}
|
||||
else if (!item.IsEpisodes)
|
||||
items.Add(item);
|
||||
|
||||
Serilog.Log.Logger.Debug("Episode scan complete");
|
||||
count++;
|
||||
}
|
||||
|
||||
Serilog.Log.Logger.Debug("Library scan complete. Found {count} books and series. Waiting on {getChildEpisodesTasksCount} series episode scans to complete.", count, getChildEpisodesTasks.Count);
|
||||
|
||||
//await and add all episides from all parents
|
||||
foreach (var epList in await Task.WhenAll(getChildEpisodesTasks))
|
||||
items.AddRange(epList);
|
||||
|
||||
Serilog.Log.Logger.Debug("Completed library scan.");
|
||||
|
||||
#if DEBUG
|
||||
//System.IO.File.WriteAllText(library_json, AudibleApi.Common.Converter.ToJson(items));
|
||||
//System.IO.File.WriteAllText(library_json, AudibleApi.Common.Converter.ToJson(items));
|
||||
#endif
|
||||
|
||||
var validators = new List<IValidator>();
|
||||
validators.AddRange(getValidators());
|
||||
foreach (var v in validators)
|
||||
@@ -156,54 +164,24 @@ namespace AudibleUtilities
|
||||
}
|
||||
|
||||
#region episodes and podcasts
|
||||
private async Task manageEpisodesAsync(List<Item> items, bool importEpisodes)
|
||||
|
||||
private async Task<List<Item>> getChildEpisodesAsync(SemaphoreSlim concurrencySemaphore, Item parent)
|
||||
{
|
||||
// add podcasts and episodes to list. If fail, don't let it de-rail the rest of the import
|
||||
await concurrencySemaphore.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
// get parents
|
||||
var parents = items.Where(i => i.IsEpisodes).ToList();
|
||||
#if DEBUG
|
||||
//var parentsDebug = parents.Select(i => i.ToJson()).Aggregate((a, b) => $"{a}\r\n\r\n{b}");
|
||||
//System.IO.File.WriteAllText("parents.json", parentsDebug);
|
||||
#endif
|
||||
Serilog.Log.Logger.Debug("Beginning episode scan for {parent}", parent);
|
||||
|
||||
if (!parents.Any())
|
||||
return;
|
||||
|
||||
Serilog.Log.Logger.Information($"{parents.Count} series of shows/podcasts found");
|
||||
|
||||
// remove episode parents. even if the following stuff fails, these will still be removed from the collection
|
||||
items.RemoveAll(i => i.IsEpisodes);
|
||||
|
||||
if (importEpisodes)
|
||||
{
|
||||
// add children
|
||||
var children = await getEpisodesAsync(parents);
|
||||
Serilog.Log.Logger.Information($"{children.Count} episodes of shows/podcasts found");
|
||||
items.AddRange(children);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Logger.Error(ex, "Error adding podcasts and episodes");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<Item>> getEpisodesAsync(List<Item> parents)
|
||||
{
|
||||
var results = new List<Item>();
|
||||
|
||||
foreach (var parent in parents)
|
||||
{
|
||||
var children = await getEpisodeChildrenAsync(parent);
|
||||
|
||||
// actual individual episode, not the parent of a series.
|
||||
// for now I'm keeping it inside this method since it fits the work flow, incl. importEpisodes logic
|
||||
if (!children.Any())
|
||||
{
|
||||
results.Add(parent);
|
||||
continue;
|
||||
//The parent is the only episode in the podcase series,
|
||||
//so the parent is its own child.
|
||||
parent.Series = new Series[] { new Series { Asin = parent.Asin, Sequence = RelationshipToProduct.Parent, Title = parent.TitleWithSubtitle } };
|
||||
children.Add(parent);
|
||||
return children;
|
||||
}
|
||||
|
||||
foreach (var child in children)
|
||||
@@ -217,7 +195,7 @@ namespace AudibleUtilities
|
||||
{
|
||||
Asin = parent.Asin,
|
||||
// This should properly be Single() not FirstOrDefault(), but FirstOrDefault is defensive for malformed data from audible
|
||||
Sequence = parent.Relationships.FirstOrDefault(r => r.Asin == child.Asin).Sort.ToString(),
|
||||
Sequence = parent.Relationships.FirstOrDefault(r => r.Asin == child.Asin)?.Sort?.ToString() ?? "0",
|
||||
Title = parent.TitleWithSubtitle
|
||||
}
|
||||
};
|
||||
@@ -232,10 +210,14 @@ namespace AudibleUtilities
|
||||
};
|
||||
}
|
||||
|
||||
results.AddRange(children);
|
||||
}
|
||||
Serilog.Log.Logger.Debug("Completed episode scan for {parent}", parent);
|
||||
|
||||
return results;
|
||||
return children;
|
||||
}
|
||||
finally
|
||||
{
|
||||
concurrencySemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<Item>> getEpisodeChildrenAsync(Item parent)
|
||||
@@ -261,8 +243,8 @@ namespace AudibleUtilities
|
||||
{
|
||||
childrenBatch = await Api.GetCatalogProductsAsync(idBatch, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS);
|
||||
#if DEBUG
|
||||
//var childrenBatchDebug = childrenBatch.Select(i => i.ToJson()).Aggregate((a, b) => $"{a}\r\n\r\n{b}");
|
||||
//System.IO.File.WriteAllText($"children of {parent.Asin}.json", childrenBatchDebug);
|
||||
//var childrenBatchDebug = childrenBatch.Select(i => i.ToJson()).Aggregate((a, b) => $"{a}\r\n\r\n{b}");
|
||||
//System.IO.File.WriteAllText($"children of {parent.Asin}.json", childrenBatchDebug);
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -277,7 +259,7 @@ namespace AudibleUtilities
|
||||
throw;
|
||||
}
|
||||
|
||||
Serilog.Log.Logger.Debug($"Batch {i}: {childrenBatch.Count} results");
|
||||
Serilog.Log.Logger.Debug($"Batch {i}: {childrenBatch.Count} results\t({{parent}})", parent);
|
||||
// the service returned no results. probably indicates an error. stop running batches
|
||||
if (!childrenBatch.Any())
|
||||
break;
|
||||
@@ -295,7 +277,7 @@ namespace AudibleUtilities
|
||||
if (childrenIds.Count != results.Count)
|
||||
{
|
||||
var ex = new ApplicationException($"Mis-match: Children defined by parent={childrenIds.Count}. Children returned by batches={results.Count}");
|
||||
Serilog.Log.Logger.Error(ex, "Quantity of series episodes defined by parent does not match quantity returned by batch fetching.");
|
||||
Serilog.Log.Logger.Error(ex, "{parent} - Quantity of series episodes defined by parent does not match quantity returned by batch fetching.", parent);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AudibleApi" Version="2.8.4.1" />
|
||||
<PackageReference Include="AudibleApi" Version="3.0.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,7 +4,8 @@ namespace FileLiberator
|
||||
{
|
||||
public abstract class AudioDecodable : Processable
|
||||
{
|
||||
public event EventHandler<Action<byte[]>> RequestCoverArt;
|
||||
public delegate byte[] RequestCoverArtHandler(object sender, EventArgs eventArgs);
|
||||
public event RequestCoverArtHandler RequestCoverArt;
|
||||
public event EventHandler<string> TitleDiscovered;
|
||||
public event EventHandler<string> AuthorsDiscovered;
|
||||
public event EventHandler<string> NarratorsDiscovered;
|
||||
@@ -32,10 +33,10 @@ namespace FileLiberator
|
||||
NarratorsDiscovered?.Invoke(this, narrators);
|
||||
}
|
||||
|
||||
protected void OnRequestCoverArt(Action<byte[]> setCoverArtDel)
|
||||
protected byte[] OnRequestCoverArt()
|
||||
{
|
||||
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(RequestCoverArt) });
|
||||
RequestCoverArt?.Invoke(this, setCoverArtDel);
|
||||
return RequestCoverArt?.Invoke(this, new());
|
||||
}
|
||||
|
||||
protected void OnCoverImageDiscovered(byte[] coverImage)
|
||||
|
||||
@@ -247,7 +247,7 @@ namespace FileLiberator
|
||||
if (e is not null)
|
||||
OnCoverImageDiscovered(e);
|
||||
else if (Configuration.Instance.AllowLibationFixup)
|
||||
OnRequestCoverArt(abDownloader.SetCoverArt);
|
||||
abDownloader.SetCoverArt(OnRequestCoverArt());
|
||||
}
|
||||
|
||||
/// <summary>Move new files to 'Books' directory</summary>
|
||||
|
||||
@@ -134,7 +134,8 @@ namespace FileManager
|
||||
|
||||
private void AddPath(string path)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
if (!File.Exists(path) && !Directory.Exists(path))
|
||||
return;
|
||||
if (File.GetAttributes(path).HasFlag(FileAttributes.Directory))
|
||||
AddUniqueFiles(FileUtility.SaferEnumerateFiles(path, SearchPattern, SearchOption));
|
||||
else
|
||||
|
||||
@@ -100,14 +100,15 @@ namespace LibationWinForms.GridView
|
||||
{
|
||||
#nullable enable
|
||||
public static IEnumerable<SeriesEntry> Series(this IEnumerable<GridEntry> gridEntries)
|
||||
=> gridEntries.Where(i => i is SeriesEntry).Cast<SeriesEntry>();
|
||||
=> gridEntries.OfType<SeriesEntry>();
|
||||
public static IEnumerable<LibraryBookEntry> LibraryBooks(this IEnumerable<GridEntry> gridEntries)
|
||||
=> gridEntries.Where(i => i is LibraryBookEntry).Cast<LibraryBookEntry>();
|
||||
=> gridEntries.OfType<LibraryBookEntry>();
|
||||
public static LibraryBookEntry? FindBookByAsin(this IEnumerable<LibraryBookEntry> gridEntries, string audibleProductID)
|
||||
=> gridEntries.FirstOrDefault(i => i.AudibleProductId == audibleProductID);
|
||||
public static SeriesEntry? FindBookSeriesEntry(this IEnumerable<GridEntry> gridEntries, IEnumerable<SeriesBook> matchSeries)
|
||||
=> gridEntries.Series().FirstOrDefault(i => matchSeries.Any(s => s.Series.Name == i.Series));
|
||||
public static IEnumerable<SeriesEntry> EmptySeries(this IEnumerable<GridEntry> gridEntries)
|
||||
=> gridEntries.Series().Where(i => i.Children.Count == 0);
|
||||
public static bool IsEpisodeChild(this LibraryBook lb) => lb.Book.ContentType == ContentType.Episode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,7 @@ namespace LibationWinForms.GridView
|
||||
|
||||
if (status.IsSeries)
|
||||
{
|
||||
var imageName = status.Expanded ? "minus" : "plus";
|
||||
|
||||
var bmp = (Bitmap)Properties.Resources.ResourceManager.GetObject(imageName);
|
||||
DrawButtonImage(graphics, bmp, cellBounds);
|
||||
DrawButtonImage(graphics, status.Expanded ? Properties.Resources.minus: Properties.Resources.plus, cellBounds);
|
||||
|
||||
ToolTipText = status.Expanded ? "Click to Collpase" : "Click to Expand";
|
||||
}
|
||||
|
||||
@@ -84,18 +84,25 @@ namespace LibationWinForms.GridView
|
||||
|
||||
public void Display()
|
||||
{
|
||||
// don't return early if lib size == 0. this will not update correctly if all books are removed
|
||||
var lib = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
if (!hasBeenDisplayed)
|
||||
try
|
||||
{
|
||||
// bind
|
||||
productsGrid.BindToGrid(lib);
|
||||
hasBeenDisplayed = true;
|
||||
InitialLoaded?.Invoke(this, new());
|
||||
// don't return early if lib size == 0. this will not update correctly if all books are removed
|
||||
var lib = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
if (!hasBeenDisplayed)
|
||||
{
|
||||
// bind
|
||||
productsGrid.BindToGrid(lib);
|
||||
hasBeenDisplayed = true;
|
||||
InitialLoaded?.Invoke(this, new());
|
||||
}
|
||||
else
|
||||
productsGrid.UpdateGrid(lib);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Error(ex, "Error displaying library in {0}", nameof(ProductsDisplay));
|
||||
}
|
||||
else
|
||||
productsGrid.UpdateGrid(lib);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -84,11 +84,12 @@ namespace LibationWinForms.GridView
|
||||
{
|
||||
var geList = dbBooks.Where(b => b.Book.ContentType is not ContentType.Episode).Select(b => new LibraryBookEntry(b)).Cast<GridEntry>().ToList();
|
||||
|
||||
var episodes = dbBooks.Where(b => b.Book.ContentType is ContentType.Episode).ToList();
|
||||
var episodes = dbBooks.Where(b => b.IsEpisodeChild()).ToList();
|
||||
|
||||
foreach (var series in episodes.Select(lb => lb.Book.SeriesLink.First()).DistinctBy(s => s.Series))
|
||||
var allSeries = episodes.SelectMany(lb => lb.Book.SeriesLink.Where(s => !s.Series.AudibleSeriesId.StartsWith("SERIES_"))).DistinctBy(s => s.Series).ToList();
|
||||
foreach (var series in allSeries)
|
||||
{
|
||||
var seriesEntry = new SeriesEntry(series, episodes.Where(lb => lb.Book.SeriesLink.First().Series == series.Book.SeriesLink.First().Series));
|
||||
var seriesEntry = new SeriesEntry(series, episodes.Where(lb => lb.Book.SeriesLink.Any(s => s.Series == series.Series)));
|
||||
|
||||
geList.Add(seriesEntry);
|
||||
geList.AddRange(seriesEntry.Children);
|
||||
@@ -117,7 +118,7 @@ namespace LibationWinForms.GridView
|
||||
// add new to top
|
||||
if (existingItem is null)
|
||||
{
|
||||
if (libraryBook.Book.ContentType is ContentType.Episode)
|
||||
if (libraryBook.IsEpisodeChild())
|
||||
{
|
||||
LibraryBookEntry lbe;
|
||||
//Find the series that libraryBook belongs to, if it exists
|
||||
@@ -148,7 +149,7 @@ namespace LibationWinForms.GridView
|
||||
|
||||
series.NotifyPropertyChanged();
|
||||
}
|
||||
else
|
||||
else if (libraryBook.Book.ContentType is not ContentType.Episode)
|
||||
//Add the new product
|
||||
bindingList.Insert(0, new LibraryBookEntry(libraryBook));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
private Processable CurrentProcessable => _currentProcessable ??= Processes.Dequeue().Invoke();
|
||||
private Processable NextProcessable() => _currentProcessable = null;
|
||||
private Processable _currentProcessable;
|
||||
private Func<byte[]> GetCoverArtDelegate;
|
||||
private readonly Queue<Func<Processable>> Processes = new();
|
||||
private readonly LogMe Logger;
|
||||
|
||||
@@ -232,11 +231,14 @@ namespace LibationWinForms.ProcessQueue
|
||||
BookText = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}";
|
||||
}
|
||||
|
||||
public void AudioDecodable_RequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate)
|
||||
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
||||
{
|
||||
byte[] coverData = GetCoverArtDelegate();
|
||||
setCoverArtDelegate(coverData);
|
||||
byte[] coverData = PictureStorage
|
||||
.GetPictureSynchronously(
|
||||
new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500));
|
||||
|
||||
AudioDecodable_CoverImageDiscovered(this, coverData);
|
||||
return coverData;
|
||||
}
|
||||
|
||||
private void AudioDecodable_CoverImageDiscovered(object sender, byte[] coverArt)
|
||||
@@ -273,11 +275,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
|
||||
Logger.Info($"{Environment.NewLine}{((Processable)sender).Name} Step, Begin: {libraryBook.Book}");
|
||||
|
||||
GetCoverArtDelegate = () => PictureStorage.GetPictureSynchronously(
|
||||
new PictureDefinition(
|
||||
libraryBook.Book.PictureId,
|
||||
PictureSize._500x500));
|
||||
|
||||
title = libraryBook.Book.Title;
|
||||
authorNames = libraryBook.Book.AuthorNames();
|
||||
narratorNames = libraryBook.Book.NarratorNames();
|
||||
@@ -286,7 +283,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
|
||||
private async void Processable_Completed(object sender, LibraryBook libraryBook)
|
||||
{
|
||||
|
||||
Logger.Info($"{((Processable)sender).Name} Step, Completed: {libraryBook.Book}");
|
||||
UnlinkProcessable((Processable)sender);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user