* upgrade api. lay the groundwork for supporting external logins. When complete, this will be v6.0
* replace AudibleApiActions with ApiExtended
This commit is contained in:
parent
5a1303c33a
commit
51020ef99e
@ -3,7 +3,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Version>5.7.5.1</Version>
|
||||
<Version>6.0.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -136,11 +136,11 @@ namespace ApplicationServices
|
||||
{
|
||||
var callback = loginCallbackFactoryFunc(account);
|
||||
|
||||
// get APIs in serial, esp b/c of logins
|
||||
var api = await AudibleApiActions.GetApiAsync(callback, account);
|
||||
// get APIs in serial b/c of logins
|
||||
var apiExtended = await ApiExtended.CreateAsync(callback, account);
|
||||
|
||||
// add scanAccountAsync as a TASK: do not await
|
||||
tasks.Add(scanAccountAsync(api, account));
|
||||
tasks.Add(scanAccountAsync(apiExtended, account));
|
||||
}
|
||||
|
||||
// import library in parallel
|
||||
@ -149,7 +149,7 @@ namespace ApplicationServices
|
||||
return importItems;
|
||||
}
|
||||
|
||||
private static async Task<List<ImportItem>> scanAccountAsync(Api api, Account account)
|
||||
private static async Task<List<ImportItem>> scanAccountAsync(ApiExtended apiExtended, Account account)
|
||||
{
|
||||
ArgumentValidator.EnsureNotNull(account, nameof(account));
|
||||
|
||||
@ -160,7 +160,7 @@ namespace ApplicationServices
|
||||
|
||||
logTime($"pre scanAccountAsync {account.AccountName}");
|
||||
|
||||
var dtoItems = await AudibleApiActions.GetLibraryValidatedAsync(api, LibraryResponseGroups);
|
||||
var dtoItems = await apiExtended.GetLibraryValidatedAsync(LibraryResponseGroups);
|
||||
|
||||
logTime($"post scanAccountAsync {account.AccountName} qty: {dtoItems.Count}");
|
||||
|
||||
|
||||
@ -84,16 +84,16 @@ namespace FileLiberator
|
||||
{
|
||||
validate(libraryBook);
|
||||
|
||||
var api = await InternalUtilities.AudibleApiActions.GetApiAsync(libraryBook.Account, libraryBook.Book.Locale);
|
||||
var apiExtended = await InternalUtilities.ApiExtended.CreateAsync(libraryBook.Account, libraryBook.Book.Locale);
|
||||
|
||||
var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId);
|
||||
var contentLic = await apiExtended.Api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId);
|
||||
|
||||
var aaxcDecryptDlLic = new DownloadLicense
|
||||
(
|
||||
contentLic?.ContentMetadata?.ContentUrl?.OfflineUrl,
|
||||
contentLic?.Voucher?.Key,
|
||||
contentLic?.Voucher?.Iv,
|
||||
Resources.UserAgent
|
||||
Resources.USER_AGENT
|
||||
);
|
||||
|
||||
if (Configuration.Instance.AllowLibationFixup)
|
||||
|
||||
@ -59,8 +59,8 @@ namespace FileLiberator
|
||||
|
||||
private async Task<string> downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath)
|
||||
{
|
||||
var api = await GetApiAsync(libraryBook);
|
||||
var downloadUrl = await api.GetPdfDownloadLinkAsync(libraryBook.Book.AudibleProductId);
|
||||
var apiExtended = await GetApiExtendedAsync(libraryBook);
|
||||
var downloadUrl = await apiExtended.Api.GetPdfDownloadLinkAsync(libraryBook.Book.AudibleProductId);
|
||||
|
||||
var client = new HttpClient();
|
||||
var actualDownloadedFilePath = await PerformDownloadAsync(
|
||||
|
||||
@ -40,8 +40,8 @@ namespace FileLiberator
|
||||
}
|
||||
}
|
||||
|
||||
protected static Task<AudibleApi.Api> GetApiAsync(LibraryBook libraryBook)
|
||||
=> InternalUtilities.AudibleApiActions.GetApiAsync(libraryBook.Account, libraryBook.Book.Locale);
|
||||
protected static Task<InternalUtilities.ApiExtended> GetApiExtendedAsync(LibraryBook libraryBook)
|
||||
=> InternalUtilities.ApiExtended.CreateAsync(libraryBook.Account, libraryBook.Book.Locale);
|
||||
|
||||
protected async Task<string> PerformDownloadAsync(string proposedDownloadFilePath, Func<Progress<DownloadProgress>, Task<string>> func)
|
||||
{
|
||||
|
||||
@ -10,36 +10,42 @@ using Polly.Retry;
|
||||
|
||||
namespace InternalUtilities
|
||||
{
|
||||
public static class AudibleApiActions
|
||||
{
|
||||
/// <summary>USE THIS from within Libation. It wraps the call with correct JSONPath</summary>
|
||||
public static Task<Api> GetApiAsync(string username, string localeName, ILoginCallback loginCallback = null)
|
||||
public class ApiExtended
|
||||
{
|
||||
public Api Api { get; private set; }
|
||||
|
||||
private ApiExtended(Api api) => Api = api;
|
||||
|
||||
public static async Task<ApiExtended> CreateAsync(string username, string localeName)
|
||||
{
|
||||
Serilog.Log.Logger.Information("GetApiAsync. {@DebugInfo}", new
|
||||
{
|
||||
Username = username.ToMask(),
|
||||
LocaleName = localeName,
|
||||
});
|
||||
return EzApiCreator.GetApiAsync(
|
||||
|
||||
var api = await EzApiCreator.GetApiAsync(
|
||||
Localization.Get(localeName),
|
||||
AudibleApiStorage.AccountsSettingsFile,
|
||||
AudibleApiStorage.GetIdentityTokensJsonPath(username, localeName),
|
||||
loginCallback);
|
||||
AudibleApiStorage.GetIdentityTokensJsonPath(username, localeName));
|
||||
return new ApiExtended(api);
|
||||
}
|
||||
|
||||
/// <summary>USE THIS from within Libation. It wraps the call with correct JSONPath</summary>
|
||||
public static Task<Api> GetApiAsync(ILoginCallback loginCallback, Account account)
|
||||
public static async Task<ApiExtended> CreateAsync(ILoginCallback loginCallback, Account account)
|
||||
{
|
||||
Serilog.Log.Logger.Information("GetApiAsync. {@DebugInfo}", new
|
||||
{
|
||||
Account = account?.MaskedLogEntry ?? "[null]",
|
||||
LocaleName = account?.Locale?.Name
|
||||
});
|
||||
return EzApiCreator.GetApiAsync(
|
||||
|
||||
var api = await EzApiCreator.GetApiAsync(
|
||||
account.Locale,
|
||||
AudibleApiStorage.AccountsSettingsFile,
|
||||
account.GetIdentityTokensJsonPath(),
|
||||
loginCallback);
|
||||
loginCallback,
|
||||
account.GetIdentityTokensJsonPath());
|
||||
return new ApiExtended(api);
|
||||
}
|
||||
|
||||
private static AsyncRetryPolicy policy { get; }
|
||||
@ -47,16 +53,16 @@ namespace InternalUtilities
|
||||
// 2 retries == 3 total
|
||||
.RetryAsync(2);
|
||||
|
||||
public static Task<List<Item>> GetLibraryValidatedAsync(Api api, LibraryOptions.ResponseGroupOptions responseGroups = LibraryOptions.ResponseGroupOptions.ALL_OPTIONS)
|
||||
public Task<List<Item>> GetLibraryValidatedAsync(LibraryOptions.ResponseGroupOptions responseGroups = LibraryOptions.ResponseGroupOptions.ALL_OPTIONS)
|
||||
{
|
||||
// bug on audible's side. the 1st time after a long absence, a query to get library will return without titles or authors. a subsequent identical query will be successful. this is true whether or tokens are refreshed
|
||||
// worse, this 1st dummy call doesn't seem to help:
|
||||
// var page = await api.GetLibraryAsync(new AudibleApi.LibraryOptions { NumberOfResultPerPage = 1, PageNumber = 1, PurchasedAfter = DateTime.Now.AddYears(-20), ResponseGroups = AudibleApi.LibraryOptions.ResponseGroupOptions.ALL_OPTIONS });
|
||||
// i don't want to incur the cost of making a full dummy call every time because it fails sometimes
|
||||
return policy.ExecuteAsync(() => getItemsAsync(api, responseGroups));
|
||||
return policy.ExecuteAsync(() => getItemsAsync(responseGroups));
|
||||
}
|
||||
|
||||
private static async Task<List<Item>> getItemsAsync(Api api, LibraryOptions.ResponseGroupOptions responseGroups)
|
||||
private async Task<List<Item>> getItemsAsync(LibraryOptions.ResponseGroupOptions responseGroups)
|
||||
{
|
||||
var items = new List<Item>();
|
||||
#if DEBUG
|
||||
@ -68,12 +74,12 @@ namespace InternalUtilities
|
||||
//}
|
||||
#endif
|
||||
if (!items.Any())
|
||||
items = await api.GetAllLibraryItemsAsync(responseGroups);
|
||||
items = await Api.GetAllLibraryItemsAsync(responseGroups);
|
||||
#if DEBUG
|
||||
//System.IO.File.WriteAllText("library.json", AudibleApi.Common.Converter.ToJson(items));
|
||||
#endif
|
||||
|
||||
await manageEpisodesAsync(api, items);
|
||||
await manageEpisodesAsync(items);
|
||||
|
||||
var validators = new List<IValidator>();
|
||||
validators.AddRange(getValidators());
|
||||
@ -88,7 +94,7 @@ namespace InternalUtilities
|
||||
}
|
||||
|
||||
#region episodes and podcasts
|
||||
private static async Task manageEpisodesAsync(Api api, List<Item> items)
|
||||
private async Task manageEpisodesAsync(List<Item> items)
|
||||
{
|
||||
// add podcasts and episodes to list. If fail, don't let it de-rail the rest of the import
|
||||
try
|
||||
@ -110,7 +116,7 @@ namespace InternalUtilities
|
||||
items.RemoveAll(i => i.IsEpisodes);
|
||||
|
||||
// add children
|
||||
var children = await getEpisodesAsync(api, parents);
|
||||
var children = await getEpisodesAsync(parents);
|
||||
Serilog.Log.Logger.Information($"{children.Count} episodes of shows/podcasts found");
|
||||
items.AddRange(children);
|
||||
}
|
||||
@ -120,13 +126,13 @@ namespace InternalUtilities
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<List<Item>> getEpisodesAsync(Api api, List<Item> parents)
|
||||
private async Task<List<Item>> getEpisodesAsync(List<Item> parents)
|
||||
{
|
||||
var results = new List<Item>();
|
||||
|
||||
foreach (var parent in parents)
|
||||
{
|
||||
var children = await getEpisodeChildrenAsync(api, parent);
|
||||
var children = await getEpisodeChildrenAsync(parent);
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
@ -159,7 +165,7 @@ namespace InternalUtilities
|
||||
return results;
|
||||
}
|
||||
|
||||
private static async Task<List<Item>> getEpisodeChildrenAsync(Api api, Item parent)
|
||||
private async Task<List<Item>> getEpisodeChildrenAsync(Item parent)
|
||||
{
|
||||
var childrenIds = parent.Relationships
|
||||
.Where(r => r.RelationshipToProduct == RelationshipToProduct.Child && r.RelationshipType == RelationshipType.Episode)
|
||||
@ -180,7 +186,7 @@ namespace InternalUtilities
|
||||
List<Item> childrenBatch;
|
||||
try
|
||||
{
|
||||
childrenBatch = await api.GetCatalogProductsAsync(idBatch, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS);
|
||||
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);
|
||||
@ -222,7 +228,7 @@ namespace InternalUtilities
|
||||
|
||||
return results;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
private static List<IValidator> getValidators()
|
||||
{
|
||||
@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AudibleApi" Version="1.2.1.2" />
|
||||
<PackageReference Include="AudibleApi" Version="2.0.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
using AudibleApi;
|
||||
using System;
|
||||
using AudibleApi;
|
||||
using InternalUtilities;
|
||||
using LibationWinForms.Dialogs.Login;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationWinForms.Login
|
||||
{
|
||||
|
||||
@ -183,7 +183,8 @@ namespace LibationWinForms
|
||||
authorize.DeregisterAsync(identity.ExistingAccessToken, identity.Cookies.ToKeyValuePair()).GetAwaiter().GetResult();
|
||||
identity.Invalidate();
|
||||
|
||||
var api = AudibleApiActions.GetApiAsync(new Login.WinformResponder(account), account).GetAwaiter().GetResult();
|
||||
// re-registers device
|
||||
ApiExtended.CreateAsync(new Login.WinformResponder(account), account).GetAwaiter().GetResult();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user