From 82135214041fa6ec9fbf2f4de5149a52dba0a887 Mon Sep 17 00:00:00 2001 From: rmcrackan Date: Thu, 9 Apr 2026 09:57:41 -0400 Subject: [PATCH 1/5] copilot fix to vulnerable nuget pkg --- Source/HangoverAvalonia/HangoverAvalonia.csproj | 1 + Source/LibationAvalonia/LibationAvalonia.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj index ea9c34f1..4be1ca78 100644 --- a/Source/HangoverAvalonia/HangoverAvalonia.csproj +++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj @@ -75,6 +75,7 @@ + diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj index be03216e..f5f4173e 100644 --- a/Source/LibationAvalonia/LibationAvalonia.csproj +++ b/Source/LibationAvalonia/LibationAvalonia.csproj @@ -80,6 +80,7 @@ + From 26946e8a87b970b2e186e2822a5341627362f4f4 Mon Sep 17 00:00:00 2001 From: rmcrackan Date: Thu, 9 Apr 2026 10:57:41 -0400 Subject: [PATCH 2/5] Log initial db state, esp to capture books in trash --- Source/AppScaffolding/LibationScaffolding.cs | 1 + Source/ApplicationServices/DbContexts.cs | 71 +++++++++++++++++++ Source/DataLayer/QueryObjects/BookQueries.cs | 4 ++ .../QueryObjects/LibraryBookQueries.cs | 7 ++ 4 files changed, 83 insertions(+) diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs index 5ab979a8..bb51d155 100644 --- a/Source/AppScaffolding/LibationScaffolding.cs +++ b/Source/AppScaffolding/LibationScaffolding.cs @@ -225,6 +225,7 @@ public static class LibationScaffolding private static void configureLogging(Configuration config) { config.ConfigureLogging(); + DbContexts.TryEmitPendingInitialDatabaseStatistics(); // capture most Console.WriteLine() and write to serilog. See below tests for details. // Some dependencies print helpful info via Console.WriteLine. We'd like to log it. diff --git a/Source/ApplicationServices/DbContexts.cs b/Source/ApplicationServices/DbContexts.cs index 03f3538b..f4a468e0 100644 --- a/Source/ApplicationServices/DbContexts.cs +++ b/Source/ApplicationServices/DbContexts.cs @@ -1,6 +1,9 @@ using DataLayer; using LibationFileManager; +using Serilog; +using System; using System.Collections.Generic; +using System.Threading; namespace ApplicationServices; @@ -8,6 +11,24 @@ public static class DbContexts { private static bool _sqliteDbValidated; + private static readonly object _initialDatabaseStatisticsCaptureLock = new(); + + /// + /// True after initial DB statistics were read and either written to Serilog or stored for . + /// False if capture has not run yet or the last attempt threw (a later may retry). + /// + private static bool _initialDatabaseStatisticsCaptured; + + /// Shape of the initial DB statistics log event; edit here only when changing what is logged. + private sealed class InitialDatabaseStatistics + { + public required int LibraryBooksNotInTrash { get; init; } + public required int LibraryBooksInTrash { get; init; } + public required int BookRecords { get; init; } + } + + private static InitialDatabaseStatistics? _pendingInitialDbStats; + /// Use for fully functional context, incl. SaveChanges(). For query-only, use the other method public static LibationContext GetContext() { @@ -25,9 +46,59 @@ public static class DbContexts _sqliteDbValidated = true; } + TryCaptureInitialDatabaseStatistics(context); + return context; } + private static void TryCaptureInitialDatabaseStatistics(LibationContext context) + { + lock (_initialDatabaseStatisticsCaptureLock) + { + if (_initialDatabaseStatisticsCaptured) + return; + + try + { + var (notInTrash, inTrash) = context.GetLibraryBookCountsByTrashFlag(); + var bookRecords = context.GetBookCount(); + + var stats = new InitialDatabaseStatistics + { + LibraryBooksNotInTrash = notInTrash, + LibraryBooksInTrash = inTrash, + BookRecords = bookRecords, + }; + + if (Configuration.Instance.SerilogInitialized) + LogInitialDatabaseStatistics(stats); + else + _pendingInitialDbStats = stats; + + _initialDatabaseStatisticsCaptured = true; + } + catch (Exception ex) + { + if (Configuration.Instance.SerilogInitialized) + Log.Warning(ex, "Could not capture initial database statistics"); + } + } + } + + /// + /// Writes initial DB statistics that were captured before Serilog was configured (e.g. WinForms early library load). + /// Call once after . + /// + public static void TryEmitPendingInitialDatabaseStatistics() + { + var pending = Interlocked.Exchange(ref _pendingInitialDbStats, null); + if (pending is not null) + LogInitialDatabaseStatistics(pending); + } + + private static void LogInitialDatabaseStatistics(InitialDatabaseStatistics stats) => + Log.Logger.Information("Initial database statistics. {@DbStats}", stats); + /// Use for full library querying. No lazy loading public static List GetLibrary_Flat_NoTracking(bool includeParents = false) { diff --git a/Source/DataLayer/QueryObjects/BookQueries.cs b/Source/DataLayer/QueryObjects/BookQueries.cs index 1353fc9e..6a4f1084 100644 --- a/Source/DataLayer/QueryObjects/BookQueries.cs +++ b/Source/DataLayer/QueryObjects/BookQueries.cs @@ -16,6 +16,10 @@ public static class BookQueries .AsNoTrackingWithIdentityResolution() .GetBook(productId); + /// Total rows in (no related entities loaded). + public static int GetBookCount(this LibationContext context) + => context.Books.AsNoTracking().Count(); + public static Book? GetBook(this IQueryable books, string productId) => books .GetBooks() diff --git a/Source/DataLayer/QueryObjects/LibraryBookQueries.cs b/Source/DataLayer/QueryObjects/LibraryBookQueries.cs index e70be80f..93d29199 100644 --- a/Source/DataLayer/QueryObjects/LibraryBookQueries.cs +++ b/Source/DataLayer/QueryObjects/LibraryBookQueries.cs @@ -62,6 +62,13 @@ public static class LibraryBookQueries .Where(lb => lb.IsDeleted || lb.Book.ContentType == ContentType.Parent) .getLibrary() .ToList(); + + /// Counts rows by (no related entities loaded). + public (int NotInTrash, int InTrash) GetLibraryBookCountsByTrashFlag() + { + var q = context.LibraryBooks.AsNoTracking(); + return (q.Count(lb => !lb.IsDeleted), q.Count(lb => lb.IsDeleted)); + } } extension(IQueryable library) From 5a0d62687c572411409972d200b854e090c5089c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:13:05 +0000 Subject: [PATCH 3/5] Bump actions/github-script from 8 to 9 Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/exempt-creators-backfill.yml | 2 +- .github/workflows/exempt-creators.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/exempt-creators-backfill.yml b/.github/workflows/exempt-creators-backfill.yml index 52f08a65..b7519853 100644 --- a/.github/workflows/exempt-creators-backfill.yml +++ b/.github/workflows/exempt-creators-backfill.yml @@ -15,7 +15,7 @@ jobs: backfill: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 with: script: | const exemptLabel = 'exempt'; diff --git a/.github/workflows/exempt-creators.yml b/.github/workflows/exempt-creators.yml index f75a92d9..71154ed0 100644 --- a/.github/workflows/exempt-creators.yml +++ b/.github/workflows/exempt-creators.yml @@ -25,7 +25,7 @@ jobs: contains(fromJSON('["rmcrackan","Mbucari"]'), github.event.issue.user.login)) || (github.event_name == 'pull_request' && contains(fromJSON('["rmcrackan","Mbucari"]'), github.event.pull_request.user.login)) - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const number = context.issue?.number || context.payload.pull_request?.number; From 197d645e100ee666c4cfcaf8b01da693f7e409e6 Mon Sep 17 00:00:00 2001 From: rmcrackan Date: Mon, 13 Apr 2026 08:51:07 -0400 Subject: [PATCH 4/5] #1729 minor docker tweak --- Docker/liberate.sh | 2 +- docs/installation/docker.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Docker/liberate.sh b/Docker/liberate.sh index 82947829..525e51f7 100755 --- a/Docker/liberate.sh +++ b/Docker/liberate.sh @@ -108,7 +108,7 @@ setup_db() { error "database not found and creation is disabled" exit 1 fi - ln -s "${FILE}" "${LIBATION_CONFIG_INTERNAL}/LibationContext.db" + ln -sf "${FILE}" "${LIBATION_CONFIG_INTERNAL}/LibationContext.db" } run() { diff --git a/docs/installation/docker.md b/docs/installation/docker.md index 1222e06c..6dabadf5 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -71,6 +71,10 @@ sudo docker run -d \ If the user it's running as is correct, and it still cannot write, be sure to check whether the files and/or folders might be owned by the wrong user. You can use the `chown` command to change the owner of the file to the correct user and group number, for example: `chown -R 1001:1001 /mnt/audiobooks /mnt/libation-config` +## Troubleshooting + +- **Library scan appears to hang in Docker:** Try setting `ImportEpisodes` to `false` in `Settings.json` on your config volume and run again. That turns off the extra episode/podcast catalog requests during import and helps narrow down whether the stall is in that path versus auth or the network. + ## Advanced Database Options The docker image supports an optional database mount location defined by `LIBATION_DB_DIR`. This allows the database to be mounted as read/write, while allowing the rest of the configuration files to be mounted as read only. This is specifically useful if running in Kubernetes where you can use Configmaps and Secrets to define the configuration. If the `LIBATION_DB_DIR` is mounted, it will be used, otherwise it will look for the database in `LIBATION_CONFIG_DIR`. If it does not find the database in the expected location, it will attempt to make an empty database there. From 550a99ac90b6f3e3efe5b98babb372aab2968c28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 15:30:12 +0000 Subject: [PATCH 5/5] Bump softprops/action-gh-release from 2 to 3 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f48c8fd3..8a9ef75b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: - name: Release id: release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: name: Libation ${{ needs.prerelease.outputs.version }} body: ""