From fde78f41679b0e3489b83d10b835aa0b4e245223 Mon Sep 17 00:00:00 2001 From: MBucari Date: Thu, 20 Nov 2025 15:09:12 -0700 Subject: [PATCH 1/5] Update to .NET 10 - Update all project runtime targets - Update all dependencies - NOTE: Using Npgsql.EntityFrameworkCore.PostgreSQL RTM build from MyGet - Delete unused pubxml files (they were made redundant by recent workflow changes) - Replace Libation.sln with Libation.slnx --- .github/workflows/build.yml | 2 +- Dockerfile | 9 +- Source/AaxDecrypter/AaxDecrypter.csproj | 4 +- Source/AppScaffolding/AppScaffolding.csproj | 2 +- .../ApplicationServices.csproj | 2 +- .../AudibleUtilities/AudibleUtilities.csproj | 6 +- .../DataLayer.Postgres.csproj | 12 +- .../DataLayer.Sqlite/DataLayer.Sqlite.csproj | 12 +- Source/DataLayer/DataLayer.csproj | 16 +- .../DtoImporterService.csproj | 2 +- Source/FileLiberator/FileLiberator.csproj | 2 +- Source/FileManager/FileManager.csproj | 4 +- .../HangoverAvalonia/HangoverAvalonia.csproj | 8 +- .../PublishProfiles/LinuxProfile.pubxml | 17 - .../PublishProfiles/MacOSProfile.pubxml | 17 - .../PublishProfiles/WindowsProfile.pubxml | 17 - Source/HangoverBase/HangoverBase.csproj | 2 +- .../HangoverWinForms/HangoverWinForms.csproj | 2 +- .../PublishProfiles/WindowsProfile.pubxml | 17 - Source/Libation.sln | 294 ------------------ Source/Libation.slnx | 72 +++++ .../LibationAvalonia/LibationAvalonia.csproj | 12 +- .../PublishProfiles/LinuxProfile.pubxml | 17 - .../PublishProfiles/MacOSProfile.pubxml | 17 - .../PublishProfiles/WindowsProfile.pubxml | 17 - Source/LibationCli/LibationCli.csproj | 2 +- .../PublishProfiles/LinuxProfile.pubxml | 17 - .../PublishProfiles/MacOSProfile.pubxml | 17 - .../PublishProfiles/WindowsProfile.pubxml | 17 - .../LibationFileManager.csproj | 4 +- .../LibationSearchEngine.csproj | 4 +- Source/LibationUiBase/LibationUiBase.csproj | 2 +- .../Dialogs/SearchSyntaxDialog.cs | 4 +- .../Dialogs/TrashBinDialog.cs | 2 +- .../LibationWinForms/LibationWinForms.csproj | 4 +- .../PublishProfiles/WindowsProfile.pubxml | 16 - .../LinuxConfigApp/LinuxConfigApp.csproj | 2 +- .../PublishProfiles/LinuxProfile.pubxml | 17 - .../MacOSConfigApp/MacOSConfigApp.csproj | 2 +- .../PublishProfiles/MacOSProfile.pubxml | 17 - .../PublishProfiles/WindowsProfile.pubxml | 16 - .../WindowsConfigApp/WindowsConfigApp.csproj | 2 +- .../CrossPlatformClientExe.csproj | 4 +- .../LinuxConfigApp/LinuxConfigApp.csproj | 2 +- .../WindowsConfigApp/WindowsConfigApp.csproj | 2 +- .../AssertionHelper/AssertionHelper.csproj | 6 +- .../AudibleUtilities.Tests.csproj | 4 +- .../FileLiberator.Tests.csproj | 4 +- .../FileManager.Tests.csproj | 4 +- .../LibationFileManager.Tests.csproj | 4 +- .../LibationSearchEngine.Tests.csproj | 4 +- .../LibationUiBase.Tests.csproj | 6 +- Source/nuget.config | 10 + 53 files changed, 162 insertions(+), 615 deletions(-) delete mode 100644 Source/HangoverAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml delete mode 100644 Source/HangoverAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml delete mode 100644 Source/HangoverAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml delete mode 100644 Source/HangoverWinForms/Properties/PublishProfiles/WindowsProfile.pubxml delete mode 100644 Source/Libation.sln create mode 100644 Source/Libation.slnx delete mode 100644 Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml delete mode 100644 Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml delete mode 100644 Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml delete mode 100644 Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml delete mode 100644 Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml delete mode 100644 Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml delete mode 100644 Source/LibationWinForms/Properties/PublishProfiles/WindowsProfile.pubxml delete mode 100644 Source/LoadByOS/LinuxConfigApp/Properties/PublishProfiles/LinuxProfile.pubxml delete mode 100644 Source/LoadByOS/MacOSConfigApp/Properties/PublishProfiles/MacOSProfile.pubxml delete mode 100644 Source/LoadByOS/WindowsConfigApp/Properties/PublishProfiles/WindowsProfile.pubxml create mode 100644 Source/nuget.config diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe4a90cc..42637a44 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ on: required: true dotnet-version: type: string - default: "9.x" + default: "10.x" description: ".NET version to target" run-unit-tests: type: boolean diff --git a/Dockerfile b/Dockerfile index c0d5f4f8..17019728 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,19 @@ # Dockerfile -FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/dotnet/sdk:10.0 AS build ARG TARGETARCH COPY Source /Source RUN dotnet publish \ /Source/LibationCli/LibationCli.csproj \ + --os linux \ --arch ${TARGETARCH} \ --configuration Release \ --output /Source/bin/Publish/Linux-chardonnay \ - -p:PublishProfile=/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml + -p:PublishProtocol=FileSystem \ + -p:PublishReadyToRun=true \ + -p:SelfContained=true -FROM mcr.microsoft.com/dotnet/runtime:9.0 +FROM mcr.microsoft.com/dotnet/runtime:10.0 ARG USER_UID=1001 ARG USER_GID=1001 diff --git a/Source/AaxDecrypter/AaxDecrypter.csproj b/Source/AaxDecrypter/AaxDecrypter.csproj index 8eee924c..ef6c4c50 100644 --- a/Source/AaxDecrypter/AaxDecrypter.csproj +++ b/Source/AaxDecrypter/AaxDecrypter.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 @@ -13,7 +13,7 @@ - + diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index d442e9ee..786ea327 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 12.7.1.1 diff --git a/Source/ApplicationServices/ApplicationServices.csproj b/Source/ApplicationServices/ApplicationServices.csproj index 2105a0b0..d868c91c 100644 --- a/Source/ApplicationServices/ApplicationServices.csproj +++ b/Source/ApplicationServices/ApplicationServices.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 4b62e37d..248de155 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -1,12 +1,12 @@  - net9.0 + net10.0 - - + + diff --git a/Source/DataLayer.Postgres/DataLayer.Postgres.csproj b/Source/DataLayer.Postgres/DataLayer.Postgres.csproj index 4ee33922..33744d7d 100644 --- a/Source/DataLayer.Postgres/DataLayer.Postgres.csproj +++ b/Source/DataLayer.Postgres/DataLayer.Postgres.csproj @@ -1,23 +1,19 @@  - net9.0 + net10.0 true Library - - - - + all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; analyzers; buildtransitive - - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/DataLayer.Sqlite/DataLayer.Sqlite.csproj b/Source/DataLayer.Sqlite/DataLayer.Sqlite.csproj index e1128635..d3f78564 100644 --- a/Source/DataLayer.Sqlite/DataLayer.Sqlite.csproj +++ b/Source/DataLayer.Sqlite/DataLayer.Sqlite.csproj @@ -1,23 +1,19 @@  - net9.0 + net10.0 true Library - - - - + all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; analyzers; buildtransitive - - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/DataLayer/DataLayer.csproj b/Source/DataLayer/DataLayer.csproj index e2c3699a..1497cf16 100644 --- a/Source/DataLayer/DataLayer.csproj +++ b/Source/DataLayer/DataLayer.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 @@ -10,15 +10,15 @@ - - - - - + + + + + all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/DtoImporterService/DtoImporterService.csproj b/Source/DtoImporterService/DtoImporterService.csproj index 693c57e7..4c4a90e1 100644 --- a/Source/DtoImporterService/DtoImporterService.csproj +++ b/Source/DtoImporterService/DtoImporterService.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 diff --git a/Source/FileLiberator/FileLiberator.csproj b/Source/FileLiberator/FileLiberator.csproj index fc6a13e8..529fdc38 100644 --- a/Source/FileLiberator/FileLiberator.csproj +++ b/Source/FileLiberator/FileLiberator.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 diff --git a/Source/FileManager/FileManager.csproj b/Source/FileManager/FileManager.csproj index 03d96351..178ffbd1 100644 --- a/Source/FileManager/FileManager.csproj +++ b/Source/FileManager/FileManager.csproj @@ -1,11 +1,11 @@  - net9.0 + net10.0 - + diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj index fdff7595..e89b5e26 100644 --- a/Source/HangoverAvalonia/HangoverAvalonia.csproj +++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj @@ -1,7 +1,7 @@  WinExe - net9.0 + net10.0 win-x64 copyused @@ -70,11 +70,11 @@ - + - + - + diff --git a/Source/HangoverAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml b/Source/HangoverAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml deleted file mode 100644 index 5e7ea5a7..00000000 --- a/Source/HangoverAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\Linux-chardonnay - FileSystem - net9.0 - linux-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/HangoverAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml b/Source/HangoverAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml deleted file mode 100644 index 51c90474..00000000 --- a/Source/HangoverAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\MacOS-chardonnay - FileSystem - net9.0 - osx-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/HangoverAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/HangoverAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml deleted file mode 100644 index 44133444..00000000 --- a/Source/HangoverAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\Windows-chardonnay - FileSystem - net9.0 - win-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/HangoverBase/HangoverBase.csproj b/Source/HangoverBase/HangoverBase.csproj index c2613767..babdaabd 100644 --- a/Source/HangoverBase/HangoverBase.csproj +++ b/Source/HangoverBase/HangoverBase.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable diff --git a/Source/HangoverWinForms/HangoverWinForms.csproj b/Source/HangoverWinForms/HangoverWinForms.csproj index 56c8eb24..fa3fd523 100644 --- a/Source/HangoverWinForms/HangoverWinForms.csproj +++ b/Source/HangoverWinForms/HangoverWinForms.csproj @@ -2,7 +2,7 @@ WinExe - net9.0-windows7.0 + net10.0-windows7.0 true Hangover true diff --git a/Source/HangoverWinForms/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/HangoverWinForms/Properties/PublishProfiles/WindowsProfile.pubxml deleted file mode 100644 index 8b58679d..00000000 --- a/Source/HangoverWinForms/Properties/PublishProfiles/WindowsProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\classic - FileSystem - net9.0-windows - win-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/Libation.sln b/Source/Libation.sln deleted file mode 100644 index 95a4f7af..00000000 --- a/Source/Libation.sln +++ /dev/null @@ -1,294 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{03C8835F-936C-4AF7-87AE-FF92BDBE8B9B}" - ProjectSection(SolutionItems) = preProject - add-migrations.ps1 = add-migrations.ps1 - REFERENCE.txt = REFERENCE.txt - Upgrading dotnet version.txt = Upgrading dotnet version.txt - _ARCHITECTURE NOTES.txt = _ARCHITECTURE NOTES.txt - _AvaloniaUI Primer.txt = _AvaloniaUI Primer.txt - _DB_NOTES.txt = _DB_NOTES.txt - __README - COLLABORATORS.txt = __README - COLLABORATORS.txt - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5 Domain Utilities (db aware)", "5 Domain Utilities (db aware)", "{41CDCC73-9B81-49DD-9570-C54406E852AF}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "6 Application", "6 Application", "{8679CAC8-9164-4007-BDD2-F004810EDA14}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 Core Libraries", "1 Core Libraries", "{43E3ACB3-E0BC-4370-8DBB-E3720C8C8FD1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4 Domain (db)", "4 Domain (db)", "{751093DD-5DBA-463E-ADBE-E05FAFB6983E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 Utilities (domain ignorant)", "2 Utilities (domain ignorant)", "{7FBBB086-0807-4998-85BF-6D1A49C8AD05}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AaxDecrypter", "AaxDecrypter\AaxDecrypter.csproj", "{8BD8E012-F44F-4EE2-A234-D66C14D5FE4B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationFileManager", "LibationFileManager\LibationFileManager.csproj", "{1AE65B61-9C05-4C80-ABFF-48F16E22FDF1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataLayer", "DataLayer\DataLayer.csproj", "{59A10DF3-63EC-43F1-A3BF-4000CFA118D2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileLiberator", "FileLiberator\FileLiberator.csproj", "{393B5B27-D15C-4F77-9457-FA14BA8F3C73}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudibleUtilities", "AudibleUtilities\AudibleUtilities.csproj", "{06882742-27A6-4347-97D9-56162CEC9C11}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3 Domain Internal Utilities (db ignorant)", "3 Domain Internal Utilities (db ignorant)", "{F0CBB7A7-D3FB-41FF-8F47-CF3F6A592249}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationSearchEngine", "LibationSearchEngine\LibationSearchEngine.csproj", "{2E1F5DB4-40CC-4804-A893-5DCE0193E598}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationWinForms", "LibationWinForms\LibationWinForms.csproj", "{635F00E1-AAD1-45F7-BEB7-D909AD33B9F6}" - ProjectSection(ProjectDependencies) = postProject - {40C67036-C1A7-4FDF-AA83-8EC902E257F3} = {40C67036-C1A7-4FDF-AA83-8EC902E257F3} - {428163C3-D558-4914-B570-A92069521877} = {428163C3-D558-4914-B570-A92069521877} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DtoImporterService", "DtoImporterService\DtoImporterService.csproj", "{401865F5-1942-4713-B230-04544C0A97B0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationServices", "ApplicationServices\ApplicationServices.csproj", "{B95650EA-25F0-449E-BA5D-99126BC5D730}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Tests", "_Tests", "{67E66E82-5532-4440-AFB3-9FB1DF9DEF53}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationSearchEngine.Tests", "_Tests\LibationSearchEngine.Tests\LibationSearchEngine.Tests.csproj", "{C5B21768-C7C9-4FCB-AC1E-187B223D5A98}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationCli", "LibationCli\LibationCli.csproj", "{428163C3-D558-4914-B570-A92069521877}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppScaffolding", "AppScaffolding\AppScaffolding.csproj", "{595E7C4D-506D-486D-98B7-5FDDF398D033}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileManager", "FileManager\FileManager.csproj", "{E86014F9-E4B3-4CD4-A210-2B3DB571DD86}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudibleUtilities.Tests", "_Tests\AudibleUtilities.Tests\AudibleUtilities.Tests.csproj", "{788294BE-0D8E-40D4-9CEE-67896FBB52CE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileLiberator.Tests", "_Tests\FileLiberator.Tests\FileLiberator.Tests.csproj", "{5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileManager.Tests", "_Tests\FileManager.Tests\FileManager.Tests.csproj", "{F2E04270-4551-41C4-99FF-E7125BED708C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationFileManager.Tests", "_Tests\LibationFileManager.Tests\LibationFileManager.Tests.csproj", "{EB781571-8548-477E-82AD-FB9FAB548D2F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HangoverWinForms", "HangoverWinForms\HangoverWinForms.csproj", "{40C67036-C1A7-4FDF-AA83-8EC902E257F3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationAvalonia", "LibationAvalonia\LibationAvalonia.csproj", "{F612D06F-3134-4B9B-95CD-EB3FC798AE60}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HangoverAvalonia", "HangoverAvalonia\HangoverAvalonia.csproj", "{8A7B01D3-9830-44FD-91A1-D8D010996BEB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HangoverBase", "HangoverBase\HangoverBase.csproj", "{5C7005BA-7D83-4E99-8073-D970943A7D61}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Demos", "_Demos", "{185AC9FF-381E-4AA1-B649-9771F4917214}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LoadByOS", "LoadByOS", "{59DF46F3-ECD0-43CA-AD12-3FEE8FCF9E4F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CrossPlatformClientExe", "_Demos\LoadByOS\CrossPlatformClientExe\CrossPlatformClientExe.csproj", "{CC275937-DFE4-4383-B1BF-1D5D42B70C98}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinuxConfigApp", "_Demos\LoadByOS\LinuxConfigApp\LinuxConfigApp.csproj", "{47325742-5B38-48E7-95FB-CD94E6E07332}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsConfigApp", "_Demos\LoadByOS\WindowsConfigApp\WindowsConfigApp.csproj", "{0520760A-9CFB-48A8-BCE4-6E951AFD6BE9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LoadByOS", "LoadByOS", "{9B906374-1142-4D69-86FF-B384806CA5FE}" - ProjectSection(SolutionItems) = preProject - LoadByOS\README.txt = LoadByOS\README.txt - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinuxConfigApp", "LoadByOS\LinuxConfigApp\LinuxConfigApp.csproj", "{357DF797-4EC2-4DBD-A4BD-D045277F2666}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MacOSConfigApp", "LoadByOS\MacOSConfigApp\MacOSConfigApp.csproj", "{ECED4E13-B676-4277-8A8F-C8B2507B7D8C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsConfigApp", "LoadByOS\WindowsConfigApp\WindowsConfigApp.csproj", "{5F65A509-26E3-4B02-B403-EEB6F0EF391F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationUiBase", "LibationUiBase\LibationUiBase.csproj", "{E90C4651-AF11-41B4-A839-10082D0391F9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hangover", "Hangover", "{FDDABAFE-35AD-42FC-AC95-0B1FE0DF0DDE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libation UI", "Libation UI", "{53758A35-1C7E-4702-9B96-433ABA457B37}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libation CLI", "Libation CLI", "{47E27674-595D-4F7A-8CFB-127E768E1D1E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssertionHelper", "_Tests\AssertionHelper\AssertionHelper.csproj", "{CFE7A0E5-37FE-40BE-A70B-41B5104181C4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataLayer.Postgres", "DataLayer.Postgres\DataLayer.Postgres.csproj", "{0E480D2D-C7C1-A6FE-8C90-8A6F0DBCEAC2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataLayer.Sqlite", "DataLayer.Sqlite\DataLayer.Sqlite.csproj", "{1E689E85-279E-39D4-7D97-3E993FB6D95B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibationUiBase.Tests", "_Tests\LibationUiBase.Tests\LibationUiBase.Tests.csproj", "{6F9DB713-2879-4B14-9F9E-3B13C9B7F35C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8BD8E012-F44F-4EE2-A234-D66C14D5FE4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BD8E012-F44F-4EE2-A234-D66C14D5FE4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BD8E012-F44F-4EE2-A234-D66C14D5FE4B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BD8E012-F44F-4EE2-A234-D66C14D5FE4B}.Release|Any CPU.Build.0 = Release|Any CPU - {1AE65B61-9C05-4C80-ABFF-48F16E22FDF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1AE65B61-9C05-4C80-ABFF-48F16E22FDF1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1AE65B61-9C05-4C80-ABFF-48F16E22FDF1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1AE65B61-9C05-4C80-ABFF-48F16E22FDF1}.Release|Any CPU.Build.0 = Release|Any CPU - {59A10DF3-63EC-43F1-A3BF-4000CFA118D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59A10DF3-63EC-43F1-A3BF-4000CFA118D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59A10DF3-63EC-43F1-A3BF-4000CFA118D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59A10DF3-63EC-43F1-A3BF-4000CFA118D2}.Release|Any CPU.Build.0 = Release|Any CPU - {393B5B27-D15C-4F77-9457-FA14BA8F3C73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {393B5B27-D15C-4F77-9457-FA14BA8F3C73}.Debug|Any CPU.Build.0 = Debug|Any CPU - {393B5B27-D15C-4F77-9457-FA14BA8F3C73}.Release|Any CPU.ActiveCfg = Release|Any CPU - {393B5B27-D15C-4F77-9457-FA14BA8F3C73}.Release|Any CPU.Build.0 = Release|Any CPU - {06882742-27A6-4347-97D9-56162CEC9C11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {06882742-27A6-4347-97D9-56162CEC9C11}.Debug|Any CPU.Build.0 = Debug|Any CPU - {06882742-27A6-4347-97D9-56162CEC9C11}.Release|Any CPU.ActiveCfg = Release|Any CPU - {06882742-27A6-4347-97D9-56162CEC9C11}.Release|Any CPU.Build.0 = Release|Any CPU - {2E1F5DB4-40CC-4804-A893-5DCE0193E598}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E1F5DB4-40CC-4804-A893-5DCE0193E598}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E1F5DB4-40CC-4804-A893-5DCE0193E598}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E1F5DB4-40CC-4804-A893-5DCE0193E598}.Release|Any CPU.Build.0 = Release|Any CPU - {635F00E1-AAD1-45F7-BEB7-D909AD33B9F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {635F00E1-AAD1-45F7-BEB7-D909AD33B9F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {635F00E1-AAD1-45F7-BEB7-D909AD33B9F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {635F00E1-AAD1-45F7-BEB7-D909AD33B9F6}.Release|Any CPU.Build.0 = Release|Any CPU - {401865F5-1942-4713-B230-04544C0A97B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {401865F5-1942-4713-B230-04544C0A97B0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {401865F5-1942-4713-B230-04544C0A97B0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {401865F5-1942-4713-B230-04544C0A97B0}.Release|Any CPU.Build.0 = Release|Any CPU - {B95650EA-25F0-449E-BA5D-99126BC5D730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B95650EA-25F0-449E-BA5D-99126BC5D730}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B95650EA-25F0-449E-BA5D-99126BC5D730}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B95650EA-25F0-449E-BA5D-99126BC5D730}.Release|Any CPU.Build.0 = Release|Any CPU - {C5B21768-C7C9-4FCB-AC1E-187B223D5A98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C5B21768-C7C9-4FCB-AC1E-187B223D5A98}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C5B21768-C7C9-4FCB-AC1E-187B223D5A98}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C5B21768-C7C9-4FCB-AC1E-187B223D5A98}.Release|Any CPU.Build.0 = Release|Any CPU - {428163C3-D558-4914-B570-A92069521877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {428163C3-D558-4914-B570-A92069521877}.Debug|Any CPU.Build.0 = Debug|Any CPU - {428163C3-D558-4914-B570-A92069521877}.Release|Any CPU.ActiveCfg = Release|Any CPU - {428163C3-D558-4914-B570-A92069521877}.Release|Any CPU.Build.0 = Release|Any CPU - {595E7C4D-506D-486D-98B7-5FDDF398D033}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {595E7C4D-506D-486D-98B7-5FDDF398D033}.Debug|Any CPU.Build.0 = Debug|Any CPU - {595E7C4D-506D-486D-98B7-5FDDF398D033}.Release|Any CPU.ActiveCfg = Release|Any CPU - {595E7C4D-506D-486D-98B7-5FDDF398D033}.Release|Any CPU.Build.0 = Release|Any CPU - {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Release|Any CPU.Build.0 = Release|Any CPU - {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Release|Any CPU.Build.0 = Release|Any CPU - {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Release|Any CPU.Build.0 = Release|Any CPU - {F2E04270-4551-41C4-99FF-E7125BED708C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F2E04270-4551-41C4-99FF-E7125BED708C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2E04270-4551-41C4-99FF-E7125BED708C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F2E04270-4551-41C4-99FF-E7125BED708C}.Release|Any CPU.Build.0 = Release|Any CPU - {EB781571-8548-477E-82AD-FB9FAB548D2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EB781571-8548-477E-82AD-FB9FAB548D2F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EB781571-8548-477E-82AD-FB9FAB548D2F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EB781571-8548-477E-82AD-FB9FAB548D2F}.Release|Any CPU.Build.0 = Release|Any CPU - {40C67036-C1A7-4FDF-AA83-8EC902E257F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {40C67036-C1A7-4FDF-AA83-8EC902E257F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {40C67036-C1A7-4FDF-AA83-8EC902E257F3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {40C67036-C1A7-4FDF-AA83-8EC902E257F3}.Release|Any CPU.Build.0 = Release|Any CPU - {F612D06F-3134-4B9B-95CD-EB3FC798AE60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F612D06F-3134-4B9B-95CD-EB3FC798AE60}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F612D06F-3134-4B9B-95CD-EB3FC798AE60}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F612D06F-3134-4B9B-95CD-EB3FC798AE60}.Release|Any CPU.Build.0 = Release|Any CPU - {8A7B01D3-9830-44FD-91A1-D8D010996BEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A7B01D3-9830-44FD-91A1-D8D010996BEB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A7B01D3-9830-44FD-91A1-D8D010996BEB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A7B01D3-9830-44FD-91A1-D8D010996BEB}.Release|Any CPU.Build.0 = Release|Any CPU - {5C7005BA-7D83-4E99-8073-D970943A7D61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5C7005BA-7D83-4E99-8073-D970943A7D61}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C7005BA-7D83-4E99-8073-D970943A7D61}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5C7005BA-7D83-4E99-8073-D970943A7D61}.Release|Any CPU.Build.0 = Release|Any CPU - {CC275937-DFE4-4383-B1BF-1D5D42B70C98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC275937-DFE4-4383-B1BF-1D5D42B70C98}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC275937-DFE4-4383-B1BF-1D5D42B70C98}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC275937-DFE4-4383-B1BF-1D5D42B70C98}.Release|Any CPU.Build.0 = Release|Any CPU - {47325742-5B38-48E7-95FB-CD94E6E07332}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47325742-5B38-48E7-95FB-CD94E6E07332}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47325742-5B38-48E7-95FB-CD94E6E07332}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47325742-5B38-48E7-95FB-CD94E6E07332}.Release|Any CPU.Build.0 = Release|Any CPU - {0520760A-9CFB-48A8-BCE4-6E951AFD6BE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0520760A-9CFB-48A8-BCE4-6E951AFD6BE9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0520760A-9CFB-48A8-BCE4-6E951AFD6BE9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0520760A-9CFB-48A8-BCE4-6E951AFD6BE9}.Release|Any CPU.Build.0 = Release|Any CPU - {357DF797-4EC2-4DBD-A4BD-D045277F2666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {357DF797-4EC2-4DBD-A4BD-D045277F2666}.Debug|Any CPU.Build.0 = Debug|Any CPU - {357DF797-4EC2-4DBD-A4BD-D045277F2666}.Release|Any CPU.ActiveCfg = Release|Any CPU - {357DF797-4EC2-4DBD-A4BD-D045277F2666}.Release|Any CPU.Build.0 = Release|Any CPU - {ECED4E13-B676-4277-8A8F-C8B2507B7D8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ECED4E13-B676-4277-8A8F-C8B2507B7D8C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ECED4E13-B676-4277-8A8F-C8B2507B7D8C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ECED4E13-B676-4277-8A8F-C8B2507B7D8C}.Release|Any CPU.Build.0 = Release|Any CPU - {5F65A509-26E3-4B02-B403-EEB6F0EF391F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F65A509-26E3-4B02-B403-EEB6F0EF391F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F65A509-26E3-4B02-B403-EEB6F0EF391F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F65A509-26E3-4B02-B403-EEB6F0EF391F}.Release|Any CPU.Build.0 = Release|Any CPU - {E90C4651-AF11-41B4-A839-10082D0391F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E90C4651-AF11-41B4-A839-10082D0391F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E90C4651-AF11-41B4-A839-10082D0391F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E90C4651-AF11-41B4-A839-10082D0391F9}.Release|Any CPU.Build.0 = Release|Any CPU - {CFE7A0E5-37FE-40BE-A70B-41B5104181C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFE7A0E5-37FE-40BE-A70B-41B5104181C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFE7A0E5-37FE-40BE-A70B-41B5104181C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFE7A0E5-37FE-40BE-A70B-41B5104181C4}.Release|Any CPU.Build.0 = Release|Any CPU - {0E480D2D-C7C1-A6FE-8C90-8A6F0DBCEAC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E480D2D-C7C1-A6FE-8C90-8A6F0DBCEAC2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E480D2D-C7C1-A6FE-8C90-8A6F0DBCEAC2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E480D2D-C7C1-A6FE-8C90-8A6F0DBCEAC2}.Release|Any CPU.Build.0 = Release|Any CPU - {1E689E85-279E-39D4-7D97-3E993FB6D95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E689E85-279E-39D4-7D97-3E993FB6D95B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E689E85-279E-39D4-7D97-3E993FB6D95B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E689E85-279E-39D4-7D97-3E993FB6D95B}.Release|Any CPU.Build.0 = Release|Any CPU - {6F9DB713-2879-4B14-9F9E-3B13C9B7F35C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6F9DB713-2879-4B14-9F9E-3B13C9B7F35C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6F9DB713-2879-4B14-9F9E-3B13C9B7F35C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6F9DB713-2879-4B14-9F9E-3B13C9B7F35C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {8BD8E012-F44F-4EE2-A234-D66C14D5FE4B} = {7FBBB086-0807-4998-85BF-6D1A49C8AD05} - {1AE65B61-9C05-4C80-ABFF-48F16E22FDF1} = {F0CBB7A7-D3FB-41FF-8F47-CF3F6A592249} - {59A10DF3-63EC-43F1-A3BF-4000CFA118D2} = {751093DD-5DBA-463E-ADBE-E05FAFB6983E} - {393B5B27-D15C-4F77-9457-FA14BA8F3C73} = {41CDCC73-9B81-49DD-9570-C54406E852AF} - {06882742-27A6-4347-97D9-56162CEC9C11} = {F0CBB7A7-D3FB-41FF-8F47-CF3F6A592249} - {2E1F5DB4-40CC-4804-A893-5DCE0193E598} = {41CDCC73-9B81-49DD-9570-C54406E852AF} - {635F00E1-AAD1-45F7-BEB7-D909AD33B9F6} = {53758A35-1C7E-4702-9B96-433ABA457B37} - {401865F5-1942-4713-B230-04544C0A97B0} = {41CDCC73-9B81-49DD-9570-C54406E852AF} - {B95650EA-25F0-449E-BA5D-99126BC5D730} = {41CDCC73-9B81-49DD-9570-C54406E852AF} - {C5B21768-C7C9-4FCB-AC1E-187B223D5A98} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - {428163C3-D558-4914-B570-A92069521877} = {47E27674-595D-4F7A-8CFB-127E768E1D1E} - {595E7C4D-506D-486D-98B7-5FDDF398D033} = {8679CAC8-9164-4007-BDD2-F004810EDA14} - {E86014F9-E4B3-4CD4-A210-2B3DB571DD86} = {43E3ACB3-E0BC-4370-8DBB-E3720C8C8FD1} - {788294BE-0D8E-40D4-9CEE-67896FBB52CE} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - {F2E04270-4551-41C4-99FF-E7125BED708C} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - {EB781571-8548-477E-82AD-FB9FAB548D2F} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - {40C67036-C1A7-4FDF-AA83-8EC902E257F3} = {FDDABAFE-35AD-42FC-AC95-0B1FE0DF0DDE} - {F612D06F-3134-4B9B-95CD-EB3FC798AE60} = {53758A35-1C7E-4702-9B96-433ABA457B37} - {8A7B01D3-9830-44FD-91A1-D8D010996BEB} = {FDDABAFE-35AD-42FC-AC95-0B1FE0DF0DDE} - {5C7005BA-7D83-4E99-8073-D970943A7D61} = {FDDABAFE-35AD-42FC-AC95-0B1FE0DF0DDE} - {59DF46F3-ECD0-43CA-AD12-3FEE8FCF9E4F} = {185AC9FF-381E-4AA1-B649-9771F4917214} - {CC275937-DFE4-4383-B1BF-1D5D42B70C98} = {59DF46F3-ECD0-43CA-AD12-3FEE8FCF9E4F} - {47325742-5B38-48E7-95FB-CD94E6E07332} = {59DF46F3-ECD0-43CA-AD12-3FEE8FCF9E4F} - {0520760A-9CFB-48A8-BCE4-6E951AFD6BE9} = {59DF46F3-ECD0-43CA-AD12-3FEE8FCF9E4F} - {9B906374-1142-4D69-86FF-B384806CA5FE} = {8679CAC8-9164-4007-BDD2-F004810EDA14} - {357DF797-4EC2-4DBD-A4BD-D045277F2666} = {9B906374-1142-4D69-86FF-B384806CA5FE} - {ECED4E13-B676-4277-8A8F-C8B2507B7D8C} = {9B906374-1142-4D69-86FF-B384806CA5FE} - {5F65A509-26E3-4B02-B403-EEB6F0EF391F} = {9B906374-1142-4D69-86FF-B384806CA5FE} - {E90C4651-AF11-41B4-A839-10082D0391F9} = {53758A35-1C7E-4702-9B96-433ABA457B37} - {FDDABAFE-35AD-42FC-AC95-0B1FE0DF0DDE} = {8679CAC8-9164-4007-BDD2-F004810EDA14} - {53758A35-1C7E-4702-9B96-433ABA457B37} = {8679CAC8-9164-4007-BDD2-F004810EDA14} - {47E27674-595D-4F7A-8CFB-127E768E1D1E} = {8679CAC8-9164-4007-BDD2-F004810EDA14} - {CFE7A0E5-37FE-40BE-A70B-41B5104181C4} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - {0E480D2D-C7C1-A6FE-8C90-8A6F0DBCEAC2} = {751093DD-5DBA-463E-ADBE-E05FAFB6983E} - {1E689E85-279E-39D4-7D97-3E993FB6D95B} = {751093DD-5DBA-463E-ADBE-E05FAFB6983E} - {6F9DB713-2879-4B14-9F9E-3B13C9B7F35C} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {615E00ED-BAEF-4E8E-A92A-9B82D87942A9} - EndGlobalSection -EndGlobal diff --git a/Source/Libation.slnx b/Source/Libation.slnx new file mode 100644 index 00000000..cd3493a8 --- /dev/null +++ b/Source/Libation.slnx @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj index 8d188447..a0599682 100644 --- a/Source/LibationAvalonia/LibationAvalonia.csproj +++ b/Source/LibationAvalonia/LibationAvalonia.csproj @@ -3,7 +3,7 @@ WinExe - net9.0 + net10.0 true Assets/libation.ico Libation @@ -72,12 +72,12 @@ - - - - + + + + - + diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml deleted file mode 100644 index 5e7ea5a7..00000000 --- a/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\Linux-chardonnay - FileSystem - net9.0 - linux-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml deleted file mode 100644 index 51c90474..00000000 --- a/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\MacOS-chardonnay - FileSystem - net9.0 - osx-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml deleted file mode 100644 index 4ac6936b..00000000 --- a/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\Windows-chardonnay - FileSystem - net9.0-windows - win-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LibationCli/LibationCli.csproj b/Source/LibationCli/LibationCli.csproj index 2b5b1aa6..521e5ae3 100644 --- a/Source/LibationCli/LibationCli.csproj +++ b/Source/LibationCli/LibationCli.csproj @@ -3,7 +3,7 @@ Exe - net9.0-windows7.0 + net10.0-windows7.0 win-x64 true false diff --git a/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml deleted file mode 100644 index 5e7ea5a7..00000000 --- a/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\Linux-chardonnay - FileSystem - net9.0 - linux-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml deleted file mode 100644 index 51c90474..00000000 --- a/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\MacOS-chardonnay - FileSystem - net9.0 - osx-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml deleted file mode 100644 index 44133444..00000000 --- a/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\Windows-chardonnay - FileSystem - net9.0 - win-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LibationFileManager/LibationFileManager.csproj b/Source/LibationFileManager/LibationFileManager.csproj index 2fee3460..869cd12a 100644 --- a/Source/LibationFileManager/LibationFileManager.csproj +++ b/Source/LibationFileManager/LibationFileManager.csproj @@ -1,11 +1,11 @@  - net9.0 + net10.0 - + diff --git a/Source/LibationSearchEngine/LibationSearchEngine.csproj b/Source/LibationSearchEngine/LibationSearchEngine.csproj index b06dd6a4..06a79c85 100644 --- a/Source/LibationSearchEngine/LibationSearchEngine.csproj +++ b/Source/LibationSearchEngine/LibationSearchEngine.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 @@ -9,7 +9,7 @@ - + diff --git a/Source/LibationUiBase/LibationUiBase.csproj b/Source/LibationUiBase/LibationUiBase.csproj index d77c954c..9e9efc79 100644 --- a/Source/LibationUiBase/LibationUiBase.csproj +++ b/Source/LibationUiBase/LibationUiBase.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 true true false diff --git a/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.cs b/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.cs index 4eb81155..956e2436 100644 --- a/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.cs +++ b/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.cs @@ -18,9 +18,9 @@ namespace LibationWinForms.Dialogs this.SetLibationIcon(); this.RestoreSizeAndLocation(LibationFileManager.Configuration.Instance); } - protected override void OnClosing(CancelEventArgs e) + protected override void OnFormClosing(FormClosingEventArgs e) { - base.OnClosing(e); + base.OnFormClosing(e); this.SaveSizeAndLocation(LibationFileManager.Configuration.Instance); } } diff --git a/Source/LibationWinForms/Dialogs/TrashBinDialog.cs b/Source/LibationWinForms/Dialogs/TrashBinDialog.cs index 06b7abd2..a4058633 100644 --- a/Source/LibationWinForms/Dialogs/TrashBinDialog.cs +++ b/Source/LibationWinForms/Dialogs/TrashBinDialog.cs @@ -19,7 +19,7 @@ namespace LibationWinForms.Dialogs this.SetLibationIcon(); this.RestoreSizeAndLocation(Configuration.Instance); - this.Closing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); + this.FormClosing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); deletedCheckedTemplate = deletedCheckedLbl.Text; diff --git a/Source/LibationWinForms/LibationWinForms.csproj b/Source/LibationWinForms/LibationWinForms.csproj index 56ec325a..8f053f99 100644 --- a/Source/LibationWinForms/LibationWinForms.csproj +++ b/Source/LibationWinForms/LibationWinForms.csproj @@ -3,7 +3,7 @@ WinExe - net9.0-windows7.0 + net10.0-windows7.0 true libation.ico Libation @@ -40,7 +40,7 @@ - + diff --git a/Source/LibationWinForms/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/LibationWinForms/Properties/PublishProfiles/WindowsProfile.pubxml deleted file mode 100644 index e24d9190..00000000 --- a/Source/LibationWinForms/Properties/PublishProfiles/WindowsProfile.pubxml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Release - Any CPU - ..\bin\Publish\classic - FileSystem - net9.0-windows - win-x64 - true - false - - \ No newline at end of file diff --git a/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj b/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj index c7e8c8e8..5d2cbd8e 100644 --- a/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj +++ b/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable true linux-x64 diff --git a/Source/LoadByOS/LinuxConfigApp/Properties/PublishProfiles/LinuxProfile.pubxml b/Source/LoadByOS/LinuxConfigApp/Properties/PublishProfiles/LinuxProfile.pubxml deleted file mode 100644 index da8f1f12..00000000 --- a/Source/LoadByOS/LinuxConfigApp/Properties/PublishProfiles/LinuxProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\..\bin\Publish\Linux-chardonnay - FileSystem - net9.0 - linux-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj b/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj index e4dca926..8eb78e1b 100644 --- a/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj +++ b/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable true diff --git a/Source/LoadByOS/MacOSConfigApp/Properties/PublishProfiles/MacOSProfile.pubxml b/Source/LoadByOS/MacOSConfigApp/Properties/PublishProfiles/MacOSProfile.pubxml deleted file mode 100644 index 0e665a18..00000000 --- a/Source/LoadByOS/MacOSConfigApp/Properties/PublishProfiles/MacOSProfile.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Release - Any CPU - ..\..\bin\Publish\MacOS-chardonnay - FileSystem - net9.0 - osx-x64 - true - false - false - - \ No newline at end of file diff --git a/Source/LoadByOS/WindowsConfigApp/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/LoadByOS/WindowsConfigApp/Properties/PublishProfiles/WindowsProfile.pubxml deleted file mode 100644 index 352cb368..00000000 --- a/Source/LoadByOS/WindowsConfigApp/Properties/PublishProfiles/WindowsProfile.pubxml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Release - Any CPU - ..\..\bin\Publish\classic - FileSystem - net9.0-windows - win-x64 - true - false - - \ No newline at end of file diff --git a/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj b/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj index 9ed2f956..b6a1037d 100644 --- a/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj +++ b/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj @@ -2,7 +2,7 @@ WinExe - net9.0-windows7.0 + net10.0-windows7.0 true win-x64 true diff --git a/Source/_Demos/LoadByOS/CrossPlatformClientExe/CrossPlatformClientExe.csproj b/Source/_Demos/LoadByOS/CrossPlatformClientExe/CrossPlatformClientExe.csproj index ac264a10..1974d7a9 100644 --- a/Source/_Demos/LoadByOS/CrossPlatformClientExe/CrossPlatformClientExe.csproj +++ b/Source/_Demos/LoadByOS/CrossPlatformClientExe/CrossPlatformClientExe.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable false false @@ -19,7 +19,7 @@ - + diff --git a/Source/_Demos/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj b/Source/_Demos/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj index 99f8a4a0..5ce4b24b 100644 --- a/Source/_Demos/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj +++ b/Source/_Demos/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable false false diff --git a/Source/_Demos/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj b/Source/_Demos/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj index 8197bf05..505f8b20 100644 --- a/Source/_Demos/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj +++ b/Source/_Demos/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj @@ -2,7 +2,7 @@ WinExe - net9.0-windows7.0 + net10.0-windows7.0 true true enable diff --git a/Source/_Tests/AssertionHelper/AssertionHelper.csproj b/Source/_Tests/AssertionHelper/AssertionHelper.csproj index b3f660e6..467484fb 100644 --- a/Source/_Tests/AssertionHelper/AssertionHelper.csproj +++ b/Source/_Tests/AssertionHelper/AssertionHelper.csproj @@ -1,14 +1,14 @@  - net9.0 + net10.0 enable enable - - + + diff --git a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj index 1ad37171..6ac8d6df 100644 --- a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj +++ b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj @@ -1,12 +1,12 @@  - net9.0 + net10.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj index 732623e1..38797420 100644 --- a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj +++ b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj @@ -1,12 +1,12 @@ - net9.0 + net10.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj b/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj index da7e0dc9..2d249fbc 100644 --- a/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj +++ b/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj @@ -1,13 +1,13 @@  - net9.0 + net10.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj b/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj index b7fbad79..be9a9e84 100644 --- a/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj +++ b/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj @@ -1,13 +1,13 @@ - net9.0 + net10.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj b/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj index e44097f0..3f22cecd 100644 --- a/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj +++ b/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj @@ -1,13 +1,13 @@ - net9.0 + net10.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/_Tests/LibationUiBase.Tests/LibationUiBase.Tests.csproj b/Source/_Tests/LibationUiBase.Tests/LibationUiBase.Tests.csproj index 84b20b39..0277e6f3 100644 --- a/Source/_Tests/LibationUiBase.Tests/LibationUiBase.Tests.csproj +++ b/Source/_Tests/LibationUiBase.Tests/LibationUiBase.Tests.csproj @@ -1,15 +1,15 @@ - net9.0 + net10.0 latest enable enable - - + + diff --git a/Source/nuget.config b/Source/nuget.config new file mode 100644 index 00000000..b73c67fc --- /dev/null +++ b/Source/nuget.config @@ -0,0 +1,10 @@ + + + + + + + + + + From f9ac0253fb6bf3a151327ed275538df315d625ad Mon Sep 17 00:00:00 2001 From: MBucari Date: Thu, 20 Nov 2025 21:00:00 -0700 Subject: [PATCH 2/5] Improve import performance on large batches --- Source/DtoImporterService/BookImporter.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Source/DtoImporterService/BookImporter.cs b/Source/DtoImporterService/BookImporter.cs index e804ce34..dc91d4cf 100644 --- a/Source/DtoImporterService/BookImporter.cs +++ b/Source/DtoImporterService/BookImporter.cs @@ -48,9 +48,21 @@ namespace DtoImporterService .Distinct() .ToHashSet(); - Cache = DbContext.Books - .GetBooks(b => productIds.Contains(b.AudibleProductId)) - .ToDictionarySafe(b => b.AudibleProductId); + if (productIds.Count > 100) + { + //For large imports, it is faster to get the whole library and filter in memory. + Cache = DbContext.Books + .GetBooks() + .ToArray() + .Where(b => productIds.Contains(b.AudibleProductId)) + .ToDictionarySafe(b => b.AudibleProductId); + } + else + { + Cache = DbContext.Books + .GetBooks(b => productIds.Contains(b.AudibleProductId)) + .ToDictionarySafe(b => b.AudibleProductId); + } } private int upsertBooks(IEnumerable importItems) From a55da5f1879ed8544211ee0c907584ba90e7b945 Mon Sep 17 00:00:00 2001 From: MBucari Date: Thu, 20 Nov 2025 22:05:16 -0700 Subject: [PATCH 3/5] Refactor DbContext access and disposal - Remove instance queue. This is a database, after all, and is designed to be accessed and written to concurrently - Reduce the number of calls to DbContexts.Create() - Ensure that no LibationContext remains open across an await boundary. Multithread context access is the most likely culprit for past issues. - Make all Update UserDefinedItem methods asynchronous. --- .../BulkSetDownloadStatus.cs | 4 +- Source/ApplicationServices/DbContexts.cs | 30 +- Source/ApplicationServices/LibraryCommands.cs | 283 +++++++++--------- Source/FileLiberator/AudioFileStorageExt.cs | 4 +- Source/FileLiberator/DownloadDecryptBook.cs | 2 +- Source/FileLiberator/DownloadPdf.cs | 2 +- .../ViewModels/TrashBinViewModel.cs | 6 +- Source/HangoverWinForms/Form1.Deleted.cs | 15 +- .../Dialogs/BookDetailsDialog.axaml.cs | 7 +- .../Dialogs/LocateAudiobooksDialog.axaml.cs | 6 +- .../Dialogs/TrashBinDialog.axaml.cs | 7 +- .../ViewModels/MainVM.VisibleBooks.cs | 8 +- .../LibationCli/Options/GetLicenseOptions.cs | 3 +- Source/LibationCli/Options/LiberateOptions.cs | 11 +- .../Options/SetDownloadStatusOptions.cs | 4 +- .../Options/_ProcessableOptionsBase.cs | 7 +- .../GridView/GridContextMenu.cs | 7 +- Source/LibationUiBase/GridView/GridEntry.cs | 2 +- .../ProcessQueue/ProcessBookViewModel.cs | 2 +- .../ProcessQueue/ProcessQueueViewModel.cs | 2 +- .../LibationUiBase/SeriesView/AyceButton.cs | 5 +- .../Dialogs/LocateAudiobooksDialog.cs | 6 +- .../Dialogs/TrashBinDialog.cs | 7 +- Source/LibationWinForms/Form1.VisibleBooks.cs | 14 +- .../LibationWinForms/GridView/ProductsGrid.cs | 2 +- 25 files changed, 218 insertions(+), 228 deletions(-) diff --git a/Source/ApplicationServices/BulkSetDownloadStatus.cs b/Source/ApplicationServices/BulkSetDownloadStatus.cs index 13a303be..bd63446f 100644 --- a/Source/ApplicationServices/BulkSetDownloadStatus.cs +++ b/Source/ApplicationServices/BulkSetDownloadStatus.cs @@ -69,10 +69,10 @@ namespace ApplicationServices return Count; } - public void Execute() + public async Task ExecuteAsync() { foreach (var a in actionSets) - a.LibraryBooks.UpdateBookStatus(a.newStatus); + await a.LibraryBooks.UpdateBookStatusAsync(a.newStatus); } } } diff --git a/Source/ApplicationServices/DbContexts.cs b/Source/ApplicationServices/DbContexts.cs index 6678ed30..8e5d44e2 100644 --- a/Source/ApplicationServices/DbContexts.cs +++ b/Source/ApplicationServices/DbContexts.cs @@ -3,20 +3,20 @@ using LibationFileManager; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; +#nullable enable namespace ApplicationServices { public static class DbContexts { /// Use for fully functional context, incl. SaveChanges(). For query-only, use the other method public static LibationContext GetContext() - => InstanceQueue.WaitToCreateInstance(() => - { - var context = !string.IsNullOrEmpty(Configuration.Instance.PostgresqlConnectionString) - ? LibationContextFactory.CreatePostgres(Configuration.Instance.PostgresqlConnectionString) - : LibationContextFactory.CreateSqlite(SqliteStorage.ConnectionString); - context.Database.Migrate(); - return context; - }); + { + var context = !string.IsNullOrEmpty(Configuration.Instance.PostgresqlConnectionString) + ? LibationContextFactory.CreatePostgres(Configuration.Instance.PostgresqlConnectionString) + : LibationContextFactory.CreateSqlite(SqliteStorage.ConnectionString); + context.Database.Migrate(); + return context; + } /// Use for full library querying. No lazy loading public static List GetLibrary_Flat_NoTracking(bool includeParents = false) @@ -24,5 +24,17 @@ namespace ApplicationServices using var context = GetContext(); return context.GetLibrary_Flat_NoTracking(includeParents); } - } + + public static List GetDeletedLibraryBooks() + { + using var context = GetContext(); + return context.GetDeletedLibraryBooks(); + } + + public static LibraryBook? GetLibraryBook_Flat_NoTracking(string productId, bool caseSensative = true) + { + using var context = GetContext(); + return context.GetLibraryBook_Flat_NoTracking(productId, caseSensative); + } + } } diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index f750eaff..24e80a01 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AudibleApi; +using AudibleApi; using AudibleUtilities; using DataLayer; using Dinah.Core; @@ -11,8 +6,14 @@ using Dinah.Core.Logging; using DtoImporterService; using FileManager; using LibationFileManager; +using Microsoft.Extensions.DependencyModel; using Newtonsoft.Json.Linq; using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; using static DtoImporterService.PerfLogger; #nullable enable @@ -141,9 +142,9 @@ namespace ApplicationServices return default; Log.Logger.Information("Begin long-running import"); - logTime($"pre {nameof(importIntoDbAsync)}"); - newCount = await importIntoDbAsync(importItems); - logTime($"post {nameof(importIntoDbAsync)}"); + logTime($"pre {nameof(ImportIntoDbAsync)}"); + newCount = await Task.Run(() => ImportIntoDbAsync(importItems)); + logTime($"post {nameof(ImportIntoDbAsync)}"); Log.Logger.Information($"Import complete. New count {newCount}"); return (totalCount, newCount); @@ -180,7 +181,8 @@ namespace ApplicationServices } } - public static async Task ImportSingleToDbAsync(AudibleApi.Common.Item item, string accountId, string localeName) + public static Task ImportSingleToDbAsync(AudibleApi.Common.Item item, string accountId, string localeName) => Task.Run(() => importSingleToDb(item, accountId, localeName)); + private static int importSingleToDb(AudibleApi.Common.Item item, string accountId, string localeName) { ArgumentValidator.EnsureNotNull(item, "item"); ArgumentValidator.EnsureNotNull(accountId, "accountId"); @@ -203,35 +205,23 @@ namespace ApplicationServices return 0; } - using var context = DbContexts.GetContext(); + return DoDbSizeChangeOperation(ctx => + { + var bookImporter = new BookImporter(ctx); + bookImporter.Import(importItems); + var book = ctx.LibraryBooks.FirstOrDefault(lb => lb.Book.AudibleProductId == importItem.DtoItem.ProductId); - var bookImporter = new BookImporter(context); - await Task.Run(() => bookImporter.Import(importItems)); - var book = await Task.Run(() => context.LibraryBooks.FirstOrDefault(lb => lb.Book.AudibleProductId == importItem.DtoItem.ProductId)); - - if (book is null) - { - book = new LibraryBook(bookImporter.Cache[importItem.DtoItem.ProductId], importItem.DtoItem.DateAdded, importItem.AccountId); - context.LibraryBooks.Add(book); - } - else - { - book.AbsentFromLastScan = false; - } - - try - { - int qtyChanged = await Task.Run(() => SaveContext(context)); - if (qtyChanged > 0) - await Task.Run(() => finalizeLibrarySizeChange(context)); - return qtyChanged; - } - catch (Exception ex) - { - Log.Logger.Error(ex, "Error adding single library book to DB. {@DebugInfo}", new { item, accountId, localeName }); - return 0; - } - } + if (book is null) + { + book = new LibraryBook(bookImporter.Cache[importItem.DtoItem.ProductId], importItem.DtoItem.DateAdded, importItem.AccountId); + ctx.LibraryBooks.Add(book); + } + else + { + book.AbsentFromLastScan = false; + } + }); + } private static LogArchiver? openLogArchive(string? archivePath) { @@ -347,23 +337,21 @@ namespace ApplicationServices } } - private static async Task importIntoDbAsync(List importItems) + private static async Task ImportIntoDbAsync(List importItems) => await Task.Run(() => importIntoDb(importItems)); + private static int importIntoDb(List importItems) { - logTime("importIntoDbAsync -- pre db"); - using var context = DbContexts.GetContext(); - var libraryBookImporter = new LibraryBookImporter(context); - var newCount = await Task.Run(() => libraryBookImporter.Import(importItems)); - logTime("importIntoDbAsync -- post Import()"); - int qtyChanges = SaveContext(context); - logTime("importIntoDbAsync -- post SaveChanges"); + logTime("importIntoDbAsync -- pre db"); - // this is any changes at all to the database, not just new books - if (qtyChanges > 0) - await Task.Run(() => finalizeLibrarySizeChange(context)); - logTime("importIntoDbAsync -- post finalizeLibrarySizeChange"); + int newCount = 0; - return newCount; - } + DoDbSizeChangeOperation(ctx => + { + var libraryBookImporter = new LibraryBookImporter(ctx); + newCount = libraryBookImporter.Import(importItems); + logTime("importIntoDbAsync -- post Import()"); + }); + return newCount; + } public static int SaveContext(LibationContext context) { @@ -389,57 +377,58 @@ namespace ApplicationServices #region remove/restore books public static Task RemoveBooksAsync(this IEnumerable idsToRemove) => Task.Run(() => removeBooks(idsToRemove)); - public static int RemoveBook(this LibraryBook idToRemove) => removeBooks(new[] { idToRemove }); private static int removeBooks(IEnumerable removeLibraryBooks) - { - try - { - if (removeLibraryBooks is null || !removeLibraryBooks.Any()) - return 0; - - using var context = DbContexts.GetContext(); + { + if (removeLibraryBooks is null || !removeLibraryBooks.Any()) + return 0; + return DoDbSizeChangeOperation(ctx => + { // Entry() NoTracking entities before SaveChanges() foreach (var lb in removeLibraryBooks) - { + { lb.IsDeleted = true; - context.Entry(lb).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + ctx.Entry(lb).State = Microsoft.EntityFrameworkCore.EntityState.Modified; } + }); + } - var qtyChanges = context.SaveChanges(); - if (qtyChanges > 0) - finalizeLibrarySizeChange(context); - - return qtyChanges; - } + public static Task RestoreBooksAsync(this IEnumerable idsToRemove) => Task.Run(() => restoreBooks(idsToRemove)); + private static int restoreBooks(this IEnumerable libraryBooks) + { + if (libraryBooks is null || !libraryBooks.Any()) + return 0; + try + { + return DoDbSizeChangeOperation(ctx => + { + // Entry() NoTracking entities before SaveChanges() + foreach (var lb in libraryBooks) + { + lb.IsDeleted = false; + ctx.Entry(lb).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + } + }); + } catch (Exception ex) { - Log.Logger.Error(ex, "Error removing books"); + Log.Logger.Error(ex, "Error restoring books"); throw; } } - public static int RestoreBooks(this IEnumerable libraryBooks) - { - try + public static Task PermanentlyDeleteBooksAsync(this IEnumerable idsToRemove) => Task.Run(() => permanentlyDeleteBooks(idsToRemove)); + private static int permanentlyDeleteBooks(this IEnumerable libraryBooks) + { + if (libraryBooks is null || !libraryBooks.Any()) + return 0; + try { - if (libraryBooks is null || !libraryBooks.Any()) - return 0; - - using var context = DbContexts.GetContext(); - - // Entry() NoTracking entities before SaveChanges() - foreach (var lb in libraryBooks) - { - lb.IsDeleted = false; - context.Entry(lb).State = Microsoft.EntityFrameworkCore.EntityState.Modified; - } - - var qtyChanges = context.SaveChanges(); - if (qtyChanges > 0) - finalizeLibrarySizeChange(context); - - return qtyChanges; + return DoDbSizeChangeOperation(ctx => + { + ctx.LibraryBooks.RemoveRange(libraryBooks); + ctx.Books.RemoveRange(libraryBooks.Select(lb => lb.Book)); + }); } catch (Exception ex) { @@ -448,36 +437,40 @@ namespace ApplicationServices } } - public static int PermanentlyDeleteBooks(this IEnumerable libraryBooks) + static int DoDbSizeChangeOperation(Action action) { - try - { - if (libraryBooks is null || !libraryBooks.Any()) - return 0; + try + { + int qtyChanges; + List? library; - using var context = DbContexts.GetContext(); + using (var context = DbContexts.GetContext()) + { + action?.Invoke(context); - context.LibraryBooks.RemoveRange(libraryBooks); - context.Books.RemoveRange(libraryBooks.Select(lb => lb.Book)); + qtyChanges = SaveContext(context); + logTime("importIntoDbAsync -- post SaveChanges"); + library = qtyChanges == 0 ? null : context.GetLibrary_Flat_NoTracking(includeParents: true); + } - var qtyChanges = context.SaveChanges(); - if (qtyChanges > 0) - finalizeLibrarySizeChange(context); + if (library is not null) + finalizeLibrarySizeChange(library); + logTime("importIntoDbAsync -- post finalizeLibrarySizeChange"); return qtyChanges; - } - catch (Exception ex) - { - Log.Logger.Error(ex, "Error restoring books"); - throw; - } - } + } + catch (Exception ex) + { + Log.Logger.Error(ex, "Error performing DB Size change operation"); + throw; + } + } + #endregion // call this whenever books are added or removed from library - private static void finalizeLibrarySizeChange(LibationContext context) + private static void finalizeLibrarySizeChange(List library) { - var library = context.GetLibrary_Flat_NoTracking(includeParents: true); LibrarySizeChanged?.Invoke(null, library); } @@ -490,21 +483,21 @@ namespace ApplicationServices public static event EventHandler>? BookUserDefinedItemCommitted; #region Update book details - public static int UpdateUserDefinedItem( + public static async Task UpdateUserDefinedItemAsync( this LibraryBook lb, string? tags = null, LiberatedStatus? bookStatus = null, LiberatedStatus? pdfStatus = null, Rating? rating = null) - => new[] { lb }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus, rating); + => await UpdateUserDefinedItemAsync([lb], tags, bookStatus, pdfStatus, rating); - public static int UpdateUserDefinedItem( + public static async Task UpdateUserDefinedItemAsync( this IEnumerable lb, string? tags = null, LiberatedStatus? bookStatus = null, LiberatedStatus? pdfStatus = null, Rating? rating = null) - => updateUserDefinedItem( + => await UpdateUserDefinedItemAsync( lb, udi => { // blank tags are expected. null tags are not @@ -521,52 +514,54 @@ namespace ApplicationServices udi.UpdateRating(rating.OverallRating, rating.PerformanceRating, rating.StoryRating); }); - public static int UpdateBookStatus(this LibraryBook lb, LiberatedStatus bookStatus, Version? libationVersion, AudioFormat audioFormat, string audioVersion) - => lb.UpdateUserDefinedItem(udi => { udi.BookStatus = bookStatus; udi.SetLastDownloaded(libationVersion, audioFormat, audioVersion); }); + public static async Task UpdateBookStatusAsync(this LibraryBook lb, LiberatedStatus bookStatus, Version? libationVersion, AudioFormat audioFormat, string audioVersion) + => await lb.UpdateUserDefinedItemAsync(udi => { udi.BookStatus = bookStatus; udi.SetLastDownloaded(libationVersion, audioFormat, audioVersion); }); - public static int UpdateBookStatus(this LibraryBook libraryBook, LiberatedStatus bookStatus) - => libraryBook.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus); - public static int UpdateBookStatus(this IEnumerable libraryBooks, LiberatedStatus bookStatus) - => libraryBooks.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus); + public static async Task UpdateBookStatusAsync(this LibraryBook libraryBook, LiberatedStatus bookStatus) + => await libraryBook.UpdateUserDefinedItemAsync(udi => udi.BookStatus = bookStatus); + public static async Task UpdateBookStatusAsync(this IEnumerable libraryBooks, LiberatedStatus bookStatus) + => await libraryBooks.UpdateUserDefinedItemAsync(udi => udi.BookStatus = bookStatus); - public static int UpdatePdfStatus(this LibraryBook libraryBook, LiberatedStatus pdfStatus) - => libraryBook.UpdateUserDefinedItem(udi => udi.SetPdfStatus(pdfStatus)); - public static int UpdatePdfStatus(this IEnumerable libraryBooks, LiberatedStatus pdfStatus) - => libraryBooks.UpdateUserDefinedItem(udi => udi.SetPdfStatus(pdfStatus)); + public static async Task UpdatePdfStatusAsync(this LibraryBook libraryBook, LiberatedStatus pdfStatus) + => await libraryBook.UpdateUserDefinedItemAsync(udi => udi.SetPdfStatus(pdfStatus)); + public static async Task UpdatePdfStatusAsync(this IEnumerable libraryBooks, LiberatedStatus pdfStatus) + => await libraryBooks.UpdateUserDefinedItemAsync(udi => udi.SetPdfStatus(pdfStatus)); - public static int UpdateTags(this LibraryBook libraryBook, string tags) - => libraryBook.UpdateUserDefinedItem(udi => udi.Tags = tags); - public static int UpdateTags(this IEnumerable libraryBooks, string tags) - => libraryBooks.UpdateUserDefinedItem(udi => udi.Tags = tags); + public static async Task UpdateTagsAsync(this LibraryBook libraryBook, string tags) + => await libraryBook.UpdateUserDefinedItemAsync(udi => udi.Tags = tags); + public static async Task UpdateTagsAsync(this IEnumerable libraryBooks, string tags) + => await libraryBooks.UpdateUserDefinedItemAsync(udi => udi.Tags = tags); - public static int UpdateUserDefinedItem(this LibraryBook libraryBook, Action action) - => libraryBook.updateUserDefinedItem(action); - public static int UpdateUserDefinedItem(this IEnumerable libraryBooks, Action action) - => libraryBooks.updateUserDefinedItem(action); + public static async Task UpdateUserDefinedItemAsync(this LibraryBook libraryBook, Action action) + => await UpdateUserDefinedItemAsync([libraryBook], action); - private static int updateUserDefinedItem(this LibraryBook libraryBook, Action action) => new[] { libraryBook }.updateUserDefinedItem(action); - private static int updateUserDefinedItem(this IEnumerable libraryBooks, Action action) + public static Task UpdateUserDefinedItemAsync(this IEnumerable libraryBooks, Action action) + => Task.Run(() => libraryBooks.updateUserDefinedItem(action)); + + private static int updateUserDefinedItem(this IEnumerable libraryBooks, Action action) { try { if (libraryBooks is null || !libraryBooks.Any()) return 0; - using var context = DbContexts.GetContext(); - - // Entry() instead of Attach() due to possible stack overflow with large tables - foreach (var book in libraryBooks) + int qtyChanges; + using (var context = DbContexts.GetContext()) { - action?.Invoke(book.Book.UserDefinedItem); + // Entry() instead of Attach() due to possible stack overflow with large tables + foreach (var book in libraryBooks) + { + action?.Invoke(book.Book.UserDefinedItem); - var udiEntity = context.Entry(book.Book.UserDefinedItem); + var udiEntity = context.Entry(book.Book.UserDefinedItem); - udiEntity.State = Microsoft.EntityFrameworkCore.EntityState.Modified; - if (udiEntity.Reference(udi => udi.Rating).TargetEntry is Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry ratingEntry) - ratingEntry.State = Microsoft.EntityFrameworkCore.EntityState.Modified; - } + udiEntity.State = Microsoft.EntityFrameworkCore.EntityState.Modified; + if (udiEntity.Reference(udi => udi.Rating).TargetEntry is Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry ratingEntry) + ratingEntry.State = Microsoft.EntityFrameworkCore.EntityState.Modified; + } - var qtyChanges = context.SaveChanges(); + qtyChanges = context.SaveChanges(); + } if (qtyChanges > 0) BookUserDefinedItemCommitted?.Invoke(null, libraryBooks); diff --git a/Source/FileLiberator/AudioFileStorageExt.cs b/Source/FileLiberator/AudioFileStorageExt.cs index 90ab45b1..c180fe85 100644 --- a/Source/FileLiberator/AudioFileStorageExt.cs +++ b/Source/FileLiberator/AudioFileStorageExt.cs @@ -23,9 +23,7 @@ namespace FileLiberator var series = libraryBook.Book.SeriesLink.SingleOrDefault(); if (series is not null) { - using var context = ApplicationServices.DbContexts.GetContext(); - var seriesParent = context.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId); - + LibraryBook seriesParent = ApplicationServices.DbContexts.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId); if (seriesParent is not null) { return Templates.Folder.GetFilename(seriesParent.ToDto(), AudibleFileStorage.BooksDirectory, ""); diff --git a/Source/FileLiberator/DownloadDecryptBook.cs b/Source/FileLiberator/DownloadDecryptBook.cs index eeaf06c0..97ba1e16 100644 --- a/Source/FileLiberator/DownloadDecryptBook.cs +++ b/Source/FileLiberator/DownloadDecryptBook.cs @@ -100,7 +100,7 @@ namespace FileLiberator { if (moveFilesTask.IsCompletedSuccessfully && !cancellationToken.IsCancellationRequested) { - libraryBook.UpdateBookStatus(LiberatedStatus.Liberated, Configuration.LibationVersion, audioFormat, audioVersion); + await libraryBook.UpdateBookStatusAsync(LiberatedStatus.Liberated, Configuration.LibationVersion, audioFormat, audioVersion); SetDirectoryTime(libraryBook, finalStorageDir); foreach (var cacheFile in result.CacheFiles.Where(f => File.Exists(f.FilePath))) { diff --git a/Source/FileLiberator/DownloadPdf.cs b/Source/FileLiberator/DownloadPdf.cs index 1e7f325a..52646fcc 100644 --- a/Source/FileLiberator/DownloadPdf.cs +++ b/Source/FileLiberator/DownloadPdf.cs @@ -35,7 +35,7 @@ namespace FileLiberator SetFileTime(libraryBook, actualDownloadedFilePath); SetDirectoryTime(libraryBook, Path.GetDirectoryName(actualDownloadedFilePath)); } - libraryBook.UpdatePdfStatus(result.IsSuccess ? LiberatedStatus.Liberated : LiberatedStatus.NotLiberated); + await libraryBook.UpdatePdfStatusAsync(result.IsSuccess ? LiberatedStatus.Liberated : LiberatedStatus.NotLiberated); return result; } diff --git a/Source/HangoverAvalonia/ViewModels/TrashBinViewModel.cs b/Source/HangoverAvalonia/ViewModels/TrashBinViewModel.cs index 22b5d15b..da2ea8fa 100644 --- a/Source/HangoverAvalonia/ViewModels/TrashBinViewModel.cs +++ b/Source/HangoverAvalonia/ViewModels/TrashBinViewModel.cs @@ -80,7 +80,7 @@ public class TrashBinViewModel : ViewModelBase, IDisposable public async Task RestoreCheckedAsync() { ControlsEnabled = false; - var qtyChanges = await Task.Run(CheckedBooks.RestoreBooks); + var qtyChanges = await CheckedBooks.RestoreBooksAsync(); if (qtyChanges > 0) Reload(); ControlsEnabled = true; @@ -89,7 +89,7 @@ public class TrashBinViewModel : ViewModelBase, IDisposable public async Task PermanentlyDeleteCheckedAsync() { ControlsEnabled = false; - var qtyChanges = await Task.Run(CheckedBooks.PermanentlyDeleteBooks); + var qtyChanges = await CheckedBooks.PermanentlyDeleteBooksAsync(); if (qtyChanges > 0) Reload(); ControlsEnabled = true; @@ -97,7 +97,7 @@ public class TrashBinViewModel : ViewModelBase, IDisposable public void Reload() { - var deletedBooks = DbContexts.GetContext().GetDeletedLibraryBooks(); + var deletedBooks = DbContexts.GetDeletedLibraryBooks(); DeletedBooks.Clear(); DeletedBooks.AddRange(deletedBooks.Select(lb => new CheckBoxViewModel { Item = lb })); diff --git a/Source/HangoverWinForms/Form1.Deleted.cs b/Source/HangoverWinForms/Form1.Deleted.cs index 0419d827..e48bd511 100644 --- a/Source/HangoverWinForms/Form1.Deleted.cs +++ b/Source/HangoverWinForms/Form1.Deleted.cs @@ -39,19 +39,22 @@ namespace HangoverWinForms deletedCbl.SetItemChecked(i, false); } - private void saveBtn_Click(object sender, EventArgs e) + private async void saveBtn_Click(object sender, EventArgs e) { var libraryBooksToRestore = deletedCbl.CheckedItems.Cast().ToList(); - var qtyChanges = libraryBooksToRestore.RestoreBooks(); + saveBtn.Enabled = false; + var qtyChanges = await libraryBooksToRestore.RestoreBooksAsync(); if (qtyChanges > 0) - reload(); - } + Invoke(reload); + Invoke(() => saveBtn.Enabled = true); + } private void reload() { deletedCbl.Items.Clear(); - var deletedBooks = DbContexts.GetContext().GetDeletedLibraryBooks(); - foreach (var lb in deletedBooks) + List deletedBooks = DbContexts.GetDeletedLibraryBooks(); + + foreach (var lb in deletedBooks) deletedCbl.Items.Add(lb); setLabel(); diff --git a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs index 7772893d..3f60f925 100644 --- a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs @@ -10,6 +10,7 @@ using LibationFileManager; using ReactiveUI; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using System.Windows.Input; namespace LibationAvalonia.Dialogs @@ -58,10 +59,10 @@ namespace LibationAvalonia.Dialogs LibraryBook = libraryBook; } - protected override void SaveAndClose() + protected override async Task SaveAndCloseAsync() { - LibraryBook.UpdateUserDefinedItem(NewTags, bookStatus: BookLiberatedStatus, pdfStatus: PdfLiberatedStatus); - base.SaveAndClose(); + await LibraryBook.UpdateUserDefinedItemAsync(NewTags, bookStatus: BookLiberatedStatus, pdfStatus: PdfLiberatedStatus); + await base.SaveAndCloseAsync(); } public void BookStatus_SelectionChanged(object sender, SelectionChangedEventArgs e) diff --git a/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs index f1eb4c75..dbabcf36 100644 --- a/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs @@ -81,17 +81,15 @@ namespace LibationAvalonia.Dialogs return; } - using var context = DbContexts.GetContext(); - await foreach (var book in AudioFileStorage.FindAudiobooksAsync(selectedFolder, tokenSource.Token)) { try { FilePathCache.Insert(book); - var lb = context.GetLibraryBook_Flat_NoTracking(book.Id); + var lb = DbContexts.GetLibraryBook_Flat_NoTracking(book.Id); if (lb is not null && lb.Book?.UserDefinedItem.BookStatus is not LiberatedStatus.Liberated) - await Task.Run(() => lb.UpdateBookStatus(LiberatedStatus.Liberated)); + await lb.UpdateBookStatusAsync(LiberatedStatus.Liberated); tokenSource.Token.ThrowIfCancellationRequested(); FileFound?.Invoke(this, book); diff --git a/Source/LibationAvalonia/Dialogs/TrashBinDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/TrashBinDialog.axaml.cs index 324aee12..b3a69b4f 100644 --- a/Source/LibationAvalonia/Dialogs/TrashBinDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/TrashBinDialog.axaml.cs @@ -104,7 +104,7 @@ namespace LibationAvalonia.Dialogs public async Task RestoreCheckedAsync() { ControlsEnabled = false; - var qtyChanges = await Task.Run(CheckedBooks.RestoreBooks); + var qtyChanges = await CheckedBooks.RestoreBooksAsync(); if (qtyChanges > 0) Reload(); ControlsEnabled = true; @@ -113,7 +113,7 @@ namespace LibationAvalonia.Dialogs public async Task PermanentlyDeleteCheckedAsync() { ControlsEnabled = false; - var qtyChanges = await Task.Run(CheckedBooks.PermanentlyDeleteBooks); + var qtyChanges = await CheckedBooks.PermanentlyDeleteBooksAsync(); if (qtyChanges > 0) Reload(); ControlsEnabled = true; @@ -121,8 +121,7 @@ namespace LibationAvalonia.Dialogs private void Reload() { - using var context = DbContexts.GetContext(); - var deletedBooks = context.GetDeletedLibraryBooks(); + var deletedBooks = DbContexts.GetDeletedLibraryBooks(); DeletedBooks.Clear(); DeletedBooks.AddRange(deletedBooks.Select(lb => new CheckBoxViewModel { Item = lb })); diff --git a/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs b/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs index 728a0b1f..bc40f7d5 100644 --- a/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs +++ b/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs @@ -102,7 +102,7 @@ namespace LibationAvalonia.ViewModels if (confirmationResult != DialogResult.Yes) return; - visibleLibraryBooks.UpdateTags(dialog.NewTags); + await visibleLibraryBooks.UpdateTagsAsync(dialog.NewTags); } public async Task SetBookDownloadedAsync() @@ -124,7 +124,7 @@ namespace LibationAvalonia.ViewModels if (confirmationResult != DialogResult.Yes) return; - visibleLibraryBooks.UpdateBookStatus(dialog.BookLiberatedStatus); + await visibleLibraryBooks.UpdateBookStatusAsync(dialog.BookLiberatedStatus); } public async Task SetPdfDownloadedAsync() @@ -146,7 +146,7 @@ namespace LibationAvalonia.ViewModels if (confirmationResult != DialogResult.Yes) return; - visibleLibraryBooks.UpdatePdfStatus(dialog.BookLiberatedStatus); + await visibleLibraryBooks.UpdatePdfStatusAsync(dialog.BookLiberatedStatus); } public async Task SetDownloadedAutoAsync() @@ -172,7 +172,7 @@ namespace LibationAvalonia.ViewModels if (confirmationResult != DialogResult.Yes) return; - bulkSetStatus.Execute(); + await bulkSetStatus.ExecuteAsync(); } public async Task RemoveVisibleAsync() diff --git a/Source/LibationCli/Options/GetLicenseOptions.cs b/Source/LibationCli/Options/GetLicenseOptions.cs index ea8296c8..bc637953 100644 --- a/Source/LibationCli/Options/GetLicenseOptions.cs +++ b/Source/LibationCli/Options/GetLicenseOptions.cs @@ -25,8 +25,7 @@ internal class GetLicenseOptions : OptionsBase return; } - using var dbContext = DbContexts.GetContext(); - if (dbContext.GetLibraryBook_Flat_NoTracking(Asin) is not LibraryBook libraryBook) + if (DbContexts.GetLibraryBook_Flat_NoTracking(Asin) is not LibraryBook libraryBook) { Console.Error.WriteLine($"Book not found with asin={Asin}"); return; diff --git a/Source/LibationCli/Options/LiberateOptions.cs b/Source/LibationCli/Options/LiberateOptions.cs index 0ff87aaa..fa327eee 100644 --- a/Source/LibationCli/Options/LiberateOptions.cs +++ b/Source/LibationCli/Options/LiberateOptions.cs @@ -53,15 +53,10 @@ namespace LibationCli return; } - LibraryBook libraryBook; - using (var dbContext = DbContexts.GetContext()) + if (DbContexts.GetLibraryBook_Flat_NoTracking(asin) is not LibraryBook libraryBook) { - if (dbContext.GetLibraryBook_Flat_NoTracking(asin) is not LibraryBook lb) - { - Console.Error.WriteLine($"Book not found with asin={asin}"); - return; - } - libraryBook = lb; + Console.Error.WriteLine($"Book not found with asin={asin}"); + return; } SetDownloadedStatus(libraryBook); diff --git a/Source/LibationCli/Options/SetDownloadStatusOptions.cs b/Source/LibationCli/Options/SetDownloadStatusOptions.cs index b563c152..1baeed57 100644 --- a/Source/LibationCli/Options/SetDownloadStatusOptions.cs +++ b/Source/LibationCli/Options/SetDownloadStatusOptions.cs @@ -53,14 +53,14 @@ namespace LibationCli { var status = SetDownloaded ? LiberatedStatus.Liberated : LiberatedStatus.NotLiberated; - var num = libraryBooks.UpdateBookStatus(status); + var num = await libraryBooks.UpdateBookStatusAsync(status); Console.WriteLine($"Set LiberatedStatus to '{status}' on {"book".PluralizeWithCount(num)}"); } else { var bulkSetStatus = new BulkSetDownloadStatus(libraryBooks, SetDownloaded, SetNotDownloaded); await Task.Run(() => bulkSetStatus.Discover()); - bulkSetStatus.Execute(); + await bulkSetStatus.ExecuteAsync(); foreach (var msg in bulkSetStatus.Messages) Console.WriteLine(msg); diff --git a/Source/LibationCli/Options/_ProcessableOptionsBase.cs b/Source/LibationCli/Options/_ProcessableOptionsBase.cs index 6450d20e..bb719300 100644 --- a/Source/LibationCli/Options/_ProcessableOptionsBase.cs +++ b/Source/LibationCli/Options/_ProcessableOptionsBase.cs @@ -77,12 +77,7 @@ namespace LibationCli { foreach (var asin in Asins.Select(a => a.TrimStart('[').TrimEnd(']'))) { - LibraryBook? lb = null; - using (var dbContext = DbContexts.GetContext()) - { - lb = dbContext.GetLibraryBook_Flat_NoTracking(asin, caseSensative: false); - } - if (lb is not null) + if (DbContexts.GetLibraryBook_Flat_NoTracking(asin, caseSensative: false) is LibraryBook lb) { config?.Invoke(lb); await ProcessOneAsync(Processable, lb, true); diff --git a/Source/LibationUiBase/GridView/GridContextMenu.cs b/Source/LibationUiBase/GridView/GridContextMenu.cs index dd73fec2..115912d6 100644 --- a/Source/LibationUiBase/GridView/GridContextMenu.cs +++ b/Source/LibationUiBase/GridView/GridContextMenu.cs @@ -57,7 +57,7 @@ public class GridContextMenu public void SetDownloaded() { LibraryBookEntries.Select(e => e.LibraryBook) - .UpdateUserDefinedItem(udi => + .UpdateUserDefinedItemAsync(udi => { udi.BookStatus = LiberatedStatus.Liberated; if (udi.Book.HasPdf()) @@ -68,7 +68,7 @@ public class GridContextMenu public void SetNotDownloaded() { LibraryBookEntries.Select(e => e.LibraryBook) - .UpdateUserDefinedItem(udi => + .UpdateUserDefinedItemAsync(udi => { udi.BookStatus = LiberatedStatus.NotLiberated; if (udi.Book.HasPdf()) @@ -90,8 +90,7 @@ public class GridContextMenu Configuration.Instance.SavePodcastsToParentFolder && libraryBook.Book.SeriesLink.SingleOrDefault() is SeriesBook series) { - using var context = DbContexts.GetContext(); - var seriesParent = context.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId); + var seriesParent = DbContexts.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId); folderDto = seriesParent?.ToDto() ?? fileDto; } diff --git a/Source/LibationUiBase/GridView/GridEntry.cs b/Source/LibationUiBase/GridView/GridEntry.cs index 72b4ba1d..754a3324 100644 --- a/Source/LibationUiBase/GridView/GridEntry.cs +++ b/Source/LibationUiBase/GridView/GridEntry.cs @@ -91,7 +91,7 @@ namespace LibationUiBase.GridView var api = await LibraryBook.GetApiAsync(); if (await api.ReviewAsync(Book.AudibleProductId, (int)rating.OverallRating, (int)rating.PerformanceRating, (int)rating.StoryRating)) - LibraryBook.UpdateUserDefinedItem(Book.UserDefinedItem.Tags, Book.UserDefinedItem.BookStatus, Book.UserDefinedItem.PdfStatus, rating); + await LibraryBook.UpdateUserDefinedItemAsync(Book.UserDefinedItem.Tags, Book.UserDefinedItem.BookStatus, Book.UserDefinedItem.PdfStatus, rating); } #endregion diff --git a/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs b/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs index c47da12e..78735622 100644 --- a/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs +++ b/Source/LibationUiBase/ProcessQueue/ProcessBookViewModel.cs @@ -364,7 +364,7 @@ public class ProcessBookViewModel : ReactiveObject if (dialogResult == SkipResult) { - libraryBook.UpdateBookStatus(LiberatedStatus.Error); + await libraryBook.UpdateBookStatusAsync(LiberatedStatus.Error); LogInfo($"Error. Skip: [{libraryBook.Book.AudibleProductId}] {libraryBook.Book.TitleWithSubtitle}"); } diff --git a/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs b/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs index 9a3472d8..e666edd5 100644 --- a/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs +++ b/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs @@ -277,7 +277,7 @@ public class ProcessQueueViewModel : ReactiveObject else if (result == ProcessBookResult.FailedAbort) Queue.ClearQueue(); else if (result == ProcessBookResult.FailedSkip) - nextBook.LibraryBook.UpdateBookStatus(LiberatedStatus.Error); + await nextBook.LibraryBook.UpdateBookStatusAsync(LiberatedStatus.Error); else if (result == ProcessBookResult.LicenseDeniedPossibleOutage && !shownServiceOutageMessage) { await MessageBoxBase.Show($""" diff --git a/Source/LibationUiBase/SeriesView/AyceButton.cs b/Source/LibationUiBase/SeriesView/AyceButton.cs index 00fb2403..842dc85f 100644 --- a/Source/LibationUiBase/SeriesView/AyceButton.cs +++ b/Source/LibationUiBase/SeriesView/AyceButton.cs @@ -70,9 +70,8 @@ namespace LibationUiBase.SeriesView if (await api.RemoveItemFromLibraryAsync(Item.ProductId)) { - using var context = DbContexts.GetContext(); - var lb = context.GetLibraryBook_Flat_NoTracking(Item.ProductId); - int result = await Task.Run((new[] { lb }).PermanentlyDeleteBooks); + var lb = DbContexts.GetLibraryBook_Flat_NoTracking(Item.ProductId); + int result = await LibraryCommands.PermanentlyDeleteBooksAsync([lb]); InLibrary = result == 0; } } diff --git a/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs b/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs index 88e3c552..c05d0e34 100644 --- a/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs +++ b/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs @@ -71,17 +71,15 @@ namespace LibationWinForms.Dialogs return; } - using var context = DbContexts.GetContext(); - await foreach (var book in AudioFileStorage.FindAudiobooksAsync(fbd.SelectedPath, tokenSource.Token)) { try { FilePathCache.Insert(book); - var lb = context.GetLibraryBook_Flat_NoTracking(book.Id); + var lb = DbContexts.GetLibraryBook_Flat_NoTracking(book.Id); if (lb.Book.UserDefinedItem.BookStatus is not LiberatedStatus.Liberated) - await Task.Run(() => lb.UpdateBookStatus(LiberatedStatus.Liberated)); + await lb.UpdateBookStatusAsync(LiberatedStatus.Liberated); tokenSource.Token.ThrowIfCancellationRequested(); this.Invoke(FileFound, this, book); diff --git a/Source/LibationWinForms/Dialogs/TrashBinDialog.cs b/Source/LibationWinForms/Dialogs/TrashBinDialog.cs index a4058633..fbb6c452 100644 --- a/Source/LibationWinForms/Dialogs/TrashBinDialog.cs +++ b/Source/LibationWinForms/Dialogs/TrashBinDialog.cs @@ -23,8 +23,7 @@ namespace LibationWinForms.Dialogs deletedCheckedTemplate = deletedCheckedLbl.Text; - using var context = DbContexts.GetContext(); - var deletedBooks = context.GetDeletedLibraryBooks(); + var deletedBooks = DbContexts.GetDeletedLibraryBooks(); foreach (var lb in deletedBooks) deletedCbl.Items.Add(lb); @@ -44,7 +43,7 @@ namespace LibationWinForms.Dialogs var removed = deletedCbl.CheckedItems.Cast().ToList(); removeFromCheckList(removed); - await Task.Run(removed.PermanentlyDeleteBooks); + await removed.PermanentlyDeleteBooksAsync(); setControlsEnabled(true); } @@ -56,7 +55,7 @@ namespace LibationWinForms.Dialogs var removed = deletedCbl.CheckedItems.Cast().ToList(); removeFromCheckList(removed); - await Task.Run(removed.RestoreBooks); + await removed.RestoreBooksAsync(); setControlsEnabled(true); } diff --git a/Source/LibationWinForms/Form1.VisibleBooks.cs b/Source/LibationWinForms/Form1.VisibleBooks.cs index fd248c3b..7c1f99ee 100644 --- a/Source/LibationWinForms/Form1.VisibleBooks.cs +++ b/Source/LibationWinForms/Form1.VisibleBooks.cs @@ -68,7 +68,7 @@ namespace LibationWinForms } } - private void replaceTagsToolStripMenuItem_Click(object sender, EventArgs e) + private async void replaceTagsToolStripMenuItem_Click(object sender, EventArgs e) { var dialog = new TagsBatchDialog(); var result = dialog.ShowDialog(); @@ -86,10 +86,10 @@ namespace LibationWinForms if (confirmationResult != DialogResult.Yes) return; - visibleLibraryBooks.UpdateTags(dialog.NewTags); + await visibleLibraryBooks.UpdateTagsAsync(dialog.NewTags); } - private void setBookDownloadedManualToolStripMenuItem_Click(object sender, EventArgs e) + private async void setBookDownloadedManualToolStripMenuItem_Click(object sender, EventArgs e) { var dialog = new LiberatedStatusBatchManualDialog(); var result = dialog.ShowDialog(); @@ -107,10 +107,10 @@ namespace LibationWinForms if (confirmationResult != DialogResult.Yes) return; - visibleLibraryBooks.UpdateBookStatus(dialog.BookLiberatedStatus); + await visibleLibraryBooks.UpdateBookStatusAsync(dialog.BookLiberatedStatus); } - private void setPdfDownloadedManualToolStripMenuItem_Click(object sender, EventArgs e) + private async void setPdfDownloadedManualToolStripMenuItem_Click(object sender, EventArgs e) { var dialog = new LiberatedStatusBatchManualDialog(isPdf: true); var result = dialog.ShowDialog(); @@ -128,7 +128,7 @@ namespace LibationWinForms if (confirmationResult != DialogResult.Yes) return; - visibleLibraryBooks.UpdatePdfStatus(dialog.BookLiberatedStatus); + await visibleLibraryBooks.UpdatePdfStatusAsync(dialog.BookLiberatedStatus); } private async void setDownloadedAutoToolStripMenuItem_Click(object sender, EventArgs e) @@ -154,7 +154,7 @@ namespace LibationWinForms if (confirmationResult != DialogResult.Yes) return; - bulkSetStatus.Execute(); + await bulkSetStatus.ExecuteAsync(); } private async void removeToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/Source/LibationWinForms/GridView/ProductsGrid.cs b/Source/LibationWinForms/GridView/ProductsGrid.cs index f17a62cb..2f8f1941 100644 --- a/Source/LibationWinForms/GridView/ProductsGrid.cs +++ b/Source/LibationWinForms/GridView/ProductsGrid.cs @@ -48,7 +48,7 @@ namespace LibationWinForms.GridView gridEntryDataGridView.CellContextMenuStripNeeded += GridEntryDataGridView_CellContextMenuStripNeeded; removeGVColumn.Frozen = false; - defaultFont = gridEntryDataGridView.DefaultCellStyle.Font; + defaultFont = gridEntryDataGridView.DefaultCellStyle.Font ?? gridEntryDataGridView.Font; setGridFontScale(Configuration.Instance.GridFontScaleFactor); setGridScale(Configuration.Instance.GridScaleFactor); Configuration.Instance.PropertyChanged += Configuration_ScaleChanged; From 913019cdfdf95ce421157b2d648b33e6140034c0 Mon Sep 17 00:00:00 2001 From: MBucari Date: Thu, 20 Nov 2025 22:19:21 -0700 Subject: [PATCH 4/5] Revert hack workaround for DataGridView error --- .../GridView/ProductsDisplay.cs | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/Source/LibationWinForms/GridView/ProductsDisplay.cs b/Source/LibationWinForms/GridView/ProductsDisplay.cs index 96254cb5..b8458049 100644 --- a/Source/LibationWinForms/GridView/ProductsDisplay.cs +++ b/Source/LibationWinForms/GridView/ProductsDisplay.cs @@ -92,32 +92,9 @@ namespace LibationWinForms.GridView private async void productsGrid_DetailsClicked(LibraryBookEntry liveGridEntry) { - // HACK: workaround for a Winforms bug. - // This event is fired by the DataGridCell.OnMouseUpInternal - // method. If any user changes made in the BookDetailsDialog - // result in the entry's row being removed from the DataGridView, - // then when this event handler returns, OnMouseUpInternal will - // throw a NRE trying to access the DataGridCell.DataGridView - // property. - - //Steps to cause the bug: - // * book has tag: asdf - // * filter is `[asdf]` - // * tag asdf is removed from book - // * DataGridView throws NRE - - //The workaround is to make this event handler execute - //asynchronously so that DataGridCell.OnMouseUpInternal completes - //before the user can change the DataGridView state. - - await Task.Run(() => this.Invoke(runAsync)); - - void runAsync() - { - var bookDetailsForm = new BookDetailsDialog(liveGridEntry.LibraryBook); - if (bookDetailsForm.ShowDialog() == DialogResult.OK) - liveGridEntry.LibraryBook.UpdateUserDefinedItem(bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus); - } + var bookDetailsForm = new BookDetailsDialog(liveGridEntry.LibraryBook); + if (bookDetailsForm.ShowDialog() == DialogResult.OK) + await liveGridEntry.LibraryBook.UpdateUserDefinedItemAsync(bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus); } #endregion From 75aa17df117cb8831dd14d0b264db2e81278db15 Mon Sep 17 00:00:00 2001 From: MBucari Date: Thu, 20 Nov 2025 22:35:13 -0700 Subject: [PATCH 5/5] Fix winforms STAThread on main --- Source/LibationWinForms/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs index 8c123f33..8862a63e 100644 --- a/Source/LibationWinForms/Program.cs +++ b/Source/LibationWinForms/Program.cs @@ -21,7 +21,7 @@ namespace LibationWinForms private static Form1 form1; [STAThread] - static async Task Main() + static void Main() { Task> libraryLoadTask; @@ -46,7 +46,7 @@ namespace LibationWinForms LibationUiBase.Forms.MessageBoxBase.ShowAsyncImpl = ShowMessageBox; // do this as soon as possible (post-config) - await RunSetupIfNeededAsync(config); + RunSetupIfNeededAsync(config).Wait(); // most migrations go in here LibationScaffolding.RunPostConfigMigrations(config);