Libation/AudibleApiDomainService/AudibleApiLibationClient.cs
2019-10-21 16:27:28 -04:00

123 lines
3.7 KiB
C#

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using AudibleApi;
using AudibleApi.Authentication;
using AudibleApi.Authorization;
using Newtonsoft.Json.Linq;
namespace AudibleApiDomainService
{
public class AudibleApiLibationClient
{
private Api _api;
#region initialize api
private AudibleApiLibationClient() { }
public async static Task<AudibleApiLibationClient> CreateClientAsync(Settings settings, IAudibleApiResponder responder)
{
Localization.SetLocale(settings.LocaleCountryCode);
Api api;
try
{
api = await EzApiCreator.GetApiAsync(settings.IdentityFilePath);
}
catch
{
var inMemoryIdentity = await loginAsync(responder);
api = await EzApiCreator.GetApiAsync(settings.IdentityFilePath, inMemoryIdentity);
}
return new AudibleApiLibationClient { _api = api };
}
// LOGIN PATTERN
// - Start with Authenticate. Submit email + pw
// - Each step in the login process will return a LoginResult
// - Each result which has required user input has a SubmitAsync method
// - The final LoginComplete result returns "Identity" -- in-memory authorization items
private static async Task<IIdentity> loginAsync(IAudibleApiResponder responder)
{
var login = new Authenticate();
var (email, password) = responder.GetLogin();
var loginResult = await login.SubmitCredentialsAsync(email, password);
while (true)
{
switch (loginResult)
{
case CredentialsPage credentialsPage:
var (emailInput, pwInput) = responder.GetLogin();
loginResult = await credentialsPage.SubmitAsync(emailInput, pwInput);
break;
case CaptchaPage captchaResult:
var imageBytes = await downloadImageAsync(captchaResult.CaptchaImage);
var guess = responder.GetCaptchaAnswer(imageBytes);
loginResult = await captchaResult.SubmitAsync(guess);
break;
case TwoFactorAuthenticationPage _2fa:
var _2faCode = responder.Get2faCode();
loginResult = await _2fa.SubmitAsync(_2faCode);
break;
case LoginComplete final:
return final.Identity;
default:
throw new Exception("Unknown LoginResult");
}
}
}
private static async Task<byte[]> downloadImageAsync(Uri imageUri)
{
using var client = new HttpClient();
using var contentStream = await client.GetStreamAsync(imageUri);
using var localStream = new MemoryStream();
await contentStream.CopyToAsync(localStream);
return localStream.ToArray();
}
#endregion
public async Task<JObject> TestGetLibraryAsync()
{
var x = await _api.GetLibraryAsync();
return x;
}
//public async Task DownloadBookAsync(string asinToDownload)
//{
// // console example
// using var progressBar = new Dinah.Core.ConsoleLib.ProgressBar();
// var progress = new Progress<Dinah.Core.Net.Http.DownloadProgress>();
// progress.ProgressChanged += (_, e) => progressBar.Report(Math.Round((double)(100 * e.BytesReceived) / e.TotalFileSize.Value) / 100);
// logger.WriteLine("Download book");
// var finalFile = await _api.DownloadAaxWorkaroundAsync(asinToDownload, "downloadExample.xyz", progress);
// logger.WriteLine(" Done!");
// logger.WriteLine("final file: " + Path.GetFullPath(finalFile));
// // benefit of this small delay:
// // - if you try to delete a file too soon after it's created, the OS isn't done with the creation and you can get an unexpected error
// // - give progressBar's internal timer time to finish. if timer is disposed before the final message is processed, "100%" will never get a chance to be displayed
// await Task.Delay(100);
// File.Delete(finalFile);
//}
public async Task ImportLibraryAsync()
{
// json = api.GetLibrary
// json => DTOs
// indexer.update(DTOs)
}
}
}