Compare commits

..
2 Commits
Author SHA1 Message Date
Robert McRackan aa829df265 log accounts changes 2026-09-08 00:15:08 -04:00
Robert McRackan e84a0a121a "Import library" 2026-09-06 21:57:46 -04:00
7 changed files with 95 additions and 3 deletions

No files matched your search

@@ -97,6 +97,7 @@ public class AccountsSettings : IUpdatable
public void Add(Account account)
{
_add(account);
Serilog.Log.Logger.Information("Added Audible account {Account}", account.MaskedLogEntry);
update_no_validate();
}
@@ -165,6 +166,8 @@ public class AccountsSettings : IUpdatable
account.Updated -= update;
var result = _accounts_backing.Remove(account);
if (result)
Serilog.Log.Logger.Information("Removed Audible account {Account}", account.MaskedLogEntry);
update_no_validate();
return result;
}
@@ -22,6 +22,8 @@ public static class ContentLicenseDeniedUserMessage
Heavy use of the Audible Plus catalog in a short time can also produce "license denied" responses; community reports often involve on the order of dozens of titles — Audible does not publish a fixed limit. Waiting 24 to 48 hours before trying again is usually enough.
If the official Audible app can play this title, {DeviceRegistrationSettingsUi.RemoveSaveReAddAccountSteps}
If the problem continues after several days, open an issue on Libation's GitHub and include your logs.
""" + AppendSuggestion();
@@ -48,6 +50,8 @@ public static class ContentLicenseDeniedUserMessage
Try waiting 24 to 48 hours and liberate again. If it still fails after several days, open an issue on Libation's GitHub with logs.
If you should not have access to this title (for example it left Plus before you downloaded), confirm in the Audible app or website.
If the official Audible app can play this title, {DeviceRegistrationSettingsUi.RemoveSaveReAddAccountSteps}
""" + AppendSuggestion();
/// <summary>
@@ -12,10 +12,17 @@ public static class DeviceRegistrationSettingsUi
public static string SettingLabel { get; } = "Device registration (experimental)";
public static string ReLoginNote { get; }
= "Changing this does not convert existing accounts. Remove and re-add the account (or run login-external) to register again.";
= "Changing this does not convert existing accounts. Remove the account, save or close the Accounts dialog, then re-add the account (or run login-external) to register again.";
/// <summary>
/// Steps that actually persist a fresh device registration. Removing alone is not enough if the
/// Accounts dialog is still open with the removal uncommitted.
/// </summary>
public static string RemoveSaveReAddAccountSteps { get; }
= "Remove the account, save or close the Accounts dialog, then re-add the account.";
public static string ThrottlingWorkaround { get; }
= "If the official Audible app can play this title, try Settings: pick an experimental device registration, then remove and re-add the account. You can also import credentials from audible-cli.";
= "If the official Audible app can play this title, try Settings: pick an experimental device registration, then remove the account, save or close the Accounts dialog, and re-add the account. You can also import credentials from audible-cli.";
public static EnumDisplay<DeviceRegistrationKind> Display(DeviceRegistrationKind kind)
=> Options.FirstOrDefault(o => o.Value.Equals(kind)) ?? Options[0];
@@ -7,6 +7,9 @@ using AudibleUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.IO;
@@ -1161,5 +1164,64 @@ public class SerializedShape : AccountsTestBase
JObject.Parse(loaded.ToJson())["Accounts"]![0]!["MaskedLogEntry"].Should().BeNull();
}
}
[TestClass]
public class AccountAddRemoveLogging
{
[TestMethod]
public void Add_and_Delete_write_masked_account_to_the_log()
{
var sink = new CollectingSink();
var original = Serilog.Log.Logger;
Serilog.Log.Logger = new LoggerConfiguration().WriteTo.Sink(sink).CreateLogger();
try
{
var settings = new AccountsSettings();
var account = settings.Upsert("user@example.com", "us");
settings.Delete(account).Should().BeTrue();
var messages = sink.Events.Select(e => e.RenderMessage()).ToList();
Assert.AreEqual(1, messages.Count(m => m.Contains("Added Audible account", StringComparison.Ordinal)));
Assert.AreEqual(1, messages.Count(m => m.Contains("Removed Audible account", StringComparison.Ordinal)));
Assert.IsTrue(messages.All(m => m.Contains(account.MaskedLogEntry, StringComparison.Ordinal)));
Assert.IsFalse(messages.Any(m => m.Contains("user@example.com", StringComparison.Ordinal)));
}
finally
{
Serilog.Log.Logger = original;
}
}
[TestMethod]
public void Loading_accounts_from_json_does_not_log_an_add()
{
var sink = new CollectingSink();
var original = Serilog.Log.Logger;
Serilog.Log.Logger = new LoggerConfiguration().WriteTo.Sink(sink).CreateLogger();
try
{
var settings = new AccountsSettings();
settings.Add(new Account("user@example.com") { IdentityTokens = new Identity(Localization.Get("us")) });
var json = settings.ToJson();
sink.Events.Clear();
_ = AccountsSettings.FromJson(json);
Assert.AreEqual(0, sink.Events.Count);
}
finally
{
Serilog.Log.Logger = original;
}
}
private class CollectingSink : ILogEventSink
{
public List<LogEvent> Events { get; } = [];
public void Emit(LogEvent logEvent) => Events.Add(logEvent);
}
}
#pragma warning restore CS8981
@@ -23,6 +23,7 @@ public class ContentLicenseDeniedUserMessageTests
StringAssert.Contains(body, "not a Libation bug");
StringAssert.Contains(body, "experimental device registration");
StringAssert.Contains(body, "audible-cli");
AssertSuggestsRemoveSaveReAdd(body);
}
[TestMethod]
@@ -32,6 +33,7 @@ public class ContentLicenseDeniedUserMessageTests
StringAssert.Contains(body, "temporary interruption of service");
Assert.IsFalse(body.Contains("account is being throttled", StringComparison.Ordinal));
AssertSuggestsRemoveSaveReAdd(body);
}
[TestMethod]
@@ -41,5 +43,14 @@ public class ContentLicenseDeniedUserMessageTests
StringAssert.Contains(body, "Audible Plus catalog");
Assert.IsFalse(body.Contains("account is being throttled", StringComparison.Ordinal));
AssertSuggestsRemoveSaveReAdd(body);
}
private static void AssertSuggestsRemoveSaveReAdd(string body)
{
StringAssert.Contains(body, "remove the account", StringComparison.OrdinalIgnoreCase);
StringAssert.Contains(body, "save or close the Accounts dialog");
StringAssert.Contains(body, "re-add the account");
}
}
@@ -25,6 +25,11 @@ public class DeviceRegistrationSettingsUiTests
{
StringAssert.Contains(DeviceRegistrationSettingsUi.ThrottlingWorkaround, "experimental device registration");
StringAssert.Contains(DeviceRegistrationSettingsUi.ThrottlingWorkaround, "audible-cli");
StringAssert.Contains(DeviceRegistrationSettingsUi.ThrottlingWorkaround, "save or close the Accounts dialog");
StringAssert.Contains(DeviceRegistrationSettingsUi.ReLoginNote, "does not convert existing accounts");
StringAssert.Contains(DeviceRegistrationSettingsUi.ReLoginNote, "save or close the Accounts dialog");
StringAssert.Contains(DeviceRegistrationSettingsUi.RemoveSaveReAddAccountSteps, "Remove the account");
StringAssert.Contains(DeviceRegistrationSettingsUi.RemoveSaveReAddAccountSteps, "save or close the Accounts dialog");
StringAssert.Contains(DeviceRegistrationSettingsUi.RemoveSaveReAddAccountSteps, "re-add the account");
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ Registration data is stored with the account, so updating Libation or changing t
## Where to find it
- **Chardonnay:** Settings -> Important -> **Device registration (experimental)**
- **Chardonnay:** Settings -> Import library -> **Device registration (experimental)**
- **Classic:** Settings -> Import library -> **Device registration (experimental)**
- **CLI / Docker:** `DeviceRegistrationKind` in `Settings.json`, or `--device-registration` on `login-external`. See [Command Line Interface](/docs/advanced/command-line-interface#log-in-with-an-external-browser-login-external).