using System; using System.Collections.Generic; using System.IO; using System.Linq; 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 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 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 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 DownloadBookAsync(string asinToDownload) //{ // // console example // using var progressBar = new Dinah.Core.ConsoleLib.ProgressBar(); // var progress = new Progress(); // 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 var jObjects = await GetLibraryItemsAsync(); // json => DTOs // indexer.update(DTOs) } private async Task> GetLibraryItemsAsync() { var allJsonResults = new List(); var pageNum = 1; while (true) { var page = await _api.GetLibraryAsync(new LibraryOptions { NumberOfResultPerPage = 1000, PageNumber = pageNum }); var debugStr = page.ToString(); var items = page["items"].Cast(); allJsonResults.AddRange(items); if (!items.Any()) break; pageNum++; } return allJsonResults; } } }