Add ContentType.Parent
Import Series parent when only individual episodes are in library
This commit is contained in:
parent
30e6deeeaa
commit
c48eacd9af
@ -1,11 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AudibleApi;
|
using AudibleApi;
|
||||||
using AudibleApi.Common;
|
using AudibleApi.Common;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
using Polly;
|
using Polly;
|
||||||
using Polly.Retry;
|
using Polly.Retry;
|
||||||
|
|
||||||
@ -129,7 +132,7 @@ namespace AudibleUtilities
|
|||||||
|
|
||||||
await foreach (var item in Api.GetLibraryItemAsyncEnumerable(libraryOptions))
|
await foreach (var item in Api.GetLibraryItemAsyncEnumerable(libraryOptions))
|
||||||
{
|
{
|
||||||
if (item.IsEpisodes && importEpisodes)
|
if ((item.IsEpisodes || item.IsSeriesParent) && importEpisodes)
|
||||||
{
|
{
|
||||||
//Get child episodes asynchronously and await all at the end
|
//Get child episodes asynchronously and await all at the end
|
||||||
getChildEpisodesTasks.Add(getChildEpisodesAsync(concurrencySemaphore, item));
|
getChildEpisodesTasks.Add(getChildEpisodesAsync(concurrencySemaphore, item));
|
||||||
@ -173,17 +176,66 @@ namespace AudibleUtilities
|
|||||||
{
|
{
|
||||||
Serilog.Log.Logger.Debug("Beginning episode scan for {parent}", parent);
|
Serilog.Log.Logger.Debug("Beginning episode scan for {parent}", parent);
|
||||||
|
|
||||||
var children = await getEpisodeChildrenAsync(parent);
|
List<Item> children;
|
||||||
|
|
||||||
if (!children.Any())
|
if (parent.IsEpisodes)
|
||||||
{
|
{
|
||||||
//The parent is the only episode in the podcase series,
|
//The 'parent' is a single episode that was added to the library.
|
||||||
//so the parent is its own child.
|
//Get the episode's parent and add it to the database.
|
||||||
parent.Series = new Series[] { new Series { Asin = parent.Asin, Sequence = RelationshipToProduct.Parent, Title = parent.TitleWithSubtitle } };
|
|
||||||
children.Add(parent);
|
Serilog.Log.Logger.Debug("Supplied Parent is an episode. Beginning parent scan for {parent}", parent);
|
||||||
return children;
|
|
||||||
|
children = new() { parent };
|
||||||
|
|
||||||
|
var parentAsins = parent.Relationships
|
||||||
|
.Where(r => r.RelationshipToProduct == RelationshipToProduct.Parent)
|
||||||
|
.Select(p => p.Asin);
|
||||||
|
|
||||||
|
var seriesParents = await Api.GetCatalogProductsAsync(parentAsins, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS);
|
||||||
|
|
||||||
|
int numSeriesParents = seriesParents.Count(p => p.IsSeriesParent);
|
||||||
|
if (numSeriesParents != 1)
|
||||||
|
{
|
||||||
|
//There should only ever be 1 top-level parent per episode. If not, log
|
||||||
|
//and throw so we can figure out what to do about those special cases.
|
||||||
|
JsonSerializerSettings Settings = new()
|
||||||
|
{
|
||||||
|
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
|
||||||
|
DateParseHandling = DateParseHandling.None,
|
||||||
|
Converters =
|
||||||
|
{
|
||||||
|
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var ex = new ApplicationException($"Found {numSeriesParents} parents for {parent.Asin}");
|
||||||
|
Serilog.Log.Logger.Error(ex, $"Episode Product:\r\n{JsonConvert.SerializeObject(parent, Formatting.None, Settings)}");
|
||||||
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var realParent = seriesParents.Single(p => p.IsSeriesParent);
|
||||||
|
realParent.PurchaseDate = parent.PurchaseDate;
|
||||||
|
|
||||||
|
Serilog.Log.Logger.Debug("Completed parent scan for {parent}", parent);
|
||||||
|
parent = realParent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
children = await getEpisodeChildrenAsync(parent);
|
||||||
|
if (!children.Any())
|
||||||
|
return new();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A series parent will always have exactly 1 Series
|
||||||
|
parent.Series = new Series[]
|
||||||
|
{
|
||||||
|
new Series
|
||||||
|
{
|
||||||
|
Asin = parent.Asin,
|
||||||
|
Sequence = "-1",
|
||||||
|
Title = parent.TitleWithSubtitle
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var child in children)
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
// use parent's 'DateAdded'. DateAdded is just a convenience prop for: PurchaseDate.UtcDateTime
|
// use parent's 'DateAdded'. DateAdded is just a convenience prop for: PurchaseDate.UtcDateTime
|
||||||
@ -199,17 +251,10 @@ namespace AudibleUtilities
|
|||||||
Title = parent.TitleWithSubtitle
|
Title = parent.TitleWithSubtitle
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// overload (read: abuse) IsEpisodes flag
|
|
||||||
child.Relationships = new Relationship[]
|
|
||||||
{
|
|
||||||
new Relationship
|
|
||||||
{
|
|
||||||
RelationshipToProduct = RelationshipToProduct.Child,
|
|
||||||
RelationshipType = RelationshipType.Episode
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
children.Add(parent);
|
||||||
|
|
||||||
Serilog.Log.Logger.Debug("Completed episode scan for {parent}", parent);
|
Serilog.Log.Logger.Debug("Completed episode scan for {parent}", parent);
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
|
|||||||
@ -16,8 +16,14 @@ namespace DataLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// enum will be easier than bool to extend later
|
// enum will be easier than bool to extend later.
|
||||||
public enum ContentType { Unknown = 0, Product = 1, Episode = 2 }
|
public enum ContentType
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Product = 1,
|
||||||
|
Episode = 2,
|
||||||
|
Parent = 4,
|
||||||
|
}
|
||||||
|
|
||||||
public class Book
|
public class Book
|
||||||
{
|
{
|
||||||
|
|||||||
@ -75,7 +75,7 @@ namespace DtoImporterService
|
|||||||
{
|
{
|
||||||
var item = importItem.DtoItem;
|
var item = importItem.DtoItem;
|
||||||
|
|
||||||
var contentType = item.IsEpisodes ? DataLayer.ContentType.Episode : DataLayer.ContentType.Product;
|
var contentType = GetContentType(item);
|
||||||
|
|
||||||
// absence of authors is very rare, but possible
|
// absence of authors is very rare, but possible
|
||||||
if (!item.Authors?.Any() ?? true)
|
if (!item.Authors?.Any() ?? true)
|
||||||
@ -184,5 +184,15 @@ namespace DtoImporterService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DataLayer.ContentType GetContentType(Item item)
|
||||||
|
{
|
||||||
|
if (item.IsEpisodes)
|
||||||
|
return DataLayer.ContentType.Episode;
|
||||||
|
else if (item.IsSeriesParent)
|
||||||
|
return DataLayer.ContentType.Parent;
|
||||||
|
else
|
||||||
|
return DataLayer.ContentType.Product;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,8 @@ namespace FileLiberator
|
|||||||
public IEnumerable<LibraryBook> GetValidLibraryBooks(IEnumerable<LibraryBook> library)
|
public IEnumerable<LibraryBook> GetValidLibraryBooks(IEnumerable<LibraryBook> library)
|
||||||
=> library.Where(libraryBook =>
|
=> library.Where(libraryBook =>
|
||||||
Validate(libraryBook)
|
Validate(libraryBook)
|
||||||
&& (libraryBook.Book.ContentType != ContentType.Episode || LibationFileManager.Configuration.Instance.DownloadEpisodes)
|
&& libraryBook.Book.ContentType != ContentType.Parent
|
||||||
|
&& (libraryBook.Book.ContentType != ContentType.Episode || Configuration.Instance.DownloadEpisodes)
|
||||||
);
|
);
|
||||||
|
|
||||||
public async Task<StatusHandler> ProcessSingleAsync(LibraryBook libraryBook, bool validate)
|
public async Task<StatusHandler> ProcessSingleAsync(LibraryBook libraryBook, bool validate)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user