diff --git a/Source/LibationCli/Options/ListAccountsOptions.cs b/Source/LibationCli/Options/ListAccountsOptions.cs new file mode 100644 index 00000000..742cd7b8 --- /dev/null +++ b/Source/LibationCli/Options/ListAccountsOptions.cs @@ -0,0 +1,56 @@ +using AudibleUtilities; +using CommandLine; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace LibationCli; + +[Verb("list-accounts", HelpText = "List configured Audible accounts, locale, scan flag, and whether stored credentials are valid.")] +internal class ListAccountsOptions : OptionsBase +{ + [Option('b', "bare", HelpText = "Print tab-separated values without table borders (account id, name, locale, scan library, authenticated).")] + public bool Bare { get; set; } + + protected override Task ProcessAsync() + { + using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); + var accounts = persister.AccountsSettings.GetAll().ToArray(); + + if (accounts.Length == 0) + { + Console.WriteLine("No accounts configured."); + return Task.CompletedTask; + } + + var rows = accounts + .Select(a => new AccountListRow( + a.AccountId, + a.AccountName ?? "", + a.Locale?.Name ?? "", + a.LibraryScan ? "yes" : "no", + a.IdentityTokens?.IsValid == true ? "yes" : "no")) + .ToArray(); + + if (Bare) + { + foreach (var r in rows) + Console.WriteLine($"{r.AccountId}\t{r.AccountName}\t{r.Locale}\t{r.LibraryScan}\t{r.Authenticated}"); + } + else + { + Console.Out.DrawTable( + rows, + new TextTableOptions(), + new ColumnDef("Account ID", r => r.AccountId), + new ColumnDef("Name", r => r.AccountName), + new ColumnDef("Locale", r => r.Locale), + new ColumnDef("Scan library", r => r.LibraryScan), + new ColumnDef("Authenticated", r => r.Authenticated)); + } + + return Task.CompletedTask; + } + + private sealed record AccountListRow(string AccountId, string AccountName, string Locale, string LibraryScan, string Authenticated); +} diff --git a/docs/advanced/command-line-interface.md b/docs/advanced/command-line-interface.md index 6c58c6b1..91fcc423 100644 --- a/docs/advanced/command-line-interface.md +++ b/docs/advanced/command-line-interface.md @@ -2,7 +2,7 @@ Libationcli.exe allows limited access to Libation's functionalities as a CLI. -Warnings about relying solely on on the CLI: +Warnings about relying solely on the CLI: - CLI will not perform any upgrades. - It will show that there is an upgrade, but that will likely scroll by too fast to notice. @@ -23,16 +23,28 @@ Redirecting also avoids progress-bar control characters in log files. ## Help +LibationCli uses a **verb-first** layout: the first argument is always a command name (for example `scan`, `liberate`). + +**Global help** — list every verb and its short description (use this when you are not sure which verb to run): + ```console libationcli --help +libationcli -h ``` -## Verb-Specific Help +On Windows, `/?`, `/h`, and `/help` are also accepted when they are the only argument. + +**Verb-specific help** — options for a single command: ```console libationcli scan --help +libationcli scan -h ``` +The `help` verb is equivalent for many cases: `libationcli help scan`. + +Help-only invocations exit with status code **0** (success), so scripts can treat them as non-errors. + ## Libation files location All verbs use the same Libation data directory as the GUI (where `AccountsSettings.json` and `Settings.json` live). To point the CLI elsewhere: @@ -79,6 +91,19 @@ If the account row already has valid saved tokens, the CLI reports that no brows Use `libationcli login-external --help` for the exact options on your build. +## List configured accounts (`list-accounts`) + +Prints each row from `AccountsSettings.json`: Audible login id, optional nickname, marketplace (`us`, `uk`, …), whether **Scan library** is enabled for that account, and whether stored identity tokens are currently **valid** (the same check `login-external` uses before starting a browser flow). Use this on headless setups to see which accounts still need `login-external` or `import-account`. + +```console +libationcli list-accounts +libationcli list-accounts --bare +``` + +`--bare` (`-b`) prints tab-separated values with no table: account id, name, locale, scan library (`yes` / `no`), authenticated (`yes` / `no`), for scripts and `cut` / `awk`. + +If no accounts exist yet, the CLI prints `No accounts configured.` and exits successfully. + ## Scan All Libraries ```console diff --git a/docs/installation/docker.md b/docs/installation/docker.md index ff1a23bc..9f72161d 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -23,6 +23,8 @@ If you run Libation on a server or in Docker and do not want to copy `AccountsSe - `login-external` — Browser-based sign-in: the CLI prints an Audible login URL; you open it in a normal browser, sign in, then paste the final URL from the address bar back into the terminal. Example: `LibationCli login-external --account you@example.com --locale us` If standard input is not a TTY (for example in some automation), pass the final URL with `--response-url "https://..."` instead of pasting interactively. +- `list-accounts` — List configured accounts and whether each has valid stored credentials (and scan-on/off). Example: + `LibationCli list-accounts` or `LibationCli list-accounts --bare` for tab-separated output. For full syntax, overrides, and the `--libationFiles` option (or the `LIBATION_FILES_DIR` environment variable) when your Libation data directory is not the default, see [Command Line Interface](/docs/advanced/command-line-interface).