Compare commits

..

97 Commits

Author SHA1 Message Date
Robert McRackan
cdd5f229d3 incr ver 2024-09-05 09:12:19 -04:00
Robert McRackan
29edfb7c3f Merge branch 'master' of https://github.com/rmcrackan/Libation 2024-09-05 09:07:54 -04:00
Robert McRackan
c0cb454d45 Make recursive file enumerations safer 2024-09-05 09:07:47 -04:00
rmcrackan
970a77c9e9 Merge pull request #946 from rmcrackan/dependabot/nuget/Source/LibationUiBase/SixLabors.ImageSharp-3.1.5
Bump SixLabors.ImageSharp from 3.1.4 to 3.1.5 in /Source/LibationUiBase
2024-07-22 14:05:40 -04:00
dependabot[bot]
3488c8e0f5 Bump SixLabors.ImageSharp from 3.1.4 to 3.1.5 in /Source/LibationUiBase
Bumps [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/SixLabors/ImageSharp/releases)
- [Commits](https://github.com/SixLabors/ImageSharp/compare/v3.1.4...v3.1.5)

---
updated-dependencies:
- dependency-name: SixLabors.ImageSharp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-22 17:45:08 +00:00
rmcrackan
5133720cc8 InstallOnMac.md updated instructions 2024-06-30 07:22:38 -04:00
rmcrackan
4150746f45 InstallOnMac.md typo 2024-06-29 08:08:57 -04:00
Robert McRackan
3a95e1e72f incr ver 2024-06-26 08:00:48 -04:00
rmcrackan
c74e26e1af Update release.yml
Release titles: don't include "v" in front of version number
2024-06-26 07:54:11 -04:00
rmcrackan
ae54c95d46 Update docker.yml
Rolling back docker build push action to attempt to fix build
2024-06-26 07:51:00 -04:00
Robert McRackan
56e6bd164b By user request, other Serilog.Sink packages are included for experimental use 2024-06-26 07:07:49 -04:00
rmcrackan
9b28bdceaa Merge pull request #923 from rmcrackan/dependabot/github_actions/docker/build-push-action-6
Bump docker/build-push-action from 5 to 6
2024-06-17 16:33:34 -04:00
dependabot[bot]
b7f7d9004d Bump docker/build-push-action from 5 to 6
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 14:23:33 +00:00
rmcrackan
1be0991e62 Add Audibly to FAQ 2024-06-07 13:27:18 -04:00
rmcrackan
ff8a2e59c5 Update FrequentlyAskedQuestions.md 2024-05-27 11:48:48 -04:00
Robert McRackan
453904261b Bug fix. Audible's api acts weird when page count gets to ~400 2024-05-16 07:53:19 -04:00
Robert McRackan
f9340db90a update references. audible api bugfix 2024-05-15 06:55:25 -04:00
Robert McRackan
5cd329dd26 refactor 2024-05-13 15:23:37 -04:00
Robert McRackan
b2a882b79d Bug fix #904 -- navigation bug with new Accessibility feature 2024-05-13 15:17:17 -04:00
Robert McRackan
75df78a2f7 Add OSVersion to logs 2024-05-13 14:01:34 -04:00
Robert McRackan
3ad52cbecc docker to .net8 2024-05-09 10:01:38 -04:00
Robert McRackan
27b2fe741c Add accessibility 2024-05-07 10:39:30 -04:00
Robert McRackan
d19fe2250c Add accessibility text to grid stoplight buttons 2024-05-06 21:56:00 -04:00
Robert McRackan
d16d0c8de2 Merge branch 'master' of https://github.com/rmcrackan/Libation 2024-05-05 16:24:07 -04:00
Robert McRackan
c213d5d9f6 Attempt to solve networking issue by disabling ipv6 2024-05-05 16:24:00 -04:00
rmcrackan
c73a023572 Update FrequentlyAskedQuestions.md 2024-04-30 22:42:34 -04:00
rmcrackan
67389917fd Merge pull request #879 from rmcrackan/dependabot/nuget/Source/LibationUiBase/SixLabors.ImageSharp-3.1.4
Bump SixLabors.ImageSharp from 3.1.3 to 3.1.4 in /Source/LibationUiBase
2024-04-15 17:03:13 -04:00
dependabot[bot]
b3264d5f42 Bump SixLabors.ImageSharp from 3.1.3 to 3.1.4 in /Source/LibationUiBase
Bumps [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) from 3.1.3 to 3.1.4.
- [Release notes](https://github.com/SixLabors/ImageSharp/releases)
- [Commits](https://github.com/SixLabors/ImageSharp/compare/v3.1.3...v3.1.4)

---
updated-dependencies:
- dependency-name: SixLabors.ImageSharp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 20:27:24 +00:00
Robert McRackan
962d9b550f "Unable to load module" should just be a warning, not error 2024-04-15 08:03:49 -04:00
Robert McRackan
91ce7272ae Bug fix #874 : Chardonnay wasn't allowing custom directories ending in "Books" 2024-04-04 08:13:37 -04:00
rmcrackan
2f64ca6856 Merge pull request #870 from ScubyG/patch-1
Update InstallOnLinux.md
2024-03-22 07:37:00 -04:00
Davy Jones
cfe5db436c Update InstallOnLinux.md
Fixed typo
2024-03-22 01:23:52 +00:00
rmcrackan
3653fc8094 Merge pull request #863 from rmcrackan/dependabot/github_actions/softprops/action-gh-release-2
Bump softprops/action-gh-release from 1 to 2
2024-03-11 10:45:44 -04:00
dependabot[bot]
662c0ec871 Bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 14:20:12 +00:00
rmcrackan
44d39eabdb Merge pull request #861 from rmcrackan/dependabot/nuget/Source/LibationUiBase/SixLabors.ImageSharp-3.1.3
Bump SixLabors.ImageSharp from 3.1.2 to 3.1.3 in /Source/LibationUiBase
2024-03-05 11:45:59 -05:00
dependabot[bot]
a0550d5c97 Bump SixLabors.ImageSharp from 3.1.2 to 3.1.3 in /Source/LibationUiBase
Bumps [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/SixLabors/ImageSharp/releases)
- [Commits](https://github.com/SixLabors/ImageSharp/compare/v3.1.2...v3.1.3)

---
updated-dependencies:
- dependency-name: SixLabors.ImageSharp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-05 16:38:00 +00:00
Robert McRackan
14eaca6d45 Update dependency. Security update 2024-03-05 11:36:36 -05:00
Robert McRackan
93ccc206ef Update dependencies 2024-03-04 14:02:42 -05:00
Robert McRackan
d3f0fd711e Remove validation check: SeriesName is null . At least 1 exception found in the wild 2024-02-29 14:44:41 -05:00
rmcrackan
3f4604e877 Update FrequentlyAskedQuestions.md
reformat
2024-02-29 10:15:47 -05:00
rmcrackan
c316709af8 Update FrequentlyAskedQuestions.md
Classic vs Chardonnay
2024-02-29 10:15:01 -05:00
Robert McRackan
221d5c7f1c paypal link 2024-02-19 10:32:26 -05:00
Robert McRackan
5a86a1a27b Typo 2024-02-13 21:42:24 -05:00
rmcrackan
dc5e55de68 Merge pull request #848 from patienttruth/master
Update Docker.md
2024-02-13 07:22:33 -05:00
patienttruth
ee37864a42 Update Docker.md
Included an explanation that you may have to manually input the InProgress variable.
2024-02-13 06:49:33 +00:00
Robert McRackan
efe347667c Better error reporting in audible api -- incl. inner exceptions 2024-01-20 21:44:29 -05:00
Robert McRackan
f27a18bdbb Better error reporting in audible api 2024-01-19 09:30:48 -05:00
Robert McRackan
d1834659d9 incr ver 2024-01-12 09:08:14 -05:00
Robert McRackan
7842b521d7 Update dependencies. Notes about upgrading 2024-01-12 07:44:40 -05:00
Robert McRackan
0822f0229d Revert Avalonia. Bug in 11.0.6 2024-01-04 10:03:33 -05:00
Robert McRackan
26aee4d29d Merge branch 'master' of https://github.com/rmcrackan/Libation 2024-01-03 11:43:59 -05:00
Robert McRackan
17a80a23a8 AAXClean upgrade to .net8 2024-01-03 11:43:45 -05:00
rmcrackan
e26fc9ca62 Merge pull request #808 from rmcrackan/dependabot/github_actions/actions/download-artifact-4
Bump actions/download-artifact from 3 to 4
2023-12-15 09:50:25 -05:00
rmcrackan
a03ccf1143 Merge pull request #807 from rmcrackan/dependabot/github_actions/actions/upload-artifact-4
Bump actions/upload-artifact from 3 to 4
2023-12-15 09:50:11 -05:00
dependabot[bot]
bb8dd615db Bump actions/download-artifact from 3 to 4
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-15 14:08:26 +00:00
dependabot[bot]
9022a2889f Bump actions/upload-artifact from 3 to 4
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-15 14:08:20 +00:00
rmcrackan
ef049a3b02 Merge pull request #805 from rmcrackan/dependabot/github_actions/actions/setup-dotnet-4
Bump actions/setup-dotnet from 3 to 4
2023-12-05 10:01:34 -05:00
dependabot[bot]
77409750aa Bump actions/setup-dotnet from 3 to 4
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3 to 4.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-05 14:14:17 +00:00
Robert McRackan
1702130b01 Upgrade to .net8 2023-11-15 19:57:39 -05:00
Robert McRackan
b6d1a7e3ba Upgrade to .net8 2023-11-15 19:53:26 -05:00
Robert McRackan
2907ba5c13 Add FAQ 2023-10-20 08:27:20 -04:00
Robert McRackan
6df6c79ac8 New locale: Brazil 2023-10-18 22:33:24 -04:00
rmcrackan
3a9ca5d827 Merge pull request #779 from rmcrackan/dependabot/github_actions/dwenegar/upload-release-assets-2
Bump dwenegar/upload-release-assets from 1 to 2
2023-10-13 14:41:26 -04:00
dependabot[bot]
e1e663e327 Bump dwenegar/upload-release-assets from 1 to 2
Bumps [dwenegar/upload-release-assets](https://github.com/dwenegar/upload-release-assets) from 1 to 2.
- [Release notes](https://github.com/dwenegar/upload-release-assets/releases)
- [Commits](https://github.com/dwenegar/upload-release-assets/compare/v1...v2)

---
updated-dependencies:
- dependency-name: dwenegar/upload-release-assets
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-13 14:37:55 +00:00
Robert McRackan
4b00d5fd84 incr ver 2023-09-18 13:58:23 -04:00
rmcrackan
02dbf8aad0 Merge pull request #751 from Mbucari/master
Minor Bug Fixes
2023-09-18 13:56:53 -04:00
rmcrackan
8326389f5c Merge pull request #732 from rmcrackan/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2023-09-18 13:56:33 -04:00
dependabot[bot]
34535b3ce1 Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 17:33:43 +00:00
rmcrackan
7e5366ab95 Merge pull request #738 from rmcrackan/dependabot/github_actions/docker/setup-buildx-action-3
Bump docker/setup-buildx-action from 2 to 3
2023-09-18 13:30:24 -04:00
dependabot[bot]
690de9bc5c Bump docker/setup-buildx-action from 2 to 3
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 17:25:20 +00:00
rmcrackan
c976aa2bb2 Merge pull request #739 from rmcrackan/dependabot/github_actions/docker/login-action-3
Bump docker/login-action from 2 to 3
2023-09-18 13:25:07 -04:00
rmcrackan
27f659285d Merge pull request #740 from rmcrackan/dependabot/github_actions/docker/build-push-action-5
Bump docker/build-push-action from 4 to 5
2023-09-18 13:24:55 -04:00
rmcrackan
423a5e7720 Merge pull request #741 from rmcrackan/dependabot/github_actions/docker/setup-qemu-action-3
Bump docker/setup-qemu-action from 2 to 3
2023-09-18 13:24:44 -04:00
Michael Bucari-Tovo
9152e12fe1 Fix #748 2023-09-18 10:14:54 -06:00
Michael Bucari-Tovo
f471c53139 Fix #734 2023-09-18 10:08:15 -06:00
dependabot[bot]
66d055bb90 Bump docker/setup-qemu-action from 2 to 3
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 14:50:49 +00:00
dependabot[bot]
2bbb35363a Bump docker/build-push-action from 4 to 5
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 14:50:46 +00:00
dependabot[bot]
1d3687cf9e Bump docker/login-action from 2 to 3
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 14:50:42 +00:00
Mbucari
daf925157f Update AppScaffolding.csproj 2023-09-02 07:59:30 -06:00
Mbucari
40eec9e674 Merge pull request #730 from Mbucari/master
Fix #729
2023-09-01 18:46:42 -06:00
MBucari
6f0782053e Restore PDF functionality (#729) 2023-09-01 16:30:35 -06:00
Michael Bucari-Tovo
04ad033ba0 Remove appsettings.json from program files dir 2023-08-31 09:36:38 -06:00
Robert McRackan
f12f8ba3ee incr ver 2023-08-30 15:00:20 -04:00
rmcrackan
cc6feb21ff Merge pull request #728 from Mbucari/master
Minor Bug fixes
2023-08-30 14:46:16 -04:00
Michael Bucari-Tovo
c4f2ec428d Allow Settings form resizing 2023-08-30 12:38:28 -06:00
Michael Bucari-Tovo
59689cb647 Update Dependencies 2023-08-30 11:59:40 -06:00
Michael Bucari-Tovo
d7f3758ebc Add support for environment variables and unix shortcuts in appsettings.json path. 2023-08-30 11:47:50 -06:00
Mbucari
49775b019c Update InstallOnMac.md 2023-08-30 09:06:57 -06:00
Michael Bucari-Tovo
e55e969349 Fix issue with save button being disabled. 2023-08-30 08:59:20 -06:00
Mbucari
42a93bfac1 Update AAXClean 2023-08-27 19:47:32 -06:00
Mbucari
f86c77a546 Create directory before trying to create appsettings.json 2023-08-27 19:47:00 -06:00
MBucari
88c35e2a56 Add scrolling view to settings window panels (#720) 2023-08-23 20:25:30 -06:00
MBucari
b405e8b6b2 Remove unised response groups 2023-08-20 11:40:24 -06:00
MBucari
92d283187d Add support for locating mp3 audiobooks 2023-08-20 11:38:43 -06:00
Robert McRackan
51b8cfe71f incr ver 2023-08-17 14:03:40 -04:00
rmcrackan
c80da5357b Merge pull request #716 from Mbucari/master
Fix NRE when item has no category ladders (#715)
2023-08-17 14:02:43 -04:00
Michael Bucari-Tovo
736d7c4a5f Fix NRE when item has no category ladders (#715) 2023-08-17 11:55:28 -06:00
91 changed files with 823 additions and 427 deletions

View File

@@ -33,7 +33,7 @@ on:
env:
DOTNET_CONFIGURATION: 'Release'
DOTNET_VERSION: '7.0.x'
DOTNET_VERSION: '8.0.x'
RELEASE_NAME: 'chardonnay'
jobs:
@@ -41,9 +41,9 @@ jobs:
name: '${{ inputs.OS }}-${{ inputs.architecture }}'
runs-on: ${{ inputs.runs_on }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
env:
@@ -124,7 +124,7 @@ jobs:
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
- name: Publish bundle
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ steps.bundle.outputs.artifact }}
path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}

View File

@@ -18,7 +18,7 @@ on:
env:
DOTNET_CONFIGURATION: 'Release'
DOTNET_VERSION: '7.0.x'
DOTNET_VERSION: '8.0.x'
jobs:
build:
@@ -35,9 +35,9 @@ jobs:
release_name: classic
prefix: Classic-
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
env:
@@ -107,7 +107,7 @@ jobs:
Compress-Archive -Path "${bin_dir}*" -DestinationPath "$artifact.zip"
- name: Publish artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ steps.zip.outputs.artifact }}.zip
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip

View File

@@ -24,22 +24,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.docker_username }}
password: ${{ secrets.docker_token }}
- name: Build and push
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
push: true
build-args: 'FOLDER_NAME=Linux-chardonnay'

View File

@@ -39,21 +39,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Release
id: release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
name: Libation v${{ needs.prerelease.outputs.version }}
name: Libation ${{ needs.prerelease.outputs.version }}
body: <Put a body here>
draft: true
prerelease: false
- name: Upload release assets
uses: dwenegar/upload-release-assets@v1
uses: dwenegar/upload-release-assets@v2
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
with:

View File

@@ -1,12 +1,12 @@
# Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:7.0 as build-env
FROM mcr.microsoft.com/dotnet/sdk:8.0 as build-env
COPY Source /Source
RUN dotnet publish -c Release -o /Source/bin/Publish/Linux-chardonnay /Source/LibationCli/LibationCli.csproj -p:PublishProfile=/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml
COPY Docker/liberate.sh /Source/bin/Publish/Linux-chardonnay
FROM mcr.microsoft.com/dotnet/runtime:7.0
FROM mcr.microsoft.com/dotnet/runtime:8.0
ENV SLEEP_TIME "30m"

View File

@@ -1,6 +1,6 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.

View File

@@ -1,10 +1,11 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
### Disclaimer
# Disclaimer
The docker image is provided as-is. We hope it can be useful to you but it is not officially supported.
### Setup
@@ -12,7 +13,15 @@ In order to use the docker image, you'll need to provide it with a copy of the `
In Settings.json, make the following changes:
* Change `Books` to `/data`
* Change `InProgress` to `/tmp`
* Change `InProgress` to `/tmp` *
*You may have to paste the following at the end of your your Settings.json file if `InProgess` is not present:
```
"InProgress": "/tmp"
```
![image](https://github.com/patienttruth/Libation/assets/105557996/cf65a108-cadf-4284-9000-e7672c99c59b)
### Running
Once the configuration files are copied and edited, the docker image can be run with the following command.

View File

@@ -0,0 +1,38 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
# Frequently Asked Questions
## Q: What's the difference between 'Classic' and 'Chardonnay'?
**A:** First and most importantly: Classic and Chardonnay have the exact same features.
* **Classic** is Windows only. Its older 'grey boxes' look has a compact design which allows for more information on the screen. Notably, Classic was written using an older, more mature technology which has built-in support for screenreaders.
* **Chardonnay** is available for Windows, Mac, and Linux. Its modern design has a more open look and feel.
## Q: Now that I've downloaded my books, how can I listen to them?
**A:** You can use any app which plays m4b files (or mp3 files if you used that setting). Here are just a few ideas. Disclaimer: I have no affiliation with any of these companies:
* iOS: [BookPlayer](https://apps.apple.com/us/app/bookplayer/id1138219998)
* iOS: [Bound](https://apps.apple.com/us/app/bound-audiobook-player/id1041727137)
* Android: [Smart AudioBook Player](https://play.google.com/store/apps/details?id=ak.alizandro.smartaudiobookplayer&hl=en_US&gl=US)
* Android: [Listen](https://play.google.com/store/apps/details?id=ru.litres.android.audio&hl=en_US&gl=US)
* Desktop: [VLC](https://www.videolan.org/)
* Windows Desktop: [Audibly](https://github.com/rstewa/Audibly) -- a desktop player build specifically for audiobooks
Self-hosting online:
* [audiobookshelf](https://www.audiobookshelf.org). On [reddit](https://www.reddit.com/r/audiobookshelf/)
* [plex](https://www.plex.tv/). Listen with [Prologue](https://prologue.audio/) (iOS)
## Q: How do I use Libation with a South Africa account?
**A:** Like many countries, amazon gives South Africa it's own amazon site. [Unlike many other regions](https://www.audible.com/ep/country-selector) there is not South Africa specific audible site. Use `US` for your region -- ie: audible.com.
(Not exactly a *frequently* asked question but it's come up more than once)

View File

@@ -1,6 +1,6 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.

View File

@@ -1,15 +1,16 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
### Install and Run Libation on Ubuntu
# Install and Run Libation on Ubuntu
New Libation releases are automatically packed into .deb and .rpm package and are available from the Libation repository's releases page.
Run this command in your terminal to dowbnload and install Libation, replacing the url with the latest Libation package url:
Run this command in your terminal to download and install Libation, replacing the url with the latest Libation package url:
- Debian
```Console

View File

@@ -1,9 +1,10 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
# Run Libation on MacOS
This walkthrough should get you up and running with Libation on your Mac.
@@ -15,13 +16,40 @@ This walkthrough should get you up and running with Libation on your Mac.
- Apple Silicon (M1, M2, ...): `Libation.9.4.2-macOS-chardonnay-`**arm64**`.tgz`
- Intel: `Libation.x.x.x-macOS-chardonnay-`**x64**`.tgz`
- Move the extracted Libation app bundle to your applications folder.
- Open a terminal (Go > Utilities > Terminal)
- Copy/paste/run the following command (you'll be prompted to enter your password)
- Right-click on Libation and then click on open
- The first time, it will not immediately show you an option to open it. Just dismiss the dialog and do the same thing again (right-click -> open) then you will get an option to run the unsigned application. This takes about 10 seconds.
## If this doesn't work
You can add Libation as a safe app without touching Gatekeeper.
- Copy/paste/run the following command. Adjust the file path to the Libation.app on your computer if necessary.
```Console
xattr -r -d com.apple.quarantine ~/Downloads/Libation.app
```
- Close the terminal and use Libation!
## If this still doesn't work
- Copy/paste/run the following command (you'll be prompted to enter your Mac password)
```Console
sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
```
- Close the terminal and use Libation!
```
* Close the terminal and use Libation!
## Troubleshooting
If Libation fails to start after completing the above steps, try the following:
1. Right-click the Libation app in your applications folder and select _Show Package Contents_
2. Open the `Contents` folder and then the `MacOS` folder.
3. Find the file named `Libation`, right-click it, and then select _Open_.
Libation _should_ launch, and you should now be able to open Libation by just double-clicking the app bundle in your applications folder.
## Running Hangover
@@ -30,7 +58,7 @@ Libation comes with a recovery app called Hangover. You can start it by running
open /Applications/Libation.app --args hangover
```
## Runnign LibationCli
## Running LibationCli
Libation comes with a command-line interface. Unfortunately, due to the way apps are sandboxed on mac, its use is somewhat limited. To open a new sandboxed terminal in LibationCli's directory, run the following command:
```Console

View File

@@ -1,3 +1,10 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
# Naming Templates
File and Folder names can be customized using Libation's built-in tag template naming engine. To edit how folder and file names are created, go to Settings \> Download/Decrypt and edit the naming templates. If you're splitting your audiobook into multiple files by chapter, you can also use a custom template to set each chapter's title metadata tag by editing the template in Settings \> Audio File Options.

View File

@@ -1,6 +1,6 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.

View File

@@ -2,9 +2,11 @@
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/MBucari?locale.x=en_us)
### If you found this useful, tell a friend. If you found this REALLY useful, you can click here to [PayPal.me](https://paypal.me/mcrackan?locale.x=en_us)
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
# Table of Contents
- [Audible audiobook manager](#audible-audiobook-manager)
@@ -31,6 +33,7 @@
- [Custom File Naming](Documentation/NamingTemplates.md)
- [Command Line Interface](Documentation/Advanced.md#command-line-interface)
- [Docker](Documentation/Docker.md)
- [Frequently Asked Questions](Documentation/FrequentlyAskedQuestions.md)
## Getting started

View File

@@ -109,9 +109,6 @@ ln -s /usr/lib/libation/LibationCli /usr/bin/libationcli
if ! grep -q 'fs.inotify.max_user_instances=524288' /etc/sysctl.conf; then
echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p
fi
# workaround until this file is moved to the user's home directory
touch /usr/lib/libation/appsettings.json
chmod 666 /usr/lib/libation/appsettings.json
" >> $FOLDER_DEBIAN/postinst
echo "Creating control file..."

View File

@@ -94,8 +94,6 @@ install * %{buildroot}%{_libdir}/%{name}/
if [ \$1 -eq 1 ] ; then
# Initial installation
touch %{_libdir}/%{name}/appsettings.json
chmod 666 %{_libdir}/%{name}/appsettings.json
ln -s %{_libdir}/%{name}/Libation %{_bindir}/libation
ln -s %{_libdir}/%{name}/Hangover %{_bindir}/hangover

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -13,7 +13,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AAXClean.Codecs" Version="1.1.0" />
<PackageReference Include="AAXClean.Codecs" Version="1.1.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Version>11.0.0.1</Version>
<TargetFramework>net8.0</TargetFramework>
<Version>11.3.15.1</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Octokit" Version="7.1.0" />
<PackageReference Include="Serilog.Sinks.ZipFile" Version="1.0.1" />
<PackageReference Include="Octokit" Version="11.0.1" />
<!-- Do not remove unused Serilog.Sinks -->
<!-- Only ZipFile sink is currently used. By user request (June 2024) others packages are included for experimental use. -->
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.ZipFile" Version="3.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApplicationServices\ApplicationServices.csproj" />
@@ -19,4 +23,4 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
</Project>
</Project>

View File

@@ -9,9 +9,9 @@ using Dinah.Core;
using Dinah.Core.IO;
using Dinah.Core.Logging;
using LibationFileManager;
using System.Runtime.InteropServices;
using Newtonsoft.Json.Linq;
using Serilog;
using System.Runtime.InteropServices;
namespace AppScaffolding
{
@@ -124,6 +124,9 @@ namespace AppScaffolding
{ "MinimumLevel", "Information" },
{ "WriteTo", new JArray
{
// ABOUT SINKS
// Only ZipFile sink is currently used. By user request (June 2024) others packages are included for experimental use.
// new JObject { {"Name", "Console" } }, // this has caused more problems than it's solved
new JObject
{
@@ -227,12 +230,20 @@ namespace AppScaffolding
// begin logging session with a form feed
Log.Logger.Information("\r\n\f");
Log.Logger.Information("Begin. {@DebugInfo}", new
static int fileCount(FileManager.LongPath longPath)
{
try { return FileManager.FileUtility.SaferEnumerateFiles(longPath).Count(); }
catch { return -1; }
}
Log.Logger.Information("Begin. {@DebugInfo}", new
{
AppName = EntryAssembly.GetName().Name,
Version = BuildVersion.ToString(),
ReleaseIdentifier,
Configuration.OS,
Environment.OSVersion,
InteropFactory.InteropFunctionsType,
Mode = mode,
LogLevel_Verbose_Enabled = Log.Logger.IsVerboseEnabled(),
@@ -242,6 +253,7 @@ namespace AppScaffolding
LogLevel_Error_Enabled = Log.Logger.IsErrorEnabled(),
LogLevel_Fatal_Enabled = Log.Logger.IsFatalEnabled(),
config.AutoScan,
config.BetaOptIn,
config.UseCoverAsFolderIcon,
config.LibationFiles,
@@ -250,10 +262,12 @@ namespace AppScaffolding
config.InProgress,
AudibleFileStorage.DownloadsInProgressDirectory,
DownloadsInProgressFiles = FileManager.FileUtility.SaferEnumerateFiles(AudibleFileStorage.DownloadsInProgressDirectory).Count(),
DownloadsInProgressFiles = fileCount(AudibleFileStorage.DownloadsInProgressDirectory),
AudibleFileStorage.DecryptInProgressDirectory,
DecryptInProgressFiles = FileManager.FileUtility.SaferEnumerateFiles(AudibleFileStorage.DecryptInProgressDirectory).Count(),
DecryptInProgressFiles = fileCount(AudibleFileStorage.DecryptInProgressDirectory),
disableIPv6 = AppContext.TryGetSwitch("System.Net.DisableIPv6", out bool disableIPv6Value),
});
if (InteropFactory.InteropFunctionsType is null)

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="NPOI" Version="2.6.1" />
<PackageReference Include="CsvHelper" Version="32.0.3" />
<PackageReference Include="NPOI" Version="2.7.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -119,9 +119,15 @@ namespace ApplicationServices
logTime($"pre {nameof(scanAccountsAsync)} all");
var libraryOptions = new LibraryOptions
{
ResponseGroups = LibraryOptions.ResponseGroupOptions.ALL_OPTIONS,
ImageSizes = LibraryOptions.ImageSizeOptions._500 | LibraryOptions.ImageSizeOptions._1215
{
ResponseGroups
= LibraryOptions.ResponseGroupOptions.Rating | LibraryOptions.ResponseGroupOptions.Media
| LibraryOptions.ResponseGroupOptions.Relationships | LibraryOptions.ResponseGroupOptions.ProductDesc
| LibraryOptions.ResponseGroupOptions.Contributors | LibraryOptions.ResponseGroupOptions.ProvidedReview
| LibraryOptions.ResponseGroupOptions.ProductPlans | LibraryOptions.ResponseGroupOptions.Series
| LibraryOptions.ResponseGroupOptions.CategoryLadders | LibraryOptions.ResponseGroupOptions.ProductExtendedAttrs
| LibraryOptions.ResponseGroupOptions.PdfUrl | LibraryOptions.ResponseGroupOptions.OriginAsin,
ImageSizes = LibraryOptions.ImageSizeOptions._500 | LibraryOptions.ImageSizeOptions._1215
};
var importItems = await scanAccountsAsync(apiExtendedfunc, accounts, libraryOptions);
logTime($"post {nameof(scanAccountsAsync)} all");

View File

@@ -207,7 +207,11 @@ namespace AudibleUtilities
try
{
var sw = Stopwatch.StartNew();
var items = await Api.GetCatalogProductsAsync(asins, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS);
var items = await Api.GetCatalogProductsAsync(asins, CatalogOptions.ResponseGroupOptions.Rating | CatalogOptions.ResponseGroupOptions.Media
| CatalogOptions.ResponseGroupOptions.Relationships | CatalogOptions.ResponseGroupOptions.ProductDesc
| CatalogOptions.ResponseGroupOptions.Contributors | CatalogOptions.ResponseGroupOptions.ProvidedReview
| CatalogOptions.ResponseGroupOptions.ProductPlans | CatalogOptions.ResponseGroupOptions.Series
| CatalogOptions.ResponseGroupOptions.CategoryLadders | CatalogOptions.ResponseGroupOptions.ProductExtendedAttrs);
sw.Stop();
Serilog.Log.Logger.Debug($"Batch {batchNum} End: Retrieved {items.Count} items in {sw.ElapsedMilliseconds} ms");

View File

@@ -90,8 +90,10 @@ namespace AudibleUtilities
var distinct = items.GetSeriesDistinct();
if (distinct.Any(s => s.SeriesId is null))
exceptions.Add(new ArgumentException($"Collection contains {nameof(Item.Series)} with null {nameof(Series.SeriesId)}", nameof(items)));
if (distinct.Any(s => s.SeriesName is null))
exceptions.Add(new ArgumentException($"Collection contains {nameof(Item.Series)} with null {nameof(Series.SeriesName)}", nameof(items)));
//// unfortunately, a user has a series with no name
//if (distinct.Any(s => s.SeriesName is null))
// exceptions.Add(new ArgumentException($"Collection contains {nameof(Item.Series)} with null {nameof(Series.SeriesName)}", nameof(items)));
return exceptions;
}

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AudibleApi" Version="8.4.3.1" />
<PackageReference Include="AudibleApi" Version="9.1.2.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
@@ -10,14 +10,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="7.3.0.1" />
<PackageReference Include="Dinah.EntityFrameworkCore" Version="7.3.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
<PackageReference Include="Dinah.EntityFrameworkCore" Version="8.0.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -23,9 +23,11 @@ namespace DtoImporterService
loadLocal_categories();
// upsert
//Import item may not have no (null) categories
var categoryLadders = importItems
.Where(i => i.DtoItem.CategoryLadders is not null)
.SelectMany(i => i.DtoItem.CategoryLadders)
.Select(cl => cl.Ladder)
.Select(cl => cl?.Ladder)
.Where(l => l?.Length > 0)
.ToList();

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -60,6 +60,11 @@ namespace FileLiberator
config.LameMatchSourceBR,
chapters);
if (m4bBook.AppleTags.Tracks is (int trackNum, int trackCount))
{
lameConfig.ID3.Track = trackCount > 0 ? $"{trackNum}/{trackCount}" : trackNum.ToString();
}
using var mp3File = File.Open(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite);
try
{

View File

@@ -375,8 +375,15 @@ namespace FileLiberator
{
if (Configuration.Instance.AllowLibationFixup)
{
e = OnRequestCoverArt();
abDownloader.SetCoverArt(e);
try
{
e = OnRequestCoverArt();
abDownloader.SetCoverArt(e);
}
catch (Exception ex)
{
Serilog.Log.Logger.Error(ex, "Failed to retrieve cover art from server.");
}
}
if (e is not null)

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@@ -50,7 +50,7 @@ namespace FileManager
lock (fsCacheLocker)
{
fsCache.Clear();
fsCache.AddRange(FileUtility.SaferEnumerateFiles(RootDirectory, SearchPattern, SearchOption));
fsCache.AddRange(SafestEnumerateFiles(RootDirectory));
}
}
@@ -59,7 +59,7 @@ namespace FileManager
Stop();
lock (fsCacheLocker)
fsCache.AddRange(FileUtility.SaferEnumerateFiles(RootDirectory, SearchPattern, SearchOption));
fsCache.AddRange(SafestEnumerateFiles(RootDirectory));
directoryChangesEvents = new BlockingCollection<FileSystemEventArgs>();
fileSystemWatcher = new FileSystemWatcher(RootDirectory)
@@ -152,11 +152,23 @@ namespace FileManager
if (Path.GetFileName(path).Contains("LibationContext.db") || !File.Exists(path) && !Directory.Exists(path))
return;
if (File.GetAttributes(path).HasFlag(FileAttributes.Directory))
AddUniqueFiles(FileUtility.SaferEnumerateFiles(path, SearchPattern, SearchOption));
AddUniqueFiles(SafestEnumerateFiles(path));
else
AddUniqueFile(path);
}
private IEnumerable<LongPath> SafestEnumerateFiles(string path)
{
try
{
return FileUtility.SaferEnumerateFiles(path, SearchPattern, SearchOption);
}
catch
{
return [];
}
}
private void AddUniqueFiles(IEnumerable<LongPath> newFiles)
{
foreach (var file in newFiles)

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="7.3.0.1" />
<PackageReference Include="Polly" Version="7.2.4" />
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
<PackageReference Include="Polly" Version="8.4.0" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<!--Avalonia doesen't support TrimMode=link currently,but we are working on that https://github.com/AvaloniaUI/Avalonia/issues/6892 -->
<TrimMode>copyused</TrimMode>
@@ -21,9 +21,13 @@
<ApplicationIcon>hangover.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
</ItemGroup>
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\bin\Avalonia\Debug</OutputPath>
@@ -67,13 +71,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.3" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.3" />
<PackageReference Include="Avalonia" Version="11.0.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.3" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.3" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.3" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.3" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.5" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.5" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.5" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<AssemblyName>Hangover</AssemblyName>
<UseWindowsForms>true</UseWindowsForms>
@@ -15,6 +15,10 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
</ItemGroup>
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{03C8835F-936C-4AF7-87AE-FF92BDBE8B9B}"
ProjectSection(SolutionItems) = preProject
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

View File

@@ -107,7 +107,7 @@ namespace LibationAvalonia.Controls
if (known is Configuration.KnownDirectories.None)
{
directoryState.CustomDir = noSubDir;
directoryState.CustomDir = directory;
directoryState.CustomChecked = true;
}
else

View File

@@ -27,6 +27,6 @@
Margin="5"
Padding="30,3,30,3"
Content="Save"
Command="{Binding SaveButtonAsync}" />
Click="Save_Click" />
</Grid>
</Window>

View File

@@ -1,11 +1,9 @@
using Avalonia.Controls;
using LibationFileManager;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LibationAvalonia.Dialogs
{
public partial class LibationFilesDialog : Window
public partial class LibationFilesDialog : DialogWindow
{
private class DirSelectOptions
{
@@ -18,28 +16,26 @@ namespace LibationAvalonia.Dialogs
public string Directory { get; set; } = Configuration.GetKnownDirectoryPath(Configuration.KnownDirectories.UserProfile);
}
private DirSelectOptions dirSelectOptions;
private readonly DirSelectOptions dirSelectOptions;
public string SelectedDirectory => dirSelectOptions.Directory;
public DialogResult DialogResult { get; private set; }
public LibationFilesDialog()
public LibationFilesDialog() : base(saveAndRestorePosition: false)
{
InitializeComponent();
DataContext = dirSelectOptions = new();
}
public async Task SaveButtonAsync()
public async void Save_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var libationDir = dirSelectOptions.Directory;
if (!System.IO.Directory.Exists(libationDir))
if (!System.IO.Directory.Exists(SelectedDirectory))
{
await MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + libationDir, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error, saveAndRestorePosition: false);
await MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + SelectedDirectory, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error, saveAndRestorePosition: false);
return;
}
DialogResult = DialogResult.OK;
Close(DialogResult);
await SaveAndCloseAsync();
}
}
}

View File

@@ -2,8 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="750"
MinWidth="900" MinHeight="750"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="200"
MinWidth="900" MinHeight="200"
Width="900" Height="750"
x:Class="LibationAvalonia.Dialogs.SettingsDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
@@ -46,39 +46,41 @@
</TabControl.Styles>
<TabItem>
<TabItem.Header>
<TextBlock Text="Important Settings"/>
</TabItem.Header>
<settings:Important DataContext="{CompiledBinding ImportantSettings}" />
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:Important DataContext="{CompiledBinding ImportantSettings}" />
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Text="Import Library"/>
</TabItem.Header>
<settings:Import DataContext="{CompiledBinding ImportSettings}" />
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:Import DataContext="{CompiledBinding ImportSettings}" />
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Text="Download/Decrypt"/>
</TabItem.Header>
<settings:DownloadDecrypt DataContext="{CompiledBinding DownloadDecryptSettings}" />
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:DownloadDecrypt DataContext="{CompiledBinding DownloadDecryptSettings}" />
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Text="Audio File Settings"/>
</TabItem.Header>
<settings:Audio DataContext="{CompiledBinding AudioSettings}" />
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:Audio DataContext="{CompiledBinding AudioSettings}" />
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationIcon>Assets/libation.ico</ApplicationIcon>
@@ -14,6 +14,10 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
</ItemGroup>
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
@@ -69,14 +73,14 @@
<UpToDateCheckInput Remove="Controls\GroupBox.axaml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.3" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
<PackageReference Include="Avalonia" Version="11.0.3" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.3" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.3" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.3" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.3" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.3" />
<ItemGroup>
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.5" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
<PackageReference Include="Avalonia" Version="11.0.5" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.5" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.5" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -265,7 +265,7 @@ namespace LibationAvalonia.ViewModels
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
{
var quality
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High && LibraryBook.Book.PictureLarge is not null
? new PictureDefinition(LibraryBook.Book.PictureLarge, PictureSize.Native)
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishReadyToRun>true</PublishReadyToRun>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -11,6 +11,10 @@
<IsPublishable>True</IsPublishable>
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
</ItemGroup>
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,126 +8,136 @@ using Dinah.Core;
using System.Threading.Tasks;
using System.Threading;
using FileManager;
using AaxDecrypter;
#nullable enable
namespace LibationFileManager
{
public abstract class AudibleFileStorage
{
protected abstract LongPath? GetFilePathCustom(string productId);
protected abstract List<LongPath> GetFilePathsCustom(string productId);
public abstract class AudibleFileStorage
{
protected abstract LongPath? GetFilePathCustom(string productId);
protected abstract List<LongPath> GetFilePathsCustom(string productId);
#region static
public static LongPath DownloadsInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DownloadsInProgress")).FullName;
public static LongPath DecryptInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DecryptInProgress")).FullName;
#region static
public static LongPath DownloadsInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DownloadsInProgress")).FullName;
public static LongPath DecryptInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DecryptInProgress")).FullName;
static AudibleFileStorage()
static AudibleFileStorage()
{
//Clean up any partially-decrypted files from previous Libation instances.
//Do no clean DownloadsInProgressDirectory because those files are resumable
foreach (var tempFile in Directory.EnumerateFiles(DecryptInProgressDirectory))
FileUtility.SaferDelete(tempFile);
//Do not clean DownloadsInProgressDirectory. Those files are resumable.
try
{
foreach (var tempFile in FileUtility.SaferEnumerateFiles(DecryptInProgressDirectory))
FileUtility.SaferDelete(tempFile);
}
catch (Exception ex)
{
// since this is a static constructor which may be called very early, do not assume Serilog is initialized
try { Serilog.Log.Error(ex, "Error cleaning up partially-decrypted files"); }
catch { }
}
}
private static AaxcFileStorage AAXC { get; } = new AaxcFileStorage();
public static bool AaxcExists(string productId) => AAXC.Exists(productId);
public static bool AaxcExists(string productId) => AAXC.Exists(productId);
public static AudioFileStorage Audio { get; } = new AudioFileStorage();
public static AudioFileStorage Audio { get; } = new AudioFileStorage();
public static LongPath BooksDirectory
{
get
{
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
Configuration.Instance.Books = Path.Combine(Configuration.UserProfile, "Books");
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
}
}
#endregion
public static LongPath BooksDirectory
{
get
{
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
Configuration.Instance.Books = Path.Combine(Configuration.UserProfile, "Books");
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
}
}
#endregion
#region instance
private FileType FileType { get; }
private string regexTemplate { get; }
#region instance
private FileType FileType { get; }
private string regexTemplate { get; }
protected AudibleFileStorage(FileType fileType)
{
FileType = fileType;
protected AudibleFileStorage(FileType fileType)
{
FileType = fileType;
var extAggr = FileTypes.GetExtensions(FileType).Aggregate((a, b) => $"{a}|{b}");
regexTemplate = $@"{{0}}.*?\.({extAggr})$";
}
var extAggr = FileTypes.GetExtensions(FileType).Aggregate((a, b) => $"{a}|{b}");
regexTemplate = $@"{{0}}.*?\.({extAggr})$";
}
protected LongPath? GetFilePath(string productId)
{
// primary lookup
var cachedFile = FilePathCache.GetFirstPath(productId, FileType);
if (cachedFile is not null && File.Exists(cachedFile))
return cachedFile;
protected LongPath? GetFilePath(string productId)
{
// primary lookup
var cachedFile = FilePathCache.GetFirstPath(productId, FileType);
if (cachedFile is not null && File.Exists(cachedFile))
return cachedFile;
// secondary lookup attempt
var firstOrNull = GetFilePathCustom(productId);
if (firstOrNull is not null)
FilePathCache.Insert(productId, firstOrNull);
// secondary lookup attempt
var firstOrNull = GetFilePathCustom(productId);
if (firstOrNull is not null)
FilePathCache.Insert(productId, firstOrNull);
return firstOrNull;
}
return firstOrNull;
}
public List<LongPath> GetPaths(string productId)
=> GetFilePathsCustom(productId);
public List<LongPath> GetPaths(string productId)
=> GetFilePathsCustom(productId);
protected Regex GetBookSearchRegex(string productId)
{
var pattern = string.Format(regexTemplate, productId);
return new Regex(pattern, RegexOptions.IgnoreCase);
}
#endregion
}
protected Regex GetBookSearchRegex(string productId)
{
var pattern = string.Format(regexTemplate, productId);
return new Regex(pattern, RegexOptions.IgnoreCase);
}
#endregion
}
internal class AaxcFileStorage : AudibleFileStorage
{
internal AaxcFileStorage() : base(FileType.AAXC) { }
internal class AaxcFileStorage : AudibleFileStorage
{
internal AaxcFileStorage() : base(FileType.AAXC) { }
protected override LongPath? GetFilePathCustom(string productId)
=> GetFilePathsCustom(productId).FirstOrDefault();
protected override LongPath? GetFilePathCustom(string productId)
=> GetFilePathsCustom(productId).FirstOrDefault();
protected override List<LongPath> GetFilePathsCustom(string productId)
{
var regex = GetBookSearchRegex(productId);
return FileUtility
.SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
.Where(s => regex.IsMatch(s)).ToList();
}
protected override List<LongPath> GetFilePathsCustom(string productId)
{
var regex = GetBookSearchRegex(productId);
return FileUtility
.SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
.Where(s => regex.IsMatch(s)).ToList();
}
public bool Exists(string productId) => GetFilePath(productId) is not null;
}
public bool Exists(string productId) => GetFilePath(productId) is not null;
}
public class AudioFileStorage : AudibleFileStorage
{
internal AudioFileStorage() : base(FileType.Audio)
=> BookDirectoryFiles ??= newBookDirectoryFiles();
public class AudioFileStorage : AudibleFileStorage
{
internal AudioFileStorage() : base(FileType.Audio)
=> BookDirectoryFiles ??= newBookDirectoryFiles();
private static BackgroundFileSystem? BookDirectoryFiles { get; set; }
private static object bookDirectoryFilesLocker { get; } = new();
private static BackgroundFileSystem? BookDirectoryFiles { get; set; }
private static object bookDirectoryFilesLocker { get; } = new();
private static EnumerationOptions enumerationOptions { get; } = new()
{
RecurseSubdirectories = true,
IgnoreInaccessible = true,
MatchCasing = MatchCasing.CaseInsensitive
AttributesToSkip = FileAttributes.Hidden,
};
protected override LongPath? GetFilePathCustom(string productId)
=> GetFilePathsCustom(productId).FirstOrDefault();
=> GetFilePathsCustom(productId).FirstOrDefault();
private static BackgroundFileSystem newBookDirectoryFiles()
=> new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
private static BackgroundFileSystem newBookDirectoryFiles()
=> new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
protected override List<LongPath> GetFilePathsCustom(string productId)
{
// If user changed the BooksDirectory: reinitialize
lock (bookDirectoryFilesLocker)
if (BooksDirectory != BookDirectoryFiles?.RootDirectory)
BookDirectoryFiles = newBookDirectoryFiles();
{
// If user changed the BooksDirectory: reinitialize
lock (bookDirectoryFilesLocker)
if (BooksDirectory != BookDirectoryFiles?.RootDirectory)
BookDirectoryFiles = newBookDirectoryFiles();
var regex = GetBookSearchRegex(productId);
@@ -135,44 +145,60 @@ namespace LibationFileManager
//using both the file system and the file path cache
return
FilePathCache
.GetFiles(productId)
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
.Select(c => c.path)
.Union(BookDirectoryFiles.FindFiles(regex))
.ToList();
}
.GetFiles(productId)
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
.Select(c => c.path)
.Union(BookDirectoryFiles.FindFiles(regex))
.ToList();
}
public void Refresh()
{
if (BookDirectoryFiles is null)
lock (bookDirectoryFilesLocker)
BookDirectoryFiles = newBookDirectoryFiles();
else
BookDirectoryFiles?.RefreshFiles();
}
public void Refresh()
{
if (BookDirectoryFiles is null)
lock (bookDirectoryFilesLocker)
BookDirectoryFiles = newBookDirectoryFiles();
else
BookDirectoryFiles?.RefreshFiles();
}
public LongPath? GetPath(string productId) => GetFilePath(productId);
public LongPath? GetPath(string productId) => GetFilePath(productId);
public static async IAsyncEnumerable<FilePathCache.CacheEntry> FindAudiobooksAsync(LongPath searchDirectory, [EnumeratorCancellation] CancellationToken cancellationToken)
{
ArgumentValidator.EnsureNotNull(searchDirectory, nameof(searchDirectory));
foreach (LongPath path in Directory.EnumerateFiles(searchDirectory, "*.M4B", enumerationOptions))
foreach (LongPath path in Directory.EnumerateFiles(searchDirectory, "*.*", enumerationOptions))
{
if (cancellationToken.IsCancellationRequested)
yield break;
if (getFormatByExtension(path) is not OutputFormat format)
continue;
FilePathCache.CacheEntry? audioFile = default;
try
{
using var fileStream = File.OpenRead(path);
if (format is OutputFormat.M4b)
{
var tags = await Task.Run(() => AAXClean.AppleTags.FromFile(path));
var mp4File = await Task.Run(() => new AAXClean.Mp4File(fileStream), cancellationToken);
if (tags?.Asin is not null)
audioFile = new FilePathCache.CacheEntry(tags.Asin, FileType.Audio, path);
}
else
{
using var fileStream = File.OpenRead(path);
var id3 = await Task.Run(() => NAudio.Lame.ID3.Id3Tag.Create(fileStream));
if (mp4File?.AppleTags?.Asin is not null)
audioFile = new FilePathCache.CacheEntry(mp4File.AppleTags.Asin, FileType.Audio, path);
var asin = id3?.Children
.OfType<NAudio.Lame.ID3.TXXXFrame>()
.FirstOrDefault(f => f.FieldName == "AUDIBLE_ASIN")
?.FieldValue;
if (!string.IsNullOrWhiteSpace(asin))
audioFile = new FilePathCache.CacheEntry(asin, FileType.Audio, path);
}
}
catch (Exception ex)
{
@@ -186,6 +212,15 @@ namespace LibationFileManager
if (audioFile is not null)
yield return audioFile;
}
static OutputFormat? getFormatByExtension(string path)
{
var ext = Path.GetExtension(path).ToLower();
return ext == ".mp3" ? OutputFormat.Mp3
: ext == ".m4b" ? OutputFormat.M4b
: null;
}
}
}
}

View File

@@ -6,6 +6,7 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Serilog;
using Dinah.Core.Logging;
using System.Diagnostics;
#nullable enable
namespace LibationFileManager
@@ -75,17 +76,19 @@ namespace LibationFileManager
const string appsettings_filename = "appsettings.json";
//Possible appsettings.json locations, in order of preference.
string[] possibleAppsettingsFiles = new[]
string[] possibleAppsettingsDirectories = new[]
{
Path.Combine(ProcessDirectory, appsettings_filename),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation", appsettings_filename),
Path.Combine(UserProfile, appsettings_filename),
Path.Combine(Path.GetTempPath(), "Libation", appsettings_filename)
ProcessDirectory,
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation"),
UserProfile,
Path.Combine(Path.GetTempPath(), "Libation")
};
//Try to find and validate appsettings.json in each folder
foreach (var appsettingsFile in possibleAppsettingsFiles)
foreach (var dir in possibleAppsettingsDirectories)
{
var appsettingsFile = Path.Combine(dir, appsettings_filename);
if (File.Exists(appsettingsFile))
{
try
@@ -104,10 +107,13 @@ namespace LibationFileManager
//Valid appsettings.json not found. Try to create it in each folder.
var endingContents = new JObject { { LIBATION_FILES_KEY, UserProfile } }.ToString(Formatting.Indented);
foreach (var appsettingsFile in possibleAppsettingsFiles)
foreach (var dir in possibleAppsettingsDirectories)
{
var appsettingsFile = Path.Combine(dir, appsettings_filename);
try
{
Directory.CreateDirectory(dir);
File.WriteAllText(appsettingsFile, endingContents);
return appsettingsFile;
}
@@ -121,16 +127,56 @@ namespace LibationFileManager
}
private static string getLibationFilesSettingFromJson()
{
// do not check whether directory exists. special/meta directory (eg: AppDir) is valid
// verify from live file. no try/catch. want failures to be visible
var jObjFinal = JObject.Parse(File.ReadAllText(AppsettingsJsonFile));
{
// do not check whether directory exists. special/meta directory (eg: AppDir) is valid
// verify from live file. no try/catch. want failures to be visible
var jObjFinal = JObject.Parse(File.ReadAllText(AppsettingsJsonFile));
if (jObjFinal[LIBATION_FILES_KEY]?.Value<string>() is not string valueFinal)
throw new InvalidDataException($"{LIBATION_FILES_KEY} not found in {AppsettingsJsonFile}");
return valueFinal;
}
if (IsWindows)
{
valueFinal = Environment.ExpandEnvironmentVariables(valueFinal);
}
else
{
//If the shell command fails and returns null, proceed with the verbatim
//LIBATION_FILES_KEY path and hope for the best. If Libation can't find
//anything at this path it will set LIBATION_FILES_KEY to UserProfile
valueFinal = runShellCommand("echo " + valueFinal) ?? valueFinal;
}
return valueFinal;
static string? runShellCommand(string command)
{
var psi = new ProcessStartInfo
{
FileName = "/bin/sh",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
ArgumentList =
{
"-c",
command
}
};
try
{
var proc = Process.Start(psi);
proc?.WaitForExit();
return proc?.StandardOutput?.ReadToEnd()?.Trim();
}
catch (Exception e)
{
Serilog.Log.Error(e, "Failed to run shell command. {Arguments}", psi.ArgumentList);
return null;
}
}
}
public static void SetLibationFiles(string directory)
{

View File

@@ -95,9 +95,9 @@ namespace LibationFileManager
var assembly = CurrentDomain_AssemblyResolve_internal(asmName, here: here);
lowEffortCache[key] = assembly;
//Let the runtime handle any dll not found exceptions.
// Let the runtime handle any dll not found exceptions
if (assembly is null)
Serilog.Log.Logger.Error($"Unable to load module {args.Name}");
Serilog.Log.Logger.Warning($"Unable to load module {args.Name}");
return assembly;
}

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="NameParserSharp" Version="1.5.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
</ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
@@ -9,7 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="LuceneNet303r2" Version="3.0.3.5" />
<PackageReference Include="LuceneNet303r2" Version="3.0.3.8" />
</ItemGroup>
<ItemGroup>

View File

@@ -133,7 +133,7 @@ namespace LibationUiBase.GridView
private string GetTooltip()
{
if (IsSeries)
return Expanded ? "Click to Collpase" : "Click to Expand";
return Expanded ? "Click to Collapse" : "Click to Expand";
if (IsUnavailable)
return "This book cannot be downloaded\nbecause it wasn't found during\nthe most recent library scan";

View File

@@ -95,20 +95,4 @@ public class GridContextMenu
return TemplateEditor<T>.CreateFilenameEditor(Configuration.Instance.Books, existingTemplate, folderDto, fileDto);
}
}
class Command : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public void Execute(object parameter)
{
throw new NotImplementedException();
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPublishable>true</IsPublishable>
<PublishReadyToRun>true</PublishReadyToRun>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,46 @@
using System.Windows.Forms;
namespace LibationWinForms
{
public class AccessibleDataGridViewButtonCell : DataGridViewButtonCell
{
private string accessibilityDescription;
protected string AccessibilityName { get; }
/// <summary>
/// Get or set description for accessibility. eg: screen readers. Also sets the ToolTipText
/// </summary>
protected string AccessibilityDescription
{
get => accessibilityDescription;
set
{
accessibilityDescription = value;
ToolTipText = value;
}
}
protected override AccessibleObject CreateAccessibilityInstance() => new ButtonCellAccessibilityObject(this, name: AccessibilityName, description: AccessibilityDescription);
public AccessibleDataGridViewButtonCell(string accessibilityName) : base()
{
AccessibilityName = accessibilityName;
}
protected class ButtonCellAccessibilityObject : DataGridViewButtonCellAccessibleObject
{
private string _name;
public override string Name => _name;
private string _description;
public override string Description => _description;
public ButtonCellAccessibilityObject(DataGridViewCell owner, string name, string description) : base(owner)
{
_name = name;
_description = description;
}
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Windows.Forms;
namespace LibationWinForms
{
internal class AccessibleDataGridViewTextBoxCell : DataGridViewTextBoxCell
{
private string accessibilityDescription;
protected string AccessibilityName { get; }
/// <summary>
/// Get or set description for accessibility. eg: screen readers. Also sets the ToolTipText
/// </summary>
protected string AccessibilityDescription
{
get => accessibilityDescription;
set
{
accessibilityDescription = value;
ToolTipText = value;
}
}
protected override AccessibleObject CreateAccessibilityInstance() => new TextBoxCellAccessibilityObject(this, name: AccessibilityName, description: AccessibilityDescription);
public AccessibleDataGridViewTextBoxCell(string accessibilityName) : base()
{
AccessibilityName = accessibilityName;
}
protected class TextBoxCellAccessibilityObject : DataGridViewTextBoxCellAccessibleObject
{
private string _name;
public override string Name => _name;
private string _description;
public override string Description => _description;
public TextBoxCellAccessibilityObject(DataGridViewCell owner, string name, string description) : base(owner)
{
_name = name;
_description = description;
}
}
}
}

View File

@@ -51,13 +51,13 @@ namespace LibationWinForms.Dialogs
private void AddAccountToGrid(Account account)
{
int row = dataGridView1.Rows.Add(
"X",
"Export",
account.LibraryScan,
account.AccountId,
account.Locale.Name,
account.AccountName);
var row = dataGridView1.Rows.Add(
"X",
"Export",
account.LibraryScan,
account.AccountId,
account.Locale.Name,
account.AccountName);
dataGridView1[COL_Export, row].ToolTipText = "Export account authorization to audible-cli";
}

View File

@@ -24,23 +24,39 @@ namespace LibationWinForms.Dialogs
private const string COL_MoveUp = nameof(MoveUp);
private const string COL_MoveDown = nameof(MoveDown);
internal class DisableButtonCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
internal class DisableButtonCell : AccessibleDataGridViewButtonCell
{
private int LastRowIndex => DataGridView.Rows[^1].IsNewRow ? DataGridView.Rows[^1].Index - 1 : DataGridView.Rows[^1].Index;
public DisableButtonCell() : base("Edit Filter button") { }
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if ((OwningColumn.Name == COL_MoveUp && rowIndex == 0)
|| (OwningColumn.Name == COL_MoveDown && rowIndex == LastRowIndex)
|| OwningRow.IsNewRow)
{
var isMoveUp = OwningColumn.Name == COL_MoveUp;
var isMoveDown = OwningColumn.Name == COL_MoveDown;
var isDelete = OwningColumn.Name == COL_Delete;
var isNewRow = OwningRow.IsNewRow;
if (isNewRow
|| (isMoveUp && rowIndex == 0)
|| (isMoveDown && rowIndex == LastRowIndex))
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts ^ (DataGridViewPaintParts.ContentBackground | DataGridViewPaintParts.ContentForeground | DataGridViewPaintParts.SelectionBackground));
ButtonRenderer.DrawButton(graphics, cellBounds, value as string, cellStyle.Font, false, System.Windows.Forms.VisualStyles.PushButtonState.Disabled);
}
}
else
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
}
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
int LastRowIndex => DataGridView.Rows[^1].IsNewRow ? DataGridView.Rows[^1].Index - 1 : DataGridView.Rows[^1].Index;
if (isMoveUp)
AccessibilityDescription = "Move up";
else if (isMoveDown)
AccessibilityDescription = "Move down";
else if (isDelete)
AccessibilityDescription = "Delete";
}
}
}
public EditQuickFilters()

View File

@@ -229,7 +229,7 @@
badBookGb.Controls.Add(badBookAskRb);
badBookGb.Location = new System.Drawing.Point(7, 6);
badBookGb.Name = "badBookGb";
badBookGb.Size = new System.Drawing.Size(836, 76);
badBookGb.Size = new System.Drawing.Size(841, 76);
badBookGb.TabIndex = 13;
badBookGb.TabStop = false;
badBookGb.Text = "[bad book desc]";
@@ -397,6 +397,7 @@
//
// tab1ImportantSettings
//
tab1ImportantSettings.AutoScroll = true;
tab1ImportantSettings.Controls.Add(groupBox1);
tab1ImportantSettings.Controls.Add(booksGb);
tab1ImportantSettings.Controls.Add(logsBtn);
@@ -412,6 +413,7 @@
//
// groupBox1
//
groupBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
groupBox1.Controls.Add(applyDisplaySettingsBtn);
groupBox1.Controls.Add(gridScaleFactorLbl);
groupBox1.Controls.Add(gridScaleFactorTbar);
@@ -426,6 +428,7 @@
//
// applyDisplaySettingsBtn
//
applyDisplaySettingsBtn.Anchor = System.Windows.Forms.AnchorStyles.Right;
applyDisplaySettingsBtn.Location = new System.Drawing.Point(689, 26);
applyDisplaySettingsBtn.Name = "applyDisplaySettingsBtn";
applyDisplaySettingsBtn.Size = new System.Drawing.Size(148, 34);
@@ -554,6 +557,7 @@
//
// tab2ImportLibrary
//
tab2ImportLibrary.AutoScroll = true;
tab2ImportLibrary.Controls.Add(autoDownloadEpisodesCb);
tab2ImportLibrary.Controls.Add(autoScanCb);
tab2ImportLibrary.Controls.Add(showImportedStatsCb);
@@ -599,6 +603,7 @@
//
// tab3DownloadDecrypt
//
tab3DownloadDecrypt.AutoScroll = true;
tab3DownloadDecrypt.Controls.Add(saveMetadataToFileCbox);
tab3DownloadDecrypt.Controls.Add(useCoverAsFolderIconCb);
tab3DownloadDecrypt.Controls.Add(inProgressFilesGb);
@@ -764,6 +769,7 @@
//
// tab4AudioFileOptions
//
tab4AudioFileOptions.AutoScroll = true;
tab4AudioFileOptions.Controls.Add(fileDownloadQualityCb);
tab4AudioFileOptions.Controls.Add(fileDownloadQualityLbl);
tab4AudioFileOptions.Controls.Add(combineNestedChapterTitlesCbox);
@@ -845,7 +851,7 @@
audiobookFixupsGb.Controls.Add(stripAudibleBrandingCbox);
audiobookFixupsGb.Location = new System.Drawing.Point(6, 200);
audiobookFixupsGb.Name = "audiobookFixupsGb";
audiobookFixupsGb.Size = new System.Drawing.Size(403, 182);
audiobookFixupsGb.Size = new System.Drawing.Size(385, 182);
audiobookFixupsGb.TabIndex = 19;
audiobookFixupsGb.TabStop = false;
audiobookFixupsGb.Text = "Audiobook Fix-ups";
@@ -872,6 +878,7 @@
//
// chapterTitleTemplateGb
//
chapterTitleTemplateGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateBtn);
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateTb);
chapterTitleTemplateGb.Location = new System.Drawing.Point(3, 388);
@@ -903,6 +910,7 @@
//
// lameOptionsGb
//
lameOptionsGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lameOptionsGb.Controls.Add(label20);
lameOptionsGb.Controls.Add(label21);
lameOptionsGb.Controls.Add(encoderQualityCb);
@@ -912,9 +920,9 @@
lameOptionsGb.Controls.Add(label1);
lameOptionsGb.Controls.Add(lameQualityGb);
lameOptionsGb.Controls.Add(groupBox2);
lameOptionsGb.Location = new System.Drawing.Point(415, 6);
lameOptionsGb.Location = new System.Drawing.Point(397, 6);
lameOptionsGb.Name = "lameOptionsGb";
lameOptionsGb.Size = new System.Drawing.Size(433, 376);
lameOptionsGb.Size = new System.Drawing.Size(450, 376);
lameOptionsGb.TabIndex = 14;
lameOptionsGb.TabStop = false;
lameOptionsGb.Text = "Mp3 Encoding Options";
@@ -930,6 +938,7 @@
//
// label21
//
label21.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label21.AutoSize = true;
label21.Location = new System.Drawing.Point(239, 89);
label21.Name = "label21";
@@ -939,33 +948,37 @@
//
// encoderQualityCb
//
encoderQualityCb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
encoderQualityCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
encoderQualityCb.FormattingEnabled = true;
encoderQualityCb.Location = new System.Drawing.Point(337, 86);
encoderQualityCb.Name = "encoderQualityCb";
encoderQualityCb.Size = new System.Drawing.Size(90, 23);
encoderQualityCb.Size = new System.Drawing.Size(107, 23);
encoderQualityCb.TabIndex = 2;
//
// maxSampleRateCb
//
maxSampleRateCb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
maxSampleRateCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
maxSampleRateCb.FormattingEnabled = true;
maxSampleRateCb.Location = new System.Drawing.Point(119, 86);
maxSampleRateCb.Name = "maxSampleRateCb";
maxSampleRateCb.Size = new System.Drawing.Size(101, 23);
maxSampleRateCb.Size = new System.Drawing.Size(76, 23);
maxSampleRateCb.TabIndex = 2;
//
// lameDownsampleMonoCbox
//
lameDownsampleMonoCbox.Location = new System.Drawing.Point(237, 30);
lameDownsampleMonoCbox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
lameDownsampleMonoCbox.Location = new System.Drawing.Point(247, 29);
lameDownsampleMonoCbox.Name = "lameDownsampleMonoCbox";
lameDownsampleMonoCbox.Size = new System.Drawing.Size(184, 34);
lameDownsampleMonoCbox.Size = new System.Drawing.Size(197, 34);
lameDownsampleMonoCbox.TabIndex = 1;
lameDownsampleMonoCbox.Text = "Downsample stereo to mono?\r\n(Recommended)\r\n";
lameDownsampleMonoCbox.UseVisualStyleBackColor = true;
//
// lameBitrateGb
//
lameBitrateGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lameBitrateGb.Controls.Add(LameMatchSourceBRCbox);
lameBitrateGb.Controls.Add(lameConstantBitrateCbox);
lameBitrateGb.Controls.Add(label7);
@@ -977,15 +990,16 @@
lameBitrateGb.Controls.Add(lameBitrateTb);
lameBitrateGb.Location = new System.Drawing.Point(6, 116);
lameBitrateGb.Name = "lameBitrateGb";
lameBitrateGb.Size = new System.Drawing.Size(421, 113);
lameBitrateGb.Size = new System.Drawing.Size(438, 113);
lameBitrateGb.TabIndex = 0;
lameBitrateGb.TabStop = false;
lameBitrateGb.Text = "Bitrate";
//
// LameMatchSourceBRCbox
//
LameMatchSourceBRCbox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
LameMatchSourceBRCbox.AutoSize = true;
LameMatchSourceBRCbox.Location = new System.Drawing.Point(275, 76);
LameMatchSourceBRCbox.Location = new System.Drawing.Point(254, 76);
LameMatchSourceBRCbox.Name = "LameMatchSourceBRCbox";
LameMatchSourceBRCbox.Size = new System.Drawing.Size(140, 19);
LameMatchSourceBRCbox.TabIndex = 3;
@@ -1005,6 +1019,7 @@
//
// label7
//
label7.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label7.AutoSize = true;
label7.BackColor = System.Drawing.SystemColors.ControlLightLight;
label7.Location = new System.Drawing.Point(390, 52);
@@ -1015,6 +1030,7 @@
//
// label6
//
label6.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label6.AutoSize = true;
label6.BackColor = System.Drawing.SystemColors.ControlLightLight;
label6.Location = new System.Drawing.Point(309, 52);
@@ -1025,6 +1041,7 @@
//
// label5
//
label5.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label5.AutoSize = true;
label5.BackColor = System.Drawing.SystemColors.ControlLightLight;
label5.Location = new System.Drawing.Point(228, 52);
@@ -1035,6 +1052,7 @@
//
// label4
//
label4.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label4.AutoSize = true;
label4.BackColor = System.Drawing.SystemColors.ControlLightLight;
label4.Location = new System.Drawing.Point(147, 52);
@@ -1045,6 +1063,7 @@
//
// label11
//
label11.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label11.AutoSize = true;
label11.BackColor = System.Drawing.SystemColors.ControlLightLight;
label11.Location = new System.Drawing.Point(10, 52);
@@ -1055,6 +1074,7 @@
//
// label3
//
label3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label3.AutoSize = true;
label3.BackColor = System.Drawing.SystemColors.ControlLightLight;
label3.Location = new System.Drawing.Point(71, 52);
@@ -1071,7 +1091,7 @@
lameBitrateTb.Maximum = 320;
lameBitrateTb.Minimum = 16;
lameBitrateTb.Name = "lameBitrateTb";
lameBitrateTb.Size = new System.Drawing.Size(409, 45);
lameBitrateTb.Size = new System.Drawing.Size(408, 45);
lameBitrateTb.SmallChange = 8;
lameBitrateTb.TabIndex = 0;
lameBitrateTb.TickFrequency = 16;
@@ -1090,6 +1110,7 @@
//
// lameQualityGb
//
lameQualityGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lameQualityGb.Controls.Add(label19);
lameQualityGb.Controls.Add(label18);
lameQualityGb.Controls.Add(label17);
@@ -1105,13 +1126,14 @@
lameQualityGb.Controls.Add(lameVBRQualityTb);
lameQualityGb.Location = new System.Drawing.Point(6, 235);
lameQualityGb.Name = "lameQualityGb";
lameQualityGb.Size = new System.Drawing.Size(421, 109);
lameQualityGb.Size = new System.Drawing.Size(438, 109);
lameQualityGb.TabIndex = 0;
lameQualityGb.TabStop = false;
lameQualityGb.Text = "Quality";
//
// label19
//
label19.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label19.AutoSize = true;
label19.Location = new System.Drawing.Point(349, 52);
label19.Name = "label19";
@@ -1121,6 +1143,7 @@
//
// label18
//
label18.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label18.AutoSize = true;
label18.Location = new System.Drawing.Point(307, 52);
label18.Name = "label18";
@@ -1130,6 +1153,7 @@
//
// label17
//
label17.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label17.AutoSize = true;
label17.Location = new System.Drawing.Point(265, 52);
label17.Name = "label17";
@@ -1139,6 +1163,7 @@
//
// label16
//
label16.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label16.AutoSize = true;
label16.Location = new System.Drawing.Point(223, 52);
label16.Name = "label16";
@@ -1148,6 +1173,7 @@
//
// label12
//
label12.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label12.AutoSize = true;
label12.Location = new System.Drawing.Point(182, 52);
label12.Name = "label12";
@@ -1157,6 +1183,7 @@
//
// label15
//
label15.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label15.AutoSize = true;
label15.Location = new System.Drawing.Point(140, 52);
label15.Name = "label15";
@@ -1166,6 +1193,7 @@
//
// label9
//
label9.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label9.AutoSize = true;
label9.Location = new System.Drawing.Point(97, 52);
label9.Name = "label9";
@@ -1175,6 +1203,7 @@
//
// label8
//
label8.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label8.AutoSize = true;
label8.Location = new System.Drawing.Point(391, 52);
label8.Name = "label8";
@@ -1202,6 +1231,7 @@
//
// label14
//
label14.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label14.AutoSize = true;
label14.Location = new System.Drawing.Point(56, 52);
label14.Name = "label14";
@@ -1211,6 +1241,7 @@
//
// label2
//
label2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label2.AutoSize = true;
label2.Location = new System.Drawing.Point(14, 52);
label2.Name = "label2";
@@ -1225,25 +1256,27 @@
lameVBRQualityTb.Location = new System.Drawing.Point(10, 22);
lameVBRQualityTb.Maximum = 9;
lameVBRQualityTb.Name = "lameVBRQualityTb";
lameVBRQualityTb.Size = new System.Drawing.Size(405, 45);
lameVBRQualityTb.Size = new System.Drawing.Size(404, 45);
lameVBRQualityTb.TabIndex = 0;
lameVBRQualityTb.Value = 9;
//
// groupBox2
//
groupBox2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
groupBox2.Controls.Add(lameTargetQualityRb);
groupBox2.Controls.Add(lameTargetBitrateRb);
groupBox2.Location = new System.Drawing.Point(6, 22);
groupBox2.Name = "groupBox2";
groupBox2.Size = new System.Drawing.Size(214, 58);
groupBox2.Size = new System.Drawing.Size(189, 58);
groupBox2.TabIndex = 0;
groupBox2.TabStop = false;
groupBox2.Text = "Target";
//
// lameTargetQualityRb
//
lameTargetQualityRb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
lameTargetQualityRb.AutoSize = true;
lameTargetQualityRb.Location = new System.Drawing.Point(139, 22);
lameTargetQualityRb.Location = new System.Drawing.Point(118, 22);
lameTargetQualityRb.Name = "lameTargetQualityRb";
lameTargetQualityRb.Size = new System.Drawing.Size(63, 19);
lameTargetQualityRb.TabIndex = 0;
@@ -1321,7 +1354,6 @@
Controls.Add(tabControl);
Controls.Add(cancelBtn);
Controls.Add(saveBtn);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MaximizeBox = false;
MinimizeBox = false;

View File

@@ -18,7 +18,7 @@
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>

View File

@@ -1,11 +1,12 @@
using System.Drawing;
using System.Windows.Forms;
namespace LibationWinForms.GridView
{
public class DataGridViewImageButtonCell : DataGridViewButtonCell
{
protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds)
public class DataGridViewImageButtonCell : AccessibleDataGridViewButtonCell
{
public DataGridViewImageButtonCell(string accessibilityName) : base(accessibilityName) { }
protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds)
{
var scaleFactor = OwningColumn is IDataGridScaleColumn scCol ? scCol.ScaleFactor : 1f;

View File

@@ -20,20 +20,33 @@ namespace LibationWinForms.GridView
}
internal class EditTagsDataGridViewImageButtonCell : DataGridViewImageButtonCell
{
private static Image ButtonImage { get; } = Properties.Resources.edit_25x25;
{
public EditTagsDataGridViewImageButtonCell() : base("Edit Tags button") { }
private static Image ButtonImage { get; } = Properties.Resources.edit_25x25;
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (rowIndex >= 0 && DataGridView.GetBoundItem<IGridEntry>(rowIndex) is ISeriesEntry)
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
else if (value is string tagStr && tagStr.Length == 0)
// series
if (rowIndex >= 0 && DataGridView.GetBoundItem<IGridEntry>(rowIndex) is ISeriesEntry)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
}
// tag: empty
else if (value is string tagStr && tagStr.Length == 0)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
DrawButtonImage(graphics, ButtonImage, cellBounds);
}
AccessibilityDescription = "Click to edit tags";
}
// tag: not empty
else
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
}
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
AccessibilityDescription = (string)value;
}
}
}
}

View File

@@ -1,7 +1,7 @@
using LibationUiBase.GridView;
using System;
using System;
using System.Drawing;
using System.Windows.Forms;
using LibationUiBase.GridView;
namespace LibationWinForms.GridView
{
@@ -21,15 +21,19 @@ namespace LibationWinForms.GridView
}
}
internal class LastDownloadedGridViewCell : DataGridViewTextBoxCell
{
internal class LastDownloadedGridViewCell : AccessibleDataGridViewTextBoxCell
{
private LastDownloadStatus LastDownload => (LastDownloadStatus)Value;
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
public LastDownloadedGridViewCell() : base("Last Downloaded") { }
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (value is LastDownloadStatus lastDl)
ToolTipText = lastDl.ToolTipText;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
}
if (value is LastDownloadStatus lastDl)
AccessibilityDescription = lastDl.ToolTipText;
}
protected override void OnDoubleClick(DataGridViewCellEventArgs e)
{

View File

@@ -16,7 +16,9 @@ namespace LibationWinForms.GridView
internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell
{
private static readonly Brush DISABLED_GRAY = new SolidBrush(Color.FromArgb(0x60, Color.LightGray));
public LiberateDataGridViewImageButtonCell() : base("Liberate button") { }
private static readonly Brush DISABLED_GRAY = new SolidBrush(Color.FromArgb(0x60, Color.LightGray));
private static readonly Color HiddenForeColor = Color.LightGray;
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
@@ -31,7 +33,7 @@ namespace LibationWinForms.GridView
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
DrawButtonImage(graphics, (Image)status.ButtonImage, cellBounds);
ToolTipText = status.ToolTip;
AccessibilityDescription = status.ToolTip;
if (status.IsUnavailable || status.Opacity < 1)
graphics.FillRectangle(DISABLED_GRAY, cellBounds);

View File

@@ -1,9 +1,9 @@
using DataLayer;
using System;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using DataLayer;
namespace LibationWinForms.GridView
{
@@ -24,14 +24,17 @@ namespace LibationWinForms.GridView
}
}
internal class MyRatingGridViewCell : DataGridViewTextBoxCell
{
internal class MyRatingGridViewCell : AccessibleDataGridViewTextBoxCell
{
private static Rating DefaultRating => new Rating(0, 0, 0);
public override object DefaultNewRowValue => DefaultRating;
public override Type EditType => typeof(MyRatingCellEditor);
public override Type ValueType => typeof(Rating);
public MyRatingGridViewCell() { ToolTipText = ReadOnly ? "" : "Click to change ratings"; }
public MyRatingGridViewCell() : base("My Rating")
{
AccessibilityDescription = ReadOnly ? "" : "Click to change ratings";
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
@@ -46,14 +49,14 @@ namespace LibationWinForms.GridView
{
if (value is Rating rating)
{
ToolTipText = ReadOnly ? "" : "Click to change ratings";
var starString = rating.ToStarString();
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, starString, starString, errorText, cellStyle, advancedBorderStyle, paintParts);
}
else
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts);
}
AccessibilityDescription = ReadOnly ? "" : "Click to change ratings";
}
else
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts);
}
protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
=> value is Rating rating ? rating.ToStarString() : value?.ToString();

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>libation.ico</ApplicationIcon>
@@ -17,6 +17,10 @@
<!-- Version is now in AppScaffolding.csproj -->
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
</ItemGroup>
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
@@ -37,7 +41,7 @@
<ItemGroup>
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="7.3.0.1" />
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="8.0.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -250,7 +250,7 @@ namespace LibationWinForms.ProcessQueue
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
{
var quality
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High && LibraryBook.Book.PictureLarge is not null
? new PictureDefinition(LibraryBook.Book.PictureLarge, PictureSize.Native)
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -13,37 +13,40 @@ namespace LibationWinForms.SeriesView
CellTemplate.Style.WrapMode = DataGridViewTriState.True;
}
}
internal class DownloadButtonColumnCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (value is SeriesButton sentry)
{
string cellValue = sentry.DisplayText;
if (!sentry.Enabled)
{
//Draw disabled button
Rectangle buttonArea = cellBounds;
Rectangle buttonAdjustment = BorderWidths(advancedBorderStyle);
buttonArea.X += buttonAdjustment.X;
buttonArea.Y += buttonAdjustment.Y;
buttonArea.Height -= buttonAdjustment.Height;
buttonArea.Width -= buttonAdjustment.Width;
ButtonRenderer.DrawButton(graphics, buttonArea, cellValue, cellStyle.Font, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak, focused: false, PushButtonState.Disabled);
internal class DownloadButtonColumnCell : AccessibleDataGridViewButtonCell
{
public DownloadButtonColumnCell() : base("Download Series button") { }
}
else if (sentry.HasButtonAction)
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, cellValue, cellValue, errorText, cellStyle, advancedBorderStyle, paintParts);
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
TextRenderer.DrawText(graphics, cellValue, cellStyle.Font, cellBounds, cellStyle.ForeColor);
}
}
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
}
}
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (value is not SeriesButton seriesEntry)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
return;
}
string cellValue = seriesEntry.DisplayText;
AccessibilityDescription = cellValue;
if (!seriesEntry.Enabled)
{
//Draw disabled button
Rectangle buttonArea = cellBounds;
Rectangle buttonAdjustment = BorderWidths(advancedBorderStyle);
buttonArea.X += buttonAdjustment.X;
buttonArea.Y += buttonAdjustment.Y;
buttonArea.Height -= buttonAdjustment.Height;
buttonArea.Width -= buttonAdjustment.Width;
ButtonRenderer.DrawButton(graphics, buttonArea, cellValue, cellStyle.Font, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak, focused: false, PushButtonState.Disabled);
}
else if (seriesEntry.HasButtonAction)
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, cellValue, cellValue, errorText, cellStyle, advancedBorderStyle, paintParts);
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
TextRenderer.DrawText(graphics, cellValue, cellStyle.Font, cellBounds, cellStyle.ForeColor);
}
}
}
}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<PublishReadyToRun>true</PublishReadyToRun>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -2,8 +2,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<!--<TargetFramework>net7.0-macos</TargetFramework>-->
<TargetFramework>net8.0</TargetFramework>
<!--<TargetFramework>net8.0-macos</TargetFramework>-->
<ImplicitUsings>enable</ImplicitUsings>
<PublishReadyToRun>true</PublishReadyToRun>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
@@ -26,7 +26,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1901.177" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2478.35" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,9 @@
For reasons I cannot figure out, upgrading the major .net version breaks Libation until these were done. Update these to the same version of .net as the app and release their nugets:
* https://github.com/rmcrackan/Dinah.Core
* https://github.com/rmcrackan/AudibleApi
* https://github.com/rmcrackan/LuceneNet303r2
* https://github.com/Mbucari/AAXClean.Codecs
* https://github.com/Mbucari/AAXClean
* https://github.com/Mbucari/serilog-sinks-zipfile

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
@@ -19,7 +19,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="7.3.0.1" />
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>