mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-09-08 11:47:57 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d19fe2250c | ||
|
|
d16d0c8de2 | ||
|
|
c213d5d9f6 | ||
|
|
c73a023572 | ||
|
|
67389917fd | ||
|
|
b3264d5f42 | ||
|
|
962d9b550f | ||
|
|
91ce7272ae | ||
|
|
2f64ca6856 | ||
|
|
cfe5db436c | ||
|
|
3653fc8094 | ||
|
|
662c0ec871 | ||
|
|
44d39eabdb | ||
|
|
a0550d5c97 | ||
|
|
14eaca6d45 | ||
|
|
93ccc206ef | ||
|
|
d3f0fd711e | ||
|
|
3f4604e877 | ||
|
|
c316709af8 | ||
|
|
221d5c7f1c | ||
|
|
5a86a1a27b | ||
|
|
dc5e55de68 | ||
|
|
ee37864a42 | ||
|
|
efe347667c | ||
|
|
f27a18bdbb | ||
|
|
d1834659d9 | ||
|
|
7842b521d7 | ||
|
|
0822f0229d | ||
|
|
26aee4d29d | ||
|
|
17a80a23a8 | ||
|
|
e26fc9ca62 | ||
|
|
a03ccf1143 | ||
|
|
bb8dd615db | ||
|
|
9022a2889f | ||
|
|
ef049a3b02 | ||
|
|
77409750aa | ||
|
|
1702130b01 | ||
|
|
b6d1a7e3ba | ||
|
|
2907ba5c13 | ||
|
|
6df6c79ac8 | ||
|
|
3a9ca5d827 | ||
|
|
e1e663e327 | ||
|
|
4b00d5fd84 | ||
|
|
02dbf8aad0 | ||
|
|
8326389f5c | ||
|
|
34535b3ce1 | ||
|
|
7e5366ab95 | ||
|
|
690de9bc5c | ||
|
|
c976aa2bb2 | ||
|
|
27f659285d | ||
|
|
423a5e7720 | ||
|
|
9152e12fe1 | ||
|
|
f471c53139 | ||
|
|
66d055bb90 | ||
|
|
2bbb35363a | ||
|
|
1d3687cf9e | ||
|
|
daf925157f | ||
|
|
40eec9e674 | ||
|
|
6f0782053e | ||
|
|
04ad033ba0 | ||
|
|
f12f8ba3ee | ||
|
|
cc6feb21ff | ||
|
|
c4f2ec428d | ||
|
|
59689cb647 | ||
|
|
d7f3758ebc | ||
|
|
49775b019c | ||
|
|
e55e969349 | ||
|
|
42a93bfac1 | ||
|
|
f86c77a546 | ||
|
|
88c35e2a56 | ||
|
|
b405e8b6b2 | ||
|
|
92d283187d | ||
|
|
51b8cfe71f | ||
|
|
c80da5357b | ||
|
|
736d7c4a5f | ||
|
|
f175b7592e | ||
|
|
415e6e7bc6 | ||
|
|
d6a413e8d9 | ||
|
|
3049de6246 | ||
|
|
fb9b4eb77e | ||
|
|
e65b6c76a8 | ||
|
|
167a021eb1 | ||
|
|
ff3ac2d6fd | ||
|
|
f733079a49 | ||
|
|
893d68190d | ||
|
|
97f94d8782 | ||
|
|
4b2ce0c2d1 | ||
|
|
ee00417c6f | ||
|
|
768afd8ecd | ||
|
|
32c3fa85ce | ||
|
|
6986c8f018 |
No files matched your search
@@ -33,7 +33,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DOTNET_CONFIGURATION: 'Release'
|
DOTNET_CONFIGURATION: 'Release'
|
||||||
DOTNET_VERSION: '7.0.x'
|
DOTNET_VERSION: '8.0.x'
|
||||||
RELEASE_NAME: 'chardonnay'
|
RELEASE_NAME: 'chardonnay'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -41,9 +41,9 @@ jobs:
|
|||||||
name: '${{ inputs.OS }}-${{ inputs.architecture }}'
|
name: '${{ inputs.OS }}-${{ inputs.architecture }}'
|
||||||
runs-on: ${{ inputs.runs_on }}
|
runs-on: ${{ inputs.runs_on }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v3
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||||
env:
|
env:
|
||||||
@@ -124,7 +124,7 @@ jobs:
|
|||||||
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
|
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
- name: Publish bundle
|
- name: Publish bundle
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.bundle.outputs.artifact }}
|
name: ${{ steps.bundle.outputs.artifact }}
|
||||||
path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}
|
path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DOTNET_CONFIGURATION: 'Release'
|
DOTNET_CONFIGURATION: 'Release'
|
||||||
DOTNET_VERSION: '7.0.x'
|
DOTNET_VERSION: '8.0.x'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -35,9 +35,9 @@ jobs:
|
|||||||
release_name: classic
|
release_name: classic
|
||||||
prefix: Classic-
|
prefix: Classic-
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v3
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||||
env:
|
env:
|
||||||
@@ -107,7 +107,7 @@ jobs:
|
|||||||
Compress-Archive -Path "${bin_dir}*" -DestinationPath "$artifact.zip"
|
Compress-Archive -Path "${bin_dir}*" -DestinationPath "$artifact.zip"
|
||||||
|
|
||||||
- name: Publish artifact
|
- name: Publish artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.zip.outputs.artifact }}.zip
|
name: ${{ steps.zip.outputs.artifact }}.zip
|
||||||
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
|
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
|
||||||
|
|||||||
@@ -24,22 +24,22 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.docker_username }}
|
username: ${{ secrets.docker_username }}
|
||||||
password: ${{ secrets.docker_token }}
|
password: ${{ secrets.docker_token }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
build-args: 'FOLDER_NAME=Linux-chardonnay'
|
build-args: 'FOLDER_NAME=Linux-chardonnay'
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
id: release
|
id: release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
name: Libation v${{ needs.prerelease.outputs.version }}
|
name: Libation v${{ needs.prerelease.outputs.version }}
|
||||||
body: <Put a body here>
|
body: <Put a body here>
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
- name: Upload release assets
|
- name: Upload release assets
|
||||||
uses: dwenegar/upload-release-assets@v1
|
uses: dwenegar/upload-release-assets@v2
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+12
-3
@@ -1,10 +1,11 @@
|
|||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...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.
|
The docker image is provided as-is. We hope it can be useful to you but it is not officially supported.
|
||||||
|
|
||||||
### Setup
|
### 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:
|
In Settings.json, make the following changes:
|
||||||
* Change `Books` to `/data`
|
* 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"
|
||||||
|
```
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
### Running
|
### Running
|
||||||
Once the configuration files are copied and edited, the docker image can be run with the following command.
|
Once the configuration files are copied and edited, the docker image can be run with the following command.
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
## [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)
|
||||||
|
* Desktop: [VLC](https://www.videolan.org/)
|
||||||
|
|
||||||
|
## 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)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...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.
|
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
|
- Debian
|
||||||
```Console
|
```Console
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Run Libation on MacOS
|
# Run Libation on MacOS
|
||||||
This walkthrough should get you up and running with Libation on your Mac.
|
This walkthrough should get you up and running with Libation on your Mac.
|
||||||
|
|
||||||
@@ -23,6 +24,17 @@ This walkthrough should get you up and running with Libation on your Mac.
|
|||||||
```
|
```
|
||||||
- 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
|
## Running Hangover
|
||||||
|
|
||||||
Libation comes with a recovery app called Hangover. You can start it by running this command:
|
Libation comes with a recovery app called Hangover. You can start it by running this command:
|
||||||
|
|||||||
@@ -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
|
# 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.
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+38
-27
@@ -1,28 +1,39 @@
|
|||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" enable-background="new 0 0 512 512">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 524 524" enable-background="new 0 0 524 524">
|
||||||
<path id="glass" d=
|
<defs>
|
||||||
"M139,2
|
<g id="glass">
|
||||||
A 192,200 0 0 0 103,84
|
<path fill-rule="evenodd" d=
|
||||||
A 222,334 41 0 0 241,320
|
"M262,8
|
||||||
V478
|
h-117
|
||||||
H160
|
a 192,200 0 0 0 -36,82
|
||||||
A 16,16 0 0 0 160,510
|
a 222,334 41 0 0 138,236
|
||||||
H352
|
v158
|
||||||
A16 16 0 0 0 352,478
|
h-81
|
||||||
H271
|
a 16,16 0 0 0 0,32
|
||||||
V320
|
h192
|
||||||
A 222,334 -41 0 0 409,84
|
a 16 16 0 0 0 0,-32
|
||||||
A 192,200 0 0 0 373,2
|
h-81
|
||||||
M355,32
|
v-158
|
||||||
A 192,200 0 0 1 381,127
|
a 222,334 -41 0 0 138,-236
|
||||||
A 187.5,334 -35 0 1 256,286
|
a 192,200 0 0 0 -36,-82
|
||||||
A 187.5,334 35 0 1 131,127
|
h-117
|
||||||
A 192,200 0 0 1 157,32
|
m-99,30
|
||||||
H355
|
a 192,200 0 0 0 -26,95
|
||||||
z" />
|
a 187.5,334 35 0 0 125,159
|
||||||
|
a 187.5,334 -35 0 0 125,-159
|
||||||
<path id="wine-level" d=
|
a 192,200 0 0 0 -26,-95
|
||||||
"M146,128
|
h-198
|
||||||
A 168,300 35 0 0 256,270
|
z"/>
|
||||||
A 168,300 -35 0 0 366,128
|
</g>
|
||||||
z"/>
|
<g id="wine-level">
|
||||||
|
<path d=
|
||||||
|
"M158,136
|
||||||
|
a 168,305 35 0 0 104,136
|
||||||
|
a 168,305 -35 0 0 104,-136
|
||||||
|
z"/>
|
||||||
|
</g>
|
||||||
|
</defs>
|
||||||
|
<use href="#glass" stroke="#ffffffa0" stroke-width="16" fill="Transparent" />
|
||||||
|
<use href="#wine-level" stroke="#ffffffa0" stroke-width="16" fill="Transparent" />
|
||||||
|
<use href="#glass" fill="Black" />
|
||||||
|
<use href="#wine-level" fill="Black" />
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 585 B After Width: | Height: | Size: 968 B |
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
## [Download Libation](https://github.com/rmcrackan/Libation/releases/latest)
|
## [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**.
|
...or just tell more friends. As long as I'm maintaining this software, it will remain **free** and **open source**.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
|
|
||||||
- [Audible audiobook manager](#audible-audiobook-manager)
|
- [Audible audiobook manager](#audible-audiobook-manager)
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
- [Custom File Naming](Documentation/NamingTemplates.md)
|
- [Custom File Naming](Documentation/NamingTemplates.md)
|
||||||
- [Command Line Interface](Documentation/Advanced.md#command-line-interface)
|
- [Command Line Interface](Documentation/Advanced.md#command-line-interface)
|
||||||
- [Docker](Documentation/Docker.md)
|
- [Docker](Documentation/Docker.md)
|
||||||
|
- [Frequently Asked Questions](Documentation/FrequentlyAskedQuestions.md)
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
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
|
echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p
|
||||||
fi
|
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
|
" >> $FOLDER_DEBIAN/postinst
|
||||||
|
|
||||||
echo "Creating control file..."
|
echo "Creating control file..."
|
||||||
|
|||||||
@@ -94,8 +94,6 @@ install * %{buildroot}%{_libdir}/%{name}/
|
|||||||
|
|
||||||
if [ \$1 -eq 1 ] ; then
|
if [ \$1 -eq 1 ] ; then
|
||||||
# Initial installation
|
# Initial installation
|
||||||
touch %{_libdir}/%{name}/appsettings.json
|
|
||||||
chmod 666 %{_libdir}/%{name}/appsettings.json
|
|
||||||
|
|
||||||
ln -s %{_libdir}/%{name}/Libation %{_bindir}/libation
|
ln -s %{_libdir}/%{name}/Libation %{_bindir}/libation
|
||||||
ln -s %{_libdir}/%{name}/Hangover %{_bindir}/hangover
|
ln -s %{_libdir}/%{name}/Hangover %{_bindir}/hangover
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AAXClean.Codecs" Version="1.1.0" />
|
<PackageReference Include="AAXClean.Codecs" Version="1.1.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Version>10.6.4.1</Version>
|
<Version>11.3.9.1</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Octokit" Version="7.1.0" />
|
<PackageReference Include="Octokit" Version="10.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.ZipFile" Version="1.0.1" />
|
<PackageReference Include="Serilog.Sinks.ZipFile" Version="3.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ApplicationServices\ApplicationServices.csproj" />
|
<ProjectReference Include="..\ApplicationServices\ApplicationServices.csproj" />
|
||||||
@@ -19,4 +19,4 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -254,6 +254,8 @@ namespace AppScaffolding
|
|||||||
|
|
||||||
AudibleFileStorage.DecryptInProgressDirectory,
|
AudibleFileStorage.DecryptInProgressDirectory,
|
||||||
DecryptInProgressFiles = FileManager.FileUtility.SaferEnumerateFiles(AudibleFileStorage.DecryptInProgressDirectory).Count(),
|
DecryptInProgressFiles = FileManager.FileUtility.SaferEnumerateFiles(AudibleFileStorage.DecryptInProgressDirectory).Count(),
|
||||||
|
|
||||||
|
disableIPv6 = AppContext.TryGetSwitch("System.Net.DisableIPv6", out bool disableIPv6Value),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (InteropFactory.InteropFunctionsType is null)
|
if (InteropFactory.InteropFunctionsType is null)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
<PackageReference Include="CsvHelper" Version="31.0.2" />
|
||||||
<PackageReference Include="NPOI" Version="2.6.1" />
|
<PackageReference Include="NPOI" Version="2.6.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -119,9 +119,15 @@ namespace ApplicationServices
|
|||||||
|
|
||||||
logTime($"pre {nameof(scanAccountsAsync)} all");
|
logTime($"pre {nameof(scanAccountsAsync)} all");
|
||||||
var libraryOptions = new LibraryOptions
|
var libraryOptions = new LibraryOptions
|
||||||
{
|
{
|
||||||
ResponseGroups = LibraryOptions.ResponseGroupOptions.ALL_OPTIONS,
|
ResponseGroups
|
||||||
ImageSizes = LibraryOptions.ImageSizeOptions._500 | LibraryOptions.ImageSizeOptions._1215
|
= 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);
|
var importItems = await scanAccountsAsync(apiExtendedfunc, accounts, libraryOptions);
|
||||||
logTime($"post {nameof(scanAccountsAsync)} all");
|
logTime($"post {nameof(scanAccountsAsync)} all");
|
||||||
|
|||||||
@@ -207,7 +207,11 @@ namespace AudibleUtilities
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
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();
|
sw.Stop();
|
||||||
|
|
||||||
Serilog.Log.Logger.Debug($"Batch {batchNum} End: Retrieved {items.Count} items in {sw.ElapsedMilliseconds} ms");
|
Serilog.Log.Logger.Debug($"Batch {batchNum} End: Retrieved {items.Count} items in {sw.ElapsedMilliseconds} ms");
|
||||||
|
|||||||
@@ -90,8 +90,10 @@ namespace AudibleUtilities
|
|||||||
var distinct = items.GetSeriesDistinct();
|
var distinct = items.GetSeriesDistinct();
|
||||||
if (distinct.Any(s => s.SeriesId is null))
|
if (distinct.Any(s => s.SeriesId is null))
|
||||||
exceptions.Add(new ArgumentException($"Collection contains {nameof(Item.Series)} with null {nameof(Series.SeriesId)}", nameof(items)));
|
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;
|
return exceptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AudibleApi" Version="8.4.3.1" />
|
<PackageReference Include="AudibleApi" Version="9.1.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dinah.Core" Version="7.3.0.1" />
|
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
|
||||||
<PackageReference Include="Dinah.EntityFrameworkCore" Version="7.3.0.1" />
|
<PackageReference Include="Dinah.EntityFrameworkCore" Version="8.0.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.9">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.9" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.9">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ namespace DataLayer
|
|||||||
ReplaceAuthors(authors);
|
ReplaceAuthors(authors);
|
||||||
ReplaceNarrators(narrators);
|
ReplaceNarrators(narrators);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateTitle(string title, string subtitle)
|
public void UpdateTitle(string title, string subtitle)
|
||||||
{
|
{
|
||||||
Title = title?.Trim() ?? "";
|
Title = title?.Trim() ?? "";
|
||||||
@@ -113,8 +114,11 @@ namespace DataLayer
|
|||||||
_titleWithSubtitle = null;
|
_titleWithSubtitle = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region contributors, authors, narrators
|
public void UpdateLengthInMinutes(int lengthInMinutes)
|
||||||
internal HashSet<BookContributor> ContributorsLink { get; private set; }
|
=> LengthInMinutes = lengthInMinutes;
|
||||||
|
|
||||||
|
#region contributors, authors, narrators
|
||||||
|
internal HashSet<BookContributor> ContributorsLink { get; private set; }
|
||||||
|
|
||||||
public IEnumerable<Contributor> Authors => ContributorsLink.ByRole(Role.Author).Select(bc => bc.Contributor).ToList();
|
public IEnumerable<Contributor> Authors => ContributorsLink.ByRole(Role.Author).Select(bc => bc.Contributor).ToList();
|
||||||
public IEnumerable<Contributor> Narrators => ContributorsLink.ByRole(Role.Narrator).Select(bc => bc.Contributor).ToList();
|
public IEnumerable<Contributor> Narrators => ContributorsLink.ByRole(Role.Narrator).Select(bc => bc.Contributor).ToList();
|
||||||
|
|||||||
@@ -149,6 +149,8 @@ namespace DtoImporterService
|
|||||||
{
|
{
|
||||||
var item = importItem.DtoItem;
|
var item = importItem.DtoItem;
|
||||||
|
|
||||||
|
book.UpdateLengthInMinutes(item.LengthInMinutes);
|
||||||
|
|
||||||
// Update the book titles, since formatting can change
|
// Update the book titles, since formatting can change
|
||||||
book.UpdateTitle(item.Title, item.Subtitle);
|
book.UpdateTitle(item.Title, item.Subtitle);
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ namespace DtoImporterService
|
|||||||
loadLocal_categories();
|
loadLocal_categories();
|
||||||
|
|
||||||
// upsert
|
// upsert
|
||||||
|
//Import item may not have no (null) categories
|
||||||
var categoryLadders = importItems
|
var categoryLadders = importItems
|
||||||
|
.Where(i => i.DtoItem.CategoryLadders is not null)
|
||||||
.SelectMany(i => i.DtoItem.CategoryLadders)
|
.SelectMany(i => i.DtoItem.CategoryLadders)
|
||||||
.Select(cl => cl.Ladder)
|
.Select(cl => cl?.Ladder)
|
||||||
.Where(l => l?.Length > 0)
|
.Where(l => l?.Length > 0)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace FileLiberator
|
|||||||
var series = libraryBook.Book.SeriesLink.SingleOrDefault();
|
var series = libraryBook.Book.SeriesLink.SingleOrDefault();
|
||||||
if (series is not null)
|
if (series is not null)
|
||||||
{
|
{
|
||||||
var seriesParent = ApplicationServices.DbContexts.GetContext().GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId);
|
using var context = ApplicationServices.DbContexts.GetContext();
|
||||||
|
var seriesParent = context.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId);
|
||||||
|
|
||||||
if (seriesParent is not null)
|
if (seriesParent is not null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ namespace FileLiberator
|
|||||||
config.LameMatchSourceBR,
|
config.LameMatchSourceBR,
|
||||||
chapters);
|
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);
|
using var mp3File = File.Open(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -375,8 +375,15 @@ namespace FileLiberator
|
|||||||
{
|
{
|
||||||
if (Configuration.Instance.AllowLibationFixup)
|
if (Configuration.Instance.AllowLibationFixup)
|
||||||
{
|
{
|
||||||
e = OnRequestCoverArt();
|
try
|
||||||
abDownloader.SetCoverArt(e);
|
{
|
||||||
|
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)
|
if (e is not null)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dinah.Core" Version="7.3.0.1" />
|
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
|
||||||
<PackageReference Include="Polly" Version="7.2.4" />
|
<PackageReference Include="Polly" Version="8.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<!--Avalonia doesen't support TrimMode=link currently,but we are working on that https://github.com/AvaloniaUI/Avalonia/issues/6892 -->
|
<!--Avalonia doesen't support TrimMode=link currently,but we are working on that https://github.com/AvaloniaUI/Avalonia/issues/6892 -->
|
||||||
<TrimMode>copyused</TrimMode>
|
<TrimMode>copyused</TrimMode>
|
||||||
@@ -21,9 +21,13 @@
|
|||||||
<ApplicationIcon>hangover.ico</ApplicationIcon>
|
<ApplicationIcon>hangover.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<ItemGroup>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
|
||||||
</PropertyGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<OutputPath>..\bin\Avalonia\Debug</OutputPath>
|
<OutputPath>..\bin\Avalonia\Debug</OutputPath>
|
||||||
@@ -67,13 +71,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
||||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
<PackageReference Include="Avalonia" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--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.2" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.2" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />
|
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||||
<AssemblyName>Hangover</AssemblyName>
|
<AssemblyName>Hangover</AssemblyName>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\classic</PublishDir>
|
<PublishDir>..\bin\Publish\classic</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
|||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{03C8835F-936C-4AF7-87AE-FF92BDBE8B9B}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{03C8835F-936C-4AF7-87AE-FF92BDBE8B9B}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
REFERENCE.txt = REFERENCE.txt
|
REFERENCE.txt = REFERENCE.txt
|
||||||
|
Upgrading dotnet version.txt = Upgrading dotnet version.txt
|
||||||
_ARCHITECTURE NOTES.txt = _ARCHITECTURE NOTES.txt
|
_ARCHITECTURE NOTES.txt = _ARCHITECTURE NOTES.txt
|
||||||
_AvaloniaUI Primer.txt = _AvaloniaUI Primer.txt
|
_AvaloniaUI Primer.txt = _AvaloniaUI Primer.txt
|
||||||
_DB_NOTES.txt = _DB_NOTES.txt
|
_DB_NOTES.txt = _DB_NOTES.txt
|
||||||
|
|||||||
@@ -44,9 +44,9 @@
|
|||||||
|
|
||||||
<SolidColorBrush x:Key="CancelRed" Color="#802727" />
|
<SolidColorBrush x:Key="CancelRed" Color="#802727" />
|
||||||
<SolidColorBrush x:Key="IconFill" Color="#DCE0DF" />
|
<SolidColorBrush x:Key="IconFill" Color="#DCE0DF" />
|
||||||
<SolidColorBrush x:Key="StoplightRed" Color="#5F0707" />
|
<SolidColorBrush x:Key="StoplightRed" Color="#7d1f1f" />
|
||||||
<SolidColorBrush x:Key="StoplightYellow" Color="#5F5B1A" />
|
<SolidColorBrush x:Key="StoplightYellow" Color="#7d7d1f" />
|
||||||
<SolidColorBrush x:Key="StoplightGreen" Color="#174E15" />
|
<SolidColorBrush x:Key="StoplightGreen" Color="#1f7d1f" />
|
||||||
|
|
||||||
|
|
||||||
<SolidColorBrush x:Key="DisabledGrayBrush" Opacity="0.4" Color="{StaticResource SystemChromeMediumColor}" />
|
<SolidColorBrush x:Key="DisabledGrayBrush" Opacity="0.4" Color="{StaticResource SystemChromeMediumColor}" />
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ namespace LibationAvalonia.Controls
|
|||||||
|
|
||||||
if (known is Configuration.KnownDirectories.None)
|
if (known is Configuration.KnownDirectories.None)
|
||||||
{
|
{
|
||||||
directoryState.CustomDir = noSubDir;
|
directoryState.CustomDir = directory;
|
||||||
directoryState.CustomChecked = true;
|
directoryState.CustomChecked = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -27,6 +27,6 @@
|
|||||||
Margin="5"
|
Margin="5"
|
||||||
Padding="30,3,30,3"
|
Padding="30,3,30,3"
|
||||||
Content="Save"
|
Content="Save"
|
||||||
Command="{Binding SaveButtonAsync}" />
|
Click="Save_Click" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibationAvalonia.Dialogs
|
namespace LibationAvalonia.Dialogs
|
||||||
{
|
{
|
||||||
public partial class LibationFilesDialog : Window
|
public partial class LibationFilesDialog : DialogWindow
|
||||||
{
|
{
|
||||||
private class DirSelectOptions
|
private class DirSelectOptions
|
||||||
{
|
{
|
||||||
@@ -18,28 +16,26 @@ namespace LibationAvalonia.Dialogs
|
|||||||
|
|
||||||
public string Directory { get; set; } = Configuration.GetKnownDirectoryPath(Configuration.KnownDirectories.UserProfile);
|
public string Directory { get; set; } = Configuration.GetKnownDirectoryPath(Configuration.KnownDirectories.UserProfile);
|
||||||
}
|
}
|
||||||
private DirSelectOptions dirSelectOptions;
|
|
||||||
|
private readonly DirSelectOptions dirSelectOptions;
|
||||||
public string SelectedDirectory => dirSelectOptions.Directory;
|
public string SelectedDirectory => dirSelectOptions.Directory;
|
||||||
public DialogResult DialogResult { get; private set; }
|
|
||||||
public LibationFilesDialog()
|
public LibationFilesDialog() : base(saveAndRestorePosition: false)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
DataContext = dirSelectOptions = new();
|
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(SelectedDirectory))
|
||||||
|
|
||||||
if (!System.IO.Directory.Exists(libationDir))
|
|
||||||
{
|
{
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
await SaveAndCloseAsync();
|
||||||
Close(DialogResult);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="750"
|
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="200"
|
||||||
MinWidth="900" MinHeight="750"
|
MinWidth="900" MinHeight="200"
|
||||||
Width="900" Height="750"
|
Width="900" Height="750"
|
||||||
x:Class="LibationAvalonia.Dialogs.SettingsDialog"
|
x:Class="LibationAvalonia.Dialogs.SettingsDialog"
|
||||||
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||||
@@ -46,39 +46,41 @@
|
|||||||
</TabControl.Styles>
|
</TabControl.Styles>
|
||||||
|
|
||||||
<TabItem>
|
<TabItem>
|
||||||
|
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<TextBlock Text="Important Settings"/>
|
<TextBlock Text="Important Settings"/>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
|
|
||||||
<settings:Important DataContext="{CompiledBinding ImportantSettings}" />
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<settings:Important DataContext="{CompiledBinding ImportantSettings}" />
|
||||||
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem>
|
<TabItem>
|
||||||
|
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<TextBlock Text="Import Library"/>
|
<TextBlock Text="Import Library"/>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
|
|
||||||
<settings:Import DataContext="{CompiledBinding ImportSettings}" />
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<settings:Import DataContext="{CompiledBinding ImportSettings}" />
|
||||||
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem>
|
<TabItem>
|
||||||
|
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<TextBlock Text="Download/Decrypt"/>
|
<TextBlock Text="Download/Decrypt"/>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
|
|
||||||
<settings:DownloadDecrypt DataContext="{CompiledBinding DownloadDecryptSettings}" />
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<settings:DownloadDecrypt DataContext="{CompiledBinding DownloadDecryptSettings}" />
|
||||||
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem>
|
<TabItem>
|
||||||
|
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<TextBlock Text="Audio File Settings"/>
|
<TextBlock Text="Audio File Settings"/>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<settings:Audio DataContext="{CompiledBinding AudioSettings}" />
|
<settings:Audio DataContext="{CompiledBinding AudioSettings}" />
|
||||||
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||||
<ApplicationIcon>Assets/libation.ico</ApplicationIcon>
|
<ApplicationIcon>Assets/libation.ico</ApplicationIcon>
|
||||||
@@ -14,6 +14,10 @@
|
|||||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
<StartupObject />
|
<StartupObject />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
@@ -69,14 +73,14 @@
|
|||||||
<UpToDateCheckInput Remove="Controls\GroupBox.axaml" />
|
<UpToDateCheckInput Remove="Controls\GroupBox.axaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.2" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
|
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.5" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
|
||||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
<PackageReference Include="Avalonia" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.2" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.5" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -177,9 +177,12 @@ Libation.
|
|||||||
tbx.MinWidth = vm.TextBlockMinWidth;
|
tbx.MinWidth = vm.TextBlockMinWidth;
|
||||||
tbx.Text = message;
|
tbx.Text = message;
|
||||||
|
|
||||||
var thisScreen = owner.Screens.ScreenFromVisual(owner);
|
|
||||||
|
var thisScreen = owner.Screens?.ScreenFromVisual(owner);
|
||||||
|
|
||||||
var maxSize = new Size(0.20 * thisScreen.Bounds.Width, 0.9 * thisScreen.Bounds.Height - 55);
|
var maxSize
|
||||||
|
= thisScreen is null ? owner.ClientSize
|
||||||
|
: new Size(0.20 * thisScreen.Bounds.Width, 0.9 * thisScreen.Bounds.Height - 55);
|
||||||
|
|
||||||
var desiredMax = new Size(maxSize.Width, maxSize.Height);
|
var desiredMax = new Size(maxSize.Width, maxSize.Height);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var quality
|
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.PictureLarge, PictureSize.Native)
|
||||||
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
using ApplicationServices;
|
using ApplicationServices;
|
||||||
using AudibleUtilities;
|
using AudibleUtilities;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using LibationAvalonia.Dialogs.Login;
|
using LibationAvalonia.Dialogs.Login;
|
||||||
|
using LibationFileManager;
|
||||||
using LibationUiBase.GridView;
|
using LibationUiBase.GridView;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationAvalonia.ViewModels
|
namespace LibationAvalonia.ViewModels
|
||||||
@@ -27,8 +30,8 @@ namespace LibationAvalonia.ViewModels
|
|||||||
public string FilterString { get; private set; }
|
public string FilterString { get; private set; }
|
||||||
public DataGridCollectionView GridEntries { get; private set; }
|
public DataGridCollectionView GridEntries { get; private set; }
|
||||||
|
|
||||||
private bool _removeColumnVisivle;
|
private bool _removeColumnVisible;
|
||||||
public bool RemoveColumnVisivle { get => _removeColumnVisivle; private set => this.RaiseAndSetIfChanged(ref _removeColumnVisivle, value); }
|
public bool RemoveColumnVisible { get => _removeColumnVisible; private set => this.RaiseAndSetIfChanged(ref _removeColumnVisible, value); }
|
||||||
|
|
||||||
public List<LibraryBook> GetVisibleBookEntries()
|
public List<LibraryBook> GetVisibleBookEntries()
|
||||||
=> FilteredInGridEntries?
|
=> FilteredInGridEntries?
|
||||||
@@ -321,7 +324,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
{
|
{
|
||||||
foreach (var item in SOURCE)
|
foreach (var item in SOURCE)
|
||||||
item.PropertyChanged -= GridEntry_PropertyChanged;
|
item.PropertyChanged -= GridEntry_PropertyChanged;
|
||||||
RemoveColumnVisivle = false;
|
RemoveColumnVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RemoveCheckedBooksAsync()
|
public async Task RemoveCheckedBooksAsync()
|
||||||
@@ -376,7 +379,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
item.PropertyChanged += GridEntry_PropertyChanged;
|
item.PropertyChanged += GridEntry_PropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveColumnVisivle = true;
|
RemoveColumnVisible = true;
|
||||||
RemovableCountChanged?.Invoke(this, 0);
|
RemovableCountChanged?.Invoke(this, 0);
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -421,5 +424,44 @@ namespace LibationAvalonia.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Column Widths
|
||||||
|
|
||||||
|
public DataGridLength TitleWidth { get => getColumnWidth("Title", 200); set => setColumnWidth("Title", value); }
|
||||||
|
public DataGridLength AuthorsWidth { get => getColumnWidth("Authors", 100); set => setColumnWidth("Authors", value); }
|
||||||
|
public DataGridLength NarratorsWidth { get => getColumnWidth("Narrators", 100); set => setColumnWidth("Narrators", value); }
|
||||||
|
public DataGridLength LengthWidth { get => getColumnWidth("Length", 80); set => setColumnWidth("Length", value); }
|
||||||
|
public DataGridLength SeriesWidth { get => getColumnWidth("Series", 100); set => setColumnWidth("Series", value); }
|
||||||
|
public DataGridLength SeriesOrderWidth { get => getColumnWidth("SeriesOrder", 60); set => setColumnWidth("SeriesOrder", value); }
|
||||||
|
public DataGridLength DescriptionWidth { get => getColumnWidth("Description", 100); set => setColumnWidth("Description", value); }
|
||||||
|
public DataGridLength CategoryWidth { get => getColumnWidth("Category", 100); set => setColumnWidth("Category", value); }
|
||||||
|
public DataGridLength ProductRatingWidth { get => getColumnWidth("ProductRating", 95); set => setColumnWidth("ProductRating", value); }
|
||||||
|
public DataGridLength PurchaseDateWidth { get => getColumnWidth("PurchaseDate", 75); set => setColumnWidth("PurchaseDate", value); }
|
||||||
|
public DataGridLength MyRatingWidth { get => getColumnWidth("MyRating", 95); set => setColumnWidth("MyRating", value); }
|
||||||
|
public DataGridLength MiscWidth { get => getColumnWidth("Misc", 140); set => setColumnWidth("Misc", value); }
|
||||||
|
public DataGridLength LastDownloadWidth { get => getColumnWidth("LastDownload", 100); set => setColumnWidth("LastDownload", value); }
|
||||||
|
public DataGridLength BookTagsWidth { get => getColumnWidth("BookTags", 100); set => setColumnWidth("BookTags", value); }
|
||||||
|
|
||||||
|
private static DataGridLength getColumnWidth(string columnName, double defaultWidth)
|
||||||
|
=> Configuration.Instance.GridColumnsWidths.TryGetValue(columnName, out var val)
|
||||||
|
? new DataGridLength(val)
|
||||||
|
: new DataGridLength(defaultWidth);
|
||||||
|
|
||||||
|
private void setColumnWidth(string columnName, DataGridLength width, [CallerMemberName] string propertyName = "")
|
||||||
|
{
|
||||||
|
var dictionary = Configuration.Instance.GridColumnsWidths;
|
||||||
|
|
||||||
|
var newValue = (int)width.DisplayValue;
|
||||||
|
var valueSame = dictionary.TryGetValue(columnName, out var val) && val == newValue;
|
||||||
|
dictionary[columnName] = newValue;
|
||||||
|
|
||||||
|
if (!valueSame)
|
||||||
|
{
|
||||||
|
Configuration.Instance.GridColumnsWidths = dictionary;
|
||||||
|
this.RaisePropertyChanged(propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ namespace LibationAvalonia.Views
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Configure_Upgrade();
|
Configure_Upgrade();
|
||||||
|
|
||||||
Loaded += MainWindow_Loaded;
|
Opened += MainWindow_Opened;
|
||||||
Closing += MainWindow_Closing;
|
Closing += MainWindow_Closing;
|
||||||
LibraryLoaded += MainWindow_LibraryLoaded;
|
LibraryLoaded += MainWindow_LibraryLoaded;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ namespace LibationAvalonia.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void MainWindow_Loaded(object sender, EventArgs e)
|
private async void MainWindow_Opened(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (Configuration.Instance.FirstLaunch)
|
if (Configuration.Instance.FirstLaunch)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
ItemsSource="{Binding GridEntries}"
|
ItemsSource="{Binding GridEntries}"
|
||||||
CanUserSortColumns="True" BorderThickness="3"
|
CanUserSortColumns="True" BorderThickness="3"
|
||||||
|
CanUserResizeColumns="True"
|
||||||
CanUserReorderColumns="True">
|
CanUserReorderColumns="True">
|
||||||
|
|
||||||
<DataGrid.Styles>
|
<DataGrid.Styles>
|
||||||
@@ -45,10 +46,11 @@
|
|||||||
</DataGrid.Styles>
|
</DataGrid.Styles>
|
||||||
|
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
|
|
||||||
<DataGridTemplateColumn
|
<DataGridTemplateColumn
|
||||||
CanUserSort="True"
|
CanUserSort="True"
|
||||||
IsVisible="{Binding RemoveColumnVisivle}"
|
CanUserResize="False"
|
||||||
|
IsVisible="{Binding RemoveColumnVisible}"
|
||||||
PropertyChanged="RemoveColumn_PropertyChanged"
|
PropertyChanged="RemoveColumn_PropertyChanged"
|
||||||
Header="Remove"
|
Header="Remove"
|
||||||
IsReadOnly="False"
|
IsReadOnly="False"
|
||||||
@@ -65,7 +67,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</DataGridTemplateColumn>
|
</DataGridTemplateColumn>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
|
<controls:DataGridTemplateColumnExt CanUserResize="False" CanUserSort="True" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<views:LiberateStatusButton
|
<views:LiberateStatusButton
|
||||||
@@ -80,15 +82,15 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt CanUserSort="False" Header="Cover" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
|
<controls:DataGridTemplateColumnExt CanUserResize="False" CanUserSort="False" Header="Cover" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
|
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt MinWidth="150" Width="2*" Header="Title" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
<controls:DataGridTemplateColumnExt Header="Title" MinWidth="10" Width="{Binding TitleWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -98,7 +100,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Authors" CanUserSort="True" SortMemberPath="Authors" ClipboardContentBinding="{Binding Authors}">
|
<controls:DataGridTemplateColumnExt Header="Authors" MinWidth="10" Width="{Binding AuthorsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Authors" ClipboardContentBinding="{Binding Authors}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -108,7 +110,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Narrators" CanUserSort="True" SortMemberPath="Narrators" ClipboardContentBinding="{Binding Narrators}">
|
<controls:DataGridTemplateColumnExt Header="Narrators" MinWidth="10" Width="{Binding NarratorsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Narrators" ClipboardContentBinding="{Binding Narrators}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -118,7 +120,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="90" Header="Length" CanUserSort="True" SortMemberPath="Length" ClipboardContentBinding="{Binding Length}">
|
<controls:DataGridTemplateColumnExt Header="Length" MinWidth="10" Width="{Binding LengthWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Length" ClipboardContentBinding="{Binding Length}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -128,7 +130,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Series" CanUserSort="True" SortMemberPath="Series" ClipboardContentBinding="{Binding Series}">
|
<controls:DataGridTemplateColumnExt Header="Series" MinWidth="10" Width="{Binding SeriesWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Series" ClipboardContentBinding="{Binding Series}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -138,7 +140,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="Auto" Header="Series
Order" CanUserSort="True" SortMemberPath="SeriesOrder" ClipboardContentBinding="{Binding Series}">
|
<controls:DataGridTemplateColumnExt Header="Series
Order" MinWidth="10" Width="{Binding SeriesOrderWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="SeriesOrder" ClipboardContentBinding="{Binding Series}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -148,7 +150,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt MinWidth="100" Width="1*" Header="Description" CanUserSort="True" SortMemberPath="Description" ClipboardContentBinding="{Binding Description}">
|
<controls:DataGridTemplateColumnExt Header="Description" MinWidth="10" Width="{Binding DescriptionWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Description" ClipboardContentBinding="{Binding Description}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||||
@@ -158,7 +160,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="100" Header="Category" CanUserSort="True" SortMemberPath="Category" ClipboardContentBinding="{Binding Category}">
|
<controls:DataGridTemplateColumnExt Header="Category" MinWidth="10" Width="{Binding CategoryWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Category" ClipboardContentBinding="{Binding Category}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -172,14 +174,14 @@
|
|||||||
x:DataType="uibase:IGridEntry"
|
x:DataType="uibase:IGridEntry"
|
||||||
Header="Product
Rating"
|
Header="Product
Rating"
|
||||||
IsReadOnly="true"
|
IsReadOnly="true"
|
||||||
Width="115"
|
MinWidth="10" Width="{Binding ProductRatingWidth, Mode=TwoWay}"
|
||||||
SortMemberPath="ProductRating" CanUserSort="True"
|
SortMemberPath="ProductRating" CanUserSort="True"
|
||||||
OpacityBinding="{CompiledBinding Liberate.Opacity}"
|
OpacityBinding="{CompiledBinding Liberate.Opacity}"
|
||||||
BackgroundBinding="{CompiledBinding Liberate.BackgroundBrush}"
|
BackgroundBinding="{CompiledBinding Liberate.BackgroundBrush}"
|
||||||
ClipboardContentBinding="{CompiledBinding ProductRating}"
|
ClipboardContentBinding="{CompiledBinding ProductRating}"
|
||||||
Binding="{CompiledBinding ProductRating}" />
|
Binding="{CompiledBinding ProductRating}" />
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="90" Header="Purchase
Date" CanUserSort="True" SortMemberPath="PurchaseDate" ClipboardContentBinding="{Binding PurchaseDate}">
|
<controls:DataGridTemplateColumnExt Header="Purchase
Date" MinWidth="10" Width="{Binding PurchaseDateWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="PurchaseDate" ClipboardContentBinding="{Binding PurchaseDate}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -191,16 +193,16 @@
|
|||||||
|
|
||||||
<controls:DataGridMyRatingColumn
|
<controls:DataGridMyRatingColumn
|
||||||
x:DataType="uibase:IGridEntry"
|
x:DataType="uibase:IGridEntry"
|
||||||
Header="My Rating"
|
Header="My Rating"
|
||||||
IsReadOnly="false"
|
IsReadOnly="false"
|
||||||
Width="115"
|
MinWidth="10" Width="{Binding MyRatingWidth, Mode=TwoWay}"
|
||||||
SortMemberPath="MyRating" CanUserSort="True"
|
SortMemberPath="MyRating" CanUserSort="True"
|
||||||
OpacityBinding="{CompiledBinding Liberate.Opacity}"
|
OpacityBinding="{CompiledBinding Liberate.Opacity}"
|
||||||
BackgroundBinding="{CompiledBinding Liberate.BackgroundBrush}"
|
BackgroundBinding="{CompiledBinding Liberate.BackgroundBrush}"
|
||||||
ClipboardContentBinding="{CompiledBinding MyRating}"
|
ClipboardContentBinding="{CompiledBinding MyRating}"
|
||||||
Binding="{CompiledBinding MyRating, Mode=TwoWay}" />
|
Binding="{CompiledBinding MyRating, Mode=TwoWay}" />
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
<controls:DataGridTemplateColumnExt Header="Misc" MinWidth="10" Width="{Binding MiscWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||||
@@ -210,7 +212,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="102" Header="Last
Download" CanUserSort="True" SortMemberPath="LastDownload" ClipboardContentBinding="{Binding LastDownload}">
|
<controls:DataGridTemplateColumnExt Header="Last
Download" MinWidth="10" Width="{Binding LastDownloadWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="LastDownload" ClipboardContentBinding="{Binding LastDownload}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" ToolTip.Tip="{CompiledBinding LastDownload.ToolTipText}" DoubleTapped="Version_DoubleClick">
|
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" ToolTip.Tip="{CompiledBinding LastDownload.ToolTipText}" DoubleTapped="Version_DoubleClick">
|
||||||
@@ -220,7 +222,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Width="100" Header="Tags" SortMemberPath="BookTags" ClipboardContentBinding="{Binding BookTags}">
|
<controls:DataGridTemplateColumnExt Header="Tags" MinWidth="10" Width="{Binding BookTagsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="BookTags" ClipboardContentBinding="{Binding BookTags}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using LibationAvalonia.Dialogs;
|
|||||||
using LibationAvalonia.ViewModels;
|
using LibationAvalonia.ViewModels;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationUiBase.GridView;
|
using LibationUiBase.GridView;
|
||||||
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -172,126 +173,107 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args)
|
public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args)
|
||||||
{
|
{
|
||||||
|
var entry = args.GridEntry;
|
||||||
|
var ctx = new GridContextMenu(entry, '_');
|
||||||
|
|
||||||
if (args.Column.SortMemberPath is not "Liberate" and not "Cover")
|
if (args.Column.SortMemberPath is not "Liberate" and not "Cover")
|
||||||
{
|
{
|
||||||
var menuItem = new MenuItem { Header = "_Copy Cell Contents" };
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
menuItem.Click += async (s, e)
|
Header = ctx.CopyCellText,
|
||||||
=> await App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents);
|
Command = ReactiveCommand.CreateFromTask(() => App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents))
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(menuItem);
|
|
||||||
args.ContextMenuItems.Add(new Separator());
|
args.ContextMenuItems.Add(new Separator());
|
||||||
}
|
}
|
||||||
var entry = args.GridEntry;
|
|
||||||
|
|
||||||
#region Liberate all Episodes
|
#region Liberate all Episodes
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
if (entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var liberateEpisodesMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "_Liberate All Episodes",
|
Header = ctx.LiberateEpisodesText,
|
||||||
IsEnabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
IsEnabled = ctx.LiberateEpisodesEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(() => LiberateSeriesClicked?.Invoke(this, (ISeriesEntry)entry))
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(liberateEpisodesMenuItem);
|
|
||||||
|
|
||||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, ((ISeriesEntry)entry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Set Download status to Downloaded
|
#region Set Download status to Downloaded
|
||||||
|
|
||||||
var setDownloadMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "Set Download status to '_Downloaded'",
|
Header = ctx.SetDownloadedText,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
IsEnabled = ctx.SetDownloadedEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(ctx.SetDownloaded)
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(setDownloadMenuItem);
|
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
else
|
|
||||||
setDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Set Download status to Not Downloaded
|
#region Set Download status to Not Downloaded
|
||||||
|
|
||||||
var setNotDownloadMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "Set Download status to '_Not Downloaded'",
|
Header = ctx.SetNotDownloadedText,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
IsEnabled = ctx.SetNotDownloadedEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(ctx.SetNotDownloaded)
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(setNotDownloadMenuItem);
|
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setNotDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
else
|
|
||||||
setNotDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Remove from library
|
#region Remove from library
|
||||||
|
|
||||||
var removeMenuItem = new MenuItem() { Header = "_Remove from library" };
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
args.ContextMenuItems.Add(removeMenuItem);
|
Header = ctx.RemoveText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(ctx.RemoveAsync)
|
||||||
if (entry.Liberate.IsSeries)
|
});
|
||||||
removeMenuItem.Click += async (_, __) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
|
||||||
else
|
|
||||||
removeMenuItem.Click += async (_, __) => await Task.Run(entry.LibraryBook.RemoveBook);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
#region Locate file
|
#region Locate file
|
||||||
var locateFileMenuItem = new MenuItem() { Header = "_Locate file..." };
|
|
||||||
|
|
||||||
args.ContextMenuItems.Add(locateFileMenuItem);
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
|
||||||
locateFileMenuItem.Click += async (_, __) =>
|
|
||||||
{
|
{
|
||||||
try
|
Header = ctx.LocateFileText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
var window = this.GetParentWindow();
|
try
|
||||||
|
|
||||||
var openFileDialogOptions = new FilePickerOpenOptions
|
|
||||||
{
|
{
|
||||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
var window = this.GetParentWindow();
|
||||||
AllowMultiple = false,
|
|
||||||
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
var openFileDialogOptions = new FilePickerOpenOptions
|
||||||
FileTypeFilter = new FilePickerFileType[]
|
|
||||||
{
|
{
|
||||||
new("All files (*.*)") { Patterns = new[] { "*" } },
|
Title = ctx.LocateFileDialogTitle,
|
||||||
}
|
AllowMultiple = false,
|
||||||
};
|
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
||||||
|
FileTypeFilter = new FilePickerFileType[]
|
||||||
|
{
|
||||||
|
new("All files (*.*)") { Patterns = new[] { "*" } },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var selectedFiles = await window.StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
var selectedFiles = await window.StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||||
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
|
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
|
||||||
|
|
||||||
if (selectedFile is not null)
|
if (selectedFile is not null)
|
||||||
FilePathCache.Insert(entry.AudibleProductId, selectedFile);
|
FilePathCache.Insert(entry.AudibleProductId, selectedFile);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var msg = "Error saving book's location";
|
await MessageBox.ShowAdminAlert(null, ctx.LocateFileErrorMessage, ctx.LocateFileErrorMessage, ex);
|
||||||
await MessageBox.ShowAdminAlert(null, msg, msg, ex);
|
}
|
||||||
}
|
})
|
||||||
};
|
});
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Convert to Mp3
|
#region Convert to Mp3
|
||||||
var convertToMp3MenuItem = new MenuItem
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
{
|
{
|
||||||
Header = "_Convert to Mp3",
|
Header = ctx.ConvertToMp3Text,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
IsEnabled = ctx.ConvertToMp3Enabled,
|
||||||
};
|
Command = ReactiveCommand.Create(() => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook))
|
||||||
args.ContextMenuItems.Add(convertToMp3MenuItem);
|
});
|
||||||
|
|
||||||
convertToMp3MenuItem.Click += (_, _) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -299,34 +281,72 @@ namespace LibationAvalonia.Views
|
|||||||
#region Force Re-Download
|
#region Force Re-Download
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var reDownloadMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "Re-download this audiobook",
|
Header = ctx.ReDownloadText,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
IsEnabled = ctx.ReDownloadEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
args.ContextMenuItems.Add(reDownloadMenuItem);
|
//No need to persist this change. It only needs to last long for the file to start downloading
|
||||||
reDownloadMenuItem.Click += (s, _) =>
|
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
||||||
{
|
LiberateClicked?.Invoke(this, entry.LibraryBook);
|
||||||
//No need to persist this change. It only needs to last long for the file to start downloading
|
})
|
||||||
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
});
|
||||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
args.ContextMenuItems.Add(new Separator());
|
args.ContextMenuItems.Add(new Separator());
|
||||||
|
|
||||||
|
#region Edit Templates
|
||||||
|
async Task editTemplate<T>(LibraryBook libraryBook, string existingTemplate, Action<string> setNewTemplate)
|
||||||
|
where T : Templates, LibationFileManager.ITemplate, new()
|
||||||
|
{
|
||||||
|
var template = ctx.CreateTemplateEditor<T>(libraryBook, existingTemplate);
|
||||||
|
var form = new EditTemplateDialog(template);
|
||||||
|
if (await form.ShowDialog<DialogResult>(this.GetParentWindow()) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
setNewTemplate(template.EditingTemplate.TemplateText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.Liberate.IsSeries)
|
||||||
|
{
|
||||||
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.EditTemplatesText,
|
||||||
|
ItemsSource = new[]
|
||||||
|
{
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.FolderTemplateText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(() => editTemplate<Templates.FolderTemplate>(entry.LibraryBook, Configuration.Instance.FolderTemplate, t => Configuration.Instance.FolderTemplate = t))
|
||||||
|
},
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.FileTemplateText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(() => editTemplate<Templates.FileTemplate>(entry.LibraryBook, Configuration.Instance.FileTemplate, t => Configuration.Instance.FileTemplate = t))
|
||||||
|
},
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.MultipartTemplateText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(() => editTemplate<Templates.ChapterFileTemplate>(entry.LibraryBook, Configuration.Instance.ChapterFileTemplate, t => Configuration.Instance.ChapterFileTemplate = t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
args.ContextMenuItems.Add(new Separator());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region View Bookmarks/Clips
|
#region View Bookmarks/Clips
|
||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
var bookRecordMenuItem = new MenuItem { Header = "View _Bookmarks/Clips" };
|
{
|
||||||
|
Header = ctx.ViewBookmarksText,
|
||||||
args.ContextMenuItems.Add(bookRecordMenuItem);
|
Command = ReactiveCommand.CreateFromTask(() => new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window))
|
||||||
|
});
|
||||||
bookRecordMenuItem.Click += async (_, _) => await new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -334,12 +354,11 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
if (entry.Book.SeriesLink.Any())
|
if (entry.Book.SeriesLink.Any())
|
||||||
{
|
{
|
||||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
var viewSeriesMenuItem = new MenuItem { Header = header };
|
{
|
||||||
|
Header = ctx.ViewSeriesText,
|
||||||
args.ContextMenuItems.Add(viewSeriesMenuItem);
|
Command = ReactiveCommand.Create(() => new SeriesViewDialog(entry.LibraryBook).Show())
|
||||||
|
});
|
||||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
@@ -11,6 +11,10 @@
|
|||||||
<IsPublishable>True</IsPublishable>
|
<IsPublishable>True</IsPublishable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
|
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,20 +8,21 @@ using Dinah.Core;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
|
using AaxDecrypter;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace LibationFileManager
|
namespace LibationFileManager
|
||||||
{
|
{
|
||||||
public abstract class AudibleFileStorage
|
public abstract class AudibleFileStorage
|
||||||
{
|
{
|
||||||
protected abstract LongPath? GetFilePathCustom(string productId);
|
protected abstract LongPath? GetFilePathCustom(string productId);
|
||||||
protected abstract List<LongPath> GetFilePathsCustom(string productId);
|
protected abstract List<LongPath> GetFilePathsCustom(string productId);
|
||||||
|
|
||||||
#region static
|
#region static
|
||||||
public static LongPath DownloadsInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DownloadsInProgress")).FullName;
|
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;
|
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.
|
//Clean up any partially-decrypted files from previous Libation instances.
|
||||||
//Do no clean DownloadsInProgressDirectory because those files are resumable
|
//Do no clean DownloadsInProgressDirectory because those files are resumable
|
||||||
@@ -31,103 +32,103 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
|
|
||||||
private static AaxcFileStorage AAXC { get; } = new AaxcFileStorage();
|
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
|
public static LongPath BooksDirectory
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
|
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
|
||||||
Configuration.Instance.Books = Path.Combine(Configuration.UserProfile, "Books");
|
Configuration.Instance.Books = Path.Combine(Configuration.UserProfile, "Books");
|
||||||
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
|
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region instance
|
#region instance
|
||||||
private FileType FileType { get; }
|
private FileType FileType { get; }
|
||||||
private string regexTemplate { get; }
|
private string regexTemplate { get; }
|
||||||
|
|
||||||
protected AudibleFileStorage(FileType fileType)
|
protected AudibleFileStorage(FileType fileType)
|
||||||
{
|
{
|
||||||
FileType = fileType;
|
FileType = fileType;
|
||||||
|
|
||||||
var extAggr = FileTypes.GetExtensions(FileType).Aggregate((a, b) => $"{a}|{b}");
|
var extAggr = FileTypes.GetExtensions(FileType).Aggregate((a, b) => $"{a}|{b}");
|
||||||
regexTemplate = $@"{{0}}.*?\.({extAggr})$";
|
regexTemplate = $@"{{0}}.*?\.({extAggr})$";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LongPath? GetFilePath(string productId)
|
protected LongPath? GetFilePath(string productId)
|
||||||
{
|
{
|
||||||
// primary lookup
|
// primary lookup
|
||||||
var cachedFile = FilePathCache.GetFirstPath(productId, FileType);
|
var cachedFile = FilePathCache.GetFirstPath(productId, FileType);
|
||||||
if (cachedFile is not null && File.Exists(cachedFile))
|
if (cachedFile is not null && File.Exists(cachedFile))
|
||||||
return cachedFile;
|
return cachedFile;
|
||||||
|
|
||||||
// secondary lookup attempt
|
// secondary lookup attempt
|
||||||
var firstOrNull = GetFilePathCustom(productId);
|
var firstOrNull = GetFilePathCustom(productId);
|
||||||
if (firstOrNull is not null)
|
if (firstOrNull is not null)
|
||||||
FilePathCache.Insert(productId, firstOrNull);
|
FilePathCache.Insert(productId, firstOrNull);
|
||||||
|
|
||||||
return firstOrNull;
|
return firstOrNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LongPath> GetPaths(string productId)
|
public List<LongPath> GetPaths(string productId)
|
||||||
=> GetFilePathsCustom(productId);
|
=> GetFilePathsCustom(productId);
|
||||||
|
|
||||||
protected Regex GetBookSearchRegex(string productId)
|
protected Regex GetBookSearchRegex(string productId)
|
||||||
{
|
{
|
||||||
var pattern = string.Format(regexTemplate, productId);
|
var pattern = string.Format(regexTemplate, productId);
|
||||||
return new Regex(pattern, RegexOptions.IgnoreCase);
|
return new Regex(pattern, RegexOptions.IgnoreCase);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AaxcFileStorage : AudibleFileStorage
|
internal class AaxcFileStorage : AudibleFileStorage
|
||||||
{
|
{
|
||||||
internal AaxcFileStorage() : base(FileType.AAXC) { }
|
internal AaxcFileStorage() : base(FileType.AAXC) { }
|
||||||
|
|
||||||
protected override LongPath? GetFilePathCustom(string productId)
|
protected override LongPath? GetFilePathCustom(string productId)
|
||||||
=> GetFilePathsCustom(productId).FirstOrDefault();
|
=> GetFilePathsCustom(productId).FirstOrDefault();
|
||||||
|
|
||||||
protected override List<LongPath> GetFilePathsCustom(string productId)
|
protected override List<LongPath> GetFilePathsCustom(string productId)
|
||||||
{
|
{
|
||||||
var regex = GetBookSearchRegex(productId);
|
var regex = GetBookSearchRegex(productId);
|
||||||
return FileUtility
|
return FileUtility
|
||||||
.SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
|
.SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
|
||||||
.Where(s => regex.IsMatch(s)).ToList();
|
.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
|
public class AudioFileStorage : AudibleFileStorage
|
||||||
{
|
{
|
||||||
internal AudioFileStorage() : base(FileType.Audio)
|
internal AudioFileStorage() : base(FileType.Audio)
|
||||||
=> BookDirectoryFiles ??= newBookDirectoryFiles();
|
=> BookDirectoryFiles ??= newBookDirectoryFiles();
|
||||||
|
|
||||||
private static BackgroundFileSystem? BookDirectoryFiles { get; set; }
|
private static BackgroundFileSystem? BookDirectoryFiles { get; set; }
|
||||||
private static object bookDirectoryFilesLocker { get; } = new();
|
private static object bookDirectoryFilesLocker { get; } = new();
|
||||||
private static EnumerationOptions enumerationOptions { get; } = new()
|
private static EnumerationOptions enumerationOptions { get; } = new()
|
||||||
{
|
{
|
||||||
RecurseSubdirectories = true,
|
RecurseSubdirectories = true,
|
||||||
IgnoreInaccessible = true,
|
IgnoreInaccessible = true,
|
||||||
MatchCasing = MatchCasing.CaseInsensitive
|
AttributesToSkip = FileAttributes.Hidden,
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override LongPath? GetFilePathCustom(string productId)
|
protected override LongPath? GetFilePathCustom(string productId)
|
||||||
=> GetFilePathsCustom(productId).FirstOrDefault();
|
=> GetFilePathsCustom(productId).FirstOrDefault();
|
||||||
|
|
||||||
private static BackgroundFileSystem newBookDirectoryFiles()
|
private static BackgroundFileSystem newBookDirectoryFiles()
|
||||||
=> new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
|
=> new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
|
||||||
|
|
||||||
protected override List<LongPath> GetFilePathsCustom(string productId)
|
protected override List<LongPath> GetFilePathsCustom(string productId)
|
||||||
{
|
{
|
||||||
// If user changed the BooksDirectory: reinitialize
|
// If user changed the BooksDirectory: reinitialize
|
||||||
lock (bookDirectoryFilesLocker)
|
lock (bookDirectoryFilesLocker)
|
||||||
if (BooksDirectory != BookDirectoryFiles?.RootDirectory)
|
if (BooksDirectory != BookDirectoryFiles?.RootDirectory)
|
||||||
BookDirectoryFiles = newBookDirectoryFiles();
|
BookDirectoryFiles = newBookDirectoryFiles();
|
||||||
|
|
||||||
var regex = GetBookSearchRegex(productId);
|
var regex = GetBookSearchRegex(productId);
|
||||||
|
|
||||||
@@ -135,44 +136,60 @@ namespace LibationFileManager
|
|||||||
//using both the file system and the file path cache
|
//using both the file system and the file path cache
|
||||||
return
|
return
|
||||||
FilePathCache
|
FilePathCache
|
||||||
.GetFiles(productId)
|
.GetFiles(productId)
|
||||||
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
|
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
|
||||||
.Select(c => c.path)
|
.Select(c => c.path)
|
||||||
.Union(BookDirectoryFiles.FindFiles(regex))
|
.Union(BookDirectoryFiles.FindFiles(regex))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
{
|
{
|
||||||
if (BookDirectoryFiles is null)
|
if (BookDirectoryFiles is null)
|
||||||
lock (bookDirectoryFilesLocker)
|
lock (bookDirectoryFilesLocker)
|
||||||
BookDirectoryFiles = newBookDirectoryFiles();
|
BookDirectoryFiles = newBookDirectoryFiles();
|
||||||
else
|
else
|
||||||
BookDirectoryFiles?.RefreshFiles();
|
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)
|
public static async IAsyncEnumerable<FilePathCache.CacheEntry> FindAudiobooksAsync(LongPath searchDirectory, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ArgumentValidator.EnsureNotNull(searchDirectory, nameof(searchDirectory));
|
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)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
|
if (getFormatByExtension(path) is not OutputFormat format)
|
||||||
|
continue;
|
||||||
|
|
||||||
FilePathCache.CacheEntry? audioFile = default;
|
FilePathCache.CacheEntry? audioFile = default;
|
||||||
|
|
||||||
try
|
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)
|
var asin = id3?.Children
|
||||||
audioFile = new FilePathCache.CacheEntry(mp4File.AppleTags.Asin, FileType.Audio, path);
|
.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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -186,6 +203,15 @@ namespace LibationFileManager
|
|||||||
if (audioFile is not null)
|
if (audioFile is not null)
|
||||||
yield return audioFile;
|
yield return audioFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static OutputFormat? getFormatByExtension(string path)
|
||||||
|
{
|
||||||
|
var ext = Path.GetExtension(path).ToLower();
|
||||||
|
|
||||||
|
return ext == ".mp3" ? OutputFormat.Mp3
|
||||||
|
: ext == ".m4b" ? OutputFormat.M4b
|
||||||
|
: null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Dinah.Core.Logging;
|
using Dinah.Core.Logging;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace LibationFileManager
|
namespace LibationFileManager
|
||||||
@@ -75,17 +76,19 @@ namespace LibationFileManager
|
|||||||
const string appsettings_filename = "appsettings.json";
|
const string appsettings_filename = "appsettings.json";
|
||||||
|
|
||||||
//Possible appsettings.json locations, in order of preference.
|
//Possible appsettings.json locations, in order of preference.
|
||||||
string[] possibleAppsettingsFiles = new[]
|
string[] possibleAppsettingsDirectories = new[]
|
||||||
{
|
{
|
||||||
Path.Combine(ProcessDirectory, appsettings_filename),
|
ProcessDirectory,
|
||||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation", appsettings_filename),
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation"),
|
||||||
Path.Combine(UserProfile, appsettings_filename),
|
UserProfile,
|
||||||
Path.Combine(Path.GetTempPath(), "Libation", appsettings_filename)
|
Path.Combine(Path.GetTempPath(), "Libation")
|
||||||
};
|
};
|
||||||
|
|
||||||
//Try to find and validate appsettings.json in each folder
|
//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))
|
if (File.Exists(appsettingsFile))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -104,10 +107,13 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
//Valid appsettings.json not found. Try to create it in each folder.
|
//Valid appsettings.json not found. Try to create it in each folder.
|
||||||
var endingContents = new JObject { { LIBATION_FILES_KEY, UserProfile } }.ToString(Formatting.Indented);
|
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
|
try
|
||||||
{
|
{
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
File.WriteAllText(appsettingsFile, endingContents);
|
File.WriteAllText(appsettingsFile, endingContents);
|
||||||
return appsettingsFile;
|
return appsettingsFile;
|
||||||
}
|
}
|
||||||
@@ -121,16 +127,56 @@ namespace LibationFileManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static string getLibationFilesSettingFromJson()
|
private static string getLibationFilesSettingFromJson()
|
||||||
{
|
{
|
||||||
// do not check whether directory exists. special/meta directory (eg: AppDir) is valid
|
// 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
|
// verify from live file. no try/catch. want failures to be visible
|
||||||
var jObjFinal = JObject.Parse(File.ReadAllText(AppsettingsJsonFile));
|
var jObjFinal = JObject.Parse(File.ReadAllText(AppsettingsJsonFile));
|
||||||
|
|
||||||
if (jObjFinal[LIBATION_FILES_KEY]?.Value<string>() is not string valueFinal)
|
if (jObjFinal[LIBATION_FILES_KEY]?.Value<string>() is not string valueFinal)
|
||||||
throw new InvalidDataException($"{LIBATION_FILES_KEY} not found in {AppsettingsJsonFile}");
|
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)
|
public static void SetLibationFiles(string directory)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,9 +95,9 @@ namespace LibationFileManager
|
|||||||
var assembly = CurrentDomain_AssemblyResolve_internal(asmName, here: here);
|
var assembly = CurrentDomain_AssemblyResolve_internal(asmName, here: here);
|
||||||
lowEffortCache[key] = assembly;
|
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)
|
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;
|
return assembly;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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="NameParserSharp" Version="1.5.0" />
|
||||||
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ namespace LibationFileManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly LibraryBookDto libraryBookDto
|
public LibraryBookDto FolderBook { get; }
|
||||||
|
public LibraryBookDto LibraryBook { get; }
|
||||||
|
|
||||||
|
private static readonly LibraryBookDto DefaultLibraryBook
|
||||||
= new()
|
= new()
|
||||||
{
|
{
|
||||||
Account = "myaccount@example.co",
|
Account = "myaccount@example.co",
|
||||||
@@ -60,6 +63,7 @@ namespace LibationFileManager
|
|||||||
DatePublished = new DateTime(2017, 2, 27, 0, 0, 0),
|
DatePublished = new DateTime(2017, 2, 27, 0, 0, 0),
|
||||||
AudibleProductId = "123456789",
|
AudibleProductId = "123456789",
|
||||||
Title = "A Study in Scarlet",
|
Title = "A Study in Scarlet",
|
||||||
|
TitleWithSubtitle = "A Study in Scarlet: A Sherlock Holmes Novel",
|
||||||
Subtitle = "A Sherlock Holmes Novel",
|
Subtitle = "A Sherlock Holmes Novel",
|
||||||
Locale = "us",
|
Locale = "us",
|
||||||
YearPublished = 2017,
|
YearPublished = 2017,
|
||||||
@@ -73,7 +77,7 @@ namespace LibationFileManager
|
|||||||
Language = "English"
|
Language = "English"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly MultiConvertFileProperties partFileProperties
|
private static readonly MultiConvertFileProperties DefaultMultipartProperties
|
||||||
= new()
|
= new()
|
||||||
{
|
{
|
||||||
OutputFileName = "",
|
OutputFileName = "",
|
||||||
@@ -90,23 +94,27 @@ namespace LibationFileManager
|
|||||||
* subdirectories. Without rooting, we won't be allowed to create a
|
* subdirectories. Without rooting, we won't be allowed to create a
|
||||||
* relative path longer than MAX_PATH.
|
* relative path longer than MAX_PATH.
|
||||||
*/
|
*/
|
||||||
var dir = Folder?.GetFilename(libraryBookDto, BaseDirectory, "");
|
var dir = Folder?.GetFilename(FolderBook, BaseDirectory, "");
|
||||||
if (dir is null) return null;
|
if (dir is null) return null;
|
||||||
return Path.GetRelativePath(BaseDirectory, dir);
|
return Path.GetRelativePath(BaseDirectory, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetFileName()
|
public string? GetFileName()
|
||||||
=> File?.GetFilename(libraryBookDto, partFileProperties, "", "");
|
=> File?.GetFilename(LibraryBook, DefaultMultipartProperties, "", "");
|
||||||
public string? GetName()
|
public string? GetName()
|
||||||
=> Name?.GetName(libraryBookDto, partFileProperties);
|
=> Name?.GetName(LibraryBook, DefaultMultipartProperties);
|
||||||
|
|
||||||
private TemplateEditor(
|
private TemplateEditor(
|
||||||
|
LibraryBookDto? folderDto,
|
||||||
|
LibraryBookDto? fileDto,
|
||||||
Templates editingTemplate,
|
Templates editingTemplate,
|
||||||
LongPath baseDirectory,
|
LongPath baseDirectory,
|
||||||
string defaultTemplate,
|
string defaultTemplate,
|
||||||
string templateName,
|
string templateName,
|
||||||
string templateDescription)
|
string templateDescription)
|
||||||
{
|
{
|
||||||
|
FolderBook = folderDto ?? DefaultLibraryBook;
|
||||||
|
LibraryBook = fileDto ?? DefaultLibraryBook;
|
||||||
_editingTemplate = editingTemplate;
|
_editingTemplate = editingTemplate;
|
||||||
BaseDirectory = baseDirectory;
|
BaseDirectory = baseDirectory;
|
||||||
DefaultTemplate = defaultTemplate;
|
DefaultTemplate = defaultTemplate;
|
||||||
@@ -114,25 +122,30 @@ namespace LibationFileManager
|
|||||||
TemplateDescription = templateDescription;
|
TemplateDescription = templateDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITemplateEditor CreateFilenameEditor(LongPath baseDir, string templateText)
|
public static ITemplateEditor CreateFilenameEditor(LongPath baseDir, string templateText, LibraryBookDto? folderDto = null, LibraryBookDto? fileDto = null)
|
||||||
{
|
{
|
||||||
if (!Templates.TryGetTemplate<T>(templateText, out var template))
|
if (!Templates.TryGetTemplate<T>(templateText, out var template))
|
||||||
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
||||||
|
|
||||||
var templateEditor = new TemplateEditor<T>(template, baseDir, T.DefaultTemplate, T.Name, T.Description);
|
var templateEditor = new TemplateEditor<T>(folderDto, fileDto, template, baseDir, T.DefaultTemplate, T.Name, T.Description);
|
||||||
|
|
||||||
if (!templateEditor.IsFolder && !templateEditor.IsFilePath)
|
if (!templateEditor.IsFolder && !templateEditor.IsFilePath)
|
||||||
throw new InvalidOperationException($"This method is only for File and Folder templates. Use {nameof(CreateNameEditor)} for name templates");
|
throw new InvalidOperationException($"This method is only for File and Folder templates. Use {nameof(CreateNameEditor)} for name templates");
|
||||||
|
|
||||||
|
if (templateEditor.IsFolder)
|
||||||
|
templateEditor.File = Templates.File;
|
||||||
|
else
|
||||||
|
templateEditor.Folder = Templates.Folder;
|
||||||
|
|
||||||
return templateEditor;
|
return templateEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITemplateEditor CreateNameEditor(string templateText)
|
public static ITemplateEditor CreateNameEditor(string templateText, LibraryBookDto? libraryBookDto = null)
|
||||||
{
|
{
|
||||||
if (!Templates.TryGetTemplate<T>(templateText, out var nameTemplate))
|
if (!Templates.TryGetTemplate<T>(templateText, out var nameTemplate))
|
||||||
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
||||||
|
|
||||||
var templateEditor = new TemplateEditor<T>(nameTemplate, "", T.DefaultTemplate, T.Name, T.Description);
|
var templateEditor = new TemplateEditor<T>(null, libraryBookDto, nameTemplate, "", T.DefaultTemplate, T.Name, T.Description);
|
||||||
|
|
||||||
if (templateEditor.IsFolder || templateEditor.IsFilePath)
|
if (templateEditor.IsFolder || templateEditor.IsFilePath)
|
||||||
throw new InvalidOperationException($"This method is only for name templates. Use {nameof(CreateFilenameEditor)} for file templates");
|
throw new InvalidOperationException($"This method is only for name templates. Use {nameof(CreateFilenameEditor)} for file templates");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LuceneNet303r2" Version="3.0.3.5" />
|
<PackageReference Include="LuceneNet303r2" Version="3.0.3.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ namespace LibationUiBase.GridView
|
|||||||
private string GetTooltip()
|
private string GetTooltip()
|
||||||
{
|
{
|
||||||
if (IsSeries)
|
if (IsSeries)
|
||||||
return Expanded ? "Click to Collpase" : "Click to Expand";
|
return Expanded ? "Click to Collapse" : "Click to Expand";
|
||||||
|
|
||||||
if (IsUnavailable)
|
if (IsUnavailable)
|
||||||
return "This book cannot be downloaded\nbecause it wasn't found during\nthe most recent library scan";
|
return "This book cannot be downloaded\nbecause it wasn't found during\nthe most recent library scan";
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
using ApplicationServices;
|
||||||
|
using DataLayer;
|
||||||
|
using FileLiberator;
|
||||||
|
using LibationFileManager;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace LibationUiBase.GridView;
|
||||||
|
|
||||||
|
public class GridContextMenu
|
||||||
|
{
|
||||||
|
public string CopyCellText => $"{Accelerator}Copy Cell Contents";
|
||||||
|
public string LiberateEpisodesText => $"{Accelerator}Liberate All Episodes";
|
||||||
|
public string SetDownloadedText => $"Set Download status to '{Accelerator}Downloaded'";
|
||||||
|
public string SetNotDownloadedText => $"Set Download status to '{Accelerator}Not Downloaded'";
|
||||||
|
public string RemoveText => $"{Accelerator}Remove from library";
|
||||||
|
public string LocateFileText => $"{Accelerator}Locate file...";
|
||||||
|
public string LocateFileDialogTitle => $"Locate the audio file for '{GridEntry.Book.TitleWithSubtitle}'";
|
||||||
|
public string LocateFileErrorMessage => "Error saving book's location";
|
||||||
|
public string ConvertToMp3Text => $"{Accelerator}Convert to Mp3";
|
||||||
|
public string ReDownloadText => "Re-download this audiobook";
|
||||||
|
public string EditTemplatesText => "Edit Templates";
|
||||||
|
public string FolderTemplateText => "Folder Template";
|
||||||
|
public string FileTemplateText => "File Template";
|
||||||
|
public string MultipartTemplateText => "Multipart File Template";
|
||||||
|
public string ViewBookmarksText => "View _Bookmarks/Clips";
|
||||||
|
public string ViewSeriesText => GridEntry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
||||||
|
|
||||||
|
public bool LiberateEpisodesEnabled => GridEntry is ISeriesEntry sEntry && sEntry.Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload);
|
||||||
|
public bool SetDownloadedEnabled => GridEntry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || GridEntry.Liberate.IsSeries;
|
||||||
|
public bool SetNotDownloadedEnabled => GridEntry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || GridEntry.Liberate.IsSeries;
|
||||||
|
public bool ConvertToMp3Enabled => GridEntry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated;
|
||||||
|
public bool ReDownloadEnabled => GridEntry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated;
|
||||||
|
|
||||||
|
public IGridEntry GridEntry { get; }
|
||||||
|
public char Accelerator { get; }
|
||||||
|
|
||||||
|
public GridContextMenu(IGridEntry gridEntry, char accelerator)
|
||||||
|
{
|
||||||
|
GridEntry = gridEntry;
|
||||||
|
Accelerator = accelerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDownloaded()
|
||||||
|
{
|
||||||
|
if (GridEntry is ISeriesEntry series)
|
||||||
|
{
|
||||||
|
series.Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GridEntry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetNotDownloaded()
|
||||||
|
{
|
||||||
|
if (GridEntry is ISeriesEntry series)
|
||||||
|
{
|
||||||
|
series.Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GridEntry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveAsync()
|
||||||
|
{
|
||||||
|
if (GridEntry is ISeriesEntry series)
|
||||||
|
{
|
||||||
|
await series.Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Run(GridEntry.LibraryBook.RemoveBook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITemplateEditor CreateTemplateEditor<T>(LibraryBook libraryBook, string existingTemplate)
|
||||||
|
where T : Templates, ITemplate, new()
|
||||||
|
{
|
||||||
|
LibraryBookDto fileDto = libraryBook.ToDto(), folderDto = fileDto;
|
||||||
|
|
||||||
|
if (libraryBook.Book.IsEpisodeChild() &&
|
||||||
|
Configuration.Instance.SavePodcastsToParentFolder &&
|
||||||
|
libraryBook.Book.SeriesLink.SingleOrDefault() is SeriesBook series)
|
||||||
|
{
|
||||||
|
using var context = DbContexts.GetContext();
|
||||||
|
var seriesParent = context.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId);
|
||||||
|
folderDto = seriesParent?.ToDto() ?? fileDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TemplateEditor<T>.CreateFilenameEditor(Configuration.Instance.Books, existingTemplate, folderDto, fileDto);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,7 +37,7 @@ namespace LibationUiBase.GridView
|
|||||||
private string _purchasedate;
|
private string _purchasedate;
|
||||||
private string _length;
|
private string _length;
|
||||||
private LastDownloadStatus _lastDownload;
|
private LastDownloadStatus _lastDownload;
|
||||||
private object _cover;
|
private Lazy<object> _lazyCover;
|
||||||
private string _series;
|
private string _series;
|
||||||
private SeriesOrder _seriesOrder;
|
private SeriesOrder _seriesOrder;
|
||||||
private string _title;
|
private string _title;
|
||||||
@@ -55,7 +55,7 @@ namespace LibationUiBase.GridView
|
|||||||
public string PurchaseDate { get => _purchasedate; protected set => RaiseAndSetIfChanged(ref _purchasedate, value); }
|
public string PurchaseDate { get => _purchasedate; protected set => RaiseAndSetIfChanged(ref _purchasedate, value); }
|
||||||
public string Length { get => _length; protected set => RaiseAndSetIfChanged(ref _length, value); }
|
public string Length { get => _length; protected set => RaiseAndSetIfChanged(ref _length, value); }
|
||||||
public LastDownloadStatus LastDownload { get => _lastDownload; protected set => RaiseAndSetIfChanged(ref _lastDownload, value); }
|
public LastDownloadStatus LastDownload { get => _lastDownload; protected set => RaiseAndSetIfChanged(ref _lastDownload, value); }
|
||||||
public object Cover { get => _cover; private set => RaiseAndSetIfChanged(ref _cover, value); }
|
public object Cover { get => _lazyCover.Value; }
|
||||||
public string Series { get => _series; private set => RaiseAndSetIfChanged(ref _series, value); }
|
public string Series { get => _series; private set => RaiseAndSetIfChanged(ref _series, value); }
|
||||||
public SeriesOrder SeriesOrder { get => _seriesOrder; private set => RaiseAndSetIfChanged(ref _seriesOrder, value); }
|
public SeriesOrder SeriesOrder { get => _seriesOrder; private set => RaiseAndSetIfChanged(ref _seriesOrder, value); }
|
||||||
public string Title { get => _title; private set => RaiseAndSetIfChanged(ref _title, value); }
|
public string Title { get => _title; private set => RaiseAndSetIfChanged(ref _title, value); }
|
||||||
@@ -132,7 +132,7 @@ namespace LibationUiBase.GridView
|
|||||||
int bookLenMins = GetLengthInMinutes();
|
int bookLenMins = GetLengthInMinutes();
|
||||||
return bookLenMins == 0 ? "" : $"{bookLenMins / 60} hr {bookLenMins % 60} min";
|
return bookLenMins == 0 ? "" : $"{bookLenMins / 60} hr {bookLenMins % 60} min";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region detect changes to the model, update the view.
|
#region detect changes to the model, update the view.
|
||||||
@@ -200,36 +200,31 @@ namespace LibationUiBase.GridView
|
|||||||
|
|
||||||
#region Sorting
|
#region Sorting
|
||||||
|
|
||||||
public GridEntry()
|
public object GetMemberValue(string memberName) => memberName switch
|
||||||
{
|
{
|
||||||
memberValues = new()
|
nameof(Remove) => Remove.HasValue ? Remove.Value ? RemoveStatus.Removed : RemoveStatus.NotRemoved : RemoveStatus.SomeRemoved,
|
||||||
{
|
nameof(Title) => Book.TitleSortable(),
|
||||||
{ nameof(Remove), () => Remove.HasValue ? Remove.Value ? RemoveStatus.Removed : RemoveStatus.NotRemoved : RemoveStatus.SomeRemoved },
|
nameof(Series) => Book.SeriesSortable(),
|
||||||
{ nameof(Title), () => Book.TitleSortable() },
|
nameof(SeriesOrder) => SeriesOrder,
|
||||||
{ nameof(Series), () => Book.SeriesSortable() },
|
nameof(Length) => GetLengthInMinutes(),
|
||||||
{ nameof(SeriesOrder), () => SeriesOrder },
|
nameof(MyRating) => Book.UserDefinedItem.Rating,
|
||||||
{ nameof(Length), () => GetLengthInMinutes() },
|
nameof(PurchaseDate) => GetPurchaseDate(),
|
||||||
{ nameof(MyRating), () => Book.UserDefinedItem.Rating },
|
nameof(ProductRating) => Book.Rating,
|
||||||
{ nameof(PurchaseDate), () => GetPurchaseDate() },
|
nameof(Authors) => Authors,
|
||||||
{ nameof(ProductRating), () => Book.Rating },
|
nameof(Narrators) => Narrators,
|
||||||
{ nameof(Authors), () => Authors },
|
nameof(Description) => Description,
|
||||||
{ nameof(Narrators), () => Narrators },
|
nameof(Category) => Category,
|
||||||
{ nameof(Description), () => Description },
|
nameof(Misc) => Misc,
|
||||||
{ nameof(Category), () => Category },
|
nameof(LastDownload) => LastDownload,
|
||||||
{ nameof(Misc), () => Misc },
|
nameof(BookTags) => BookTags ?? string.Empty,
|
||||||
{ nameof(LastDownload), () => LastDownload },
|
nameof(Liberate) => Liberate,
|
||||||
{ nameof(BookTags), () => BookTags ?? string.Empty },
|
nameof(DateAdded) => DateAdded,
|
||||||
{ nameof(Liberate), () => Liberate },
|
_ => null
|
||||||
{ nameof(DateAdded), () => DateAdded },
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetMemberValue(string memberName) => memberValues[memberName]();
|
|
||||||
public IComparer GetMemberComparer(Type memberType)
|
public IComparer GetMemberComparer(Type memberType)
|
||||||
=> memberTypeComparers.TryGetValue(memberType, out IComparer value) ? value : memberTypeComparers[memberType.BaseType];
|
=> memberTypeComparers.TryGetValue(memberType, out IComparer value) ? value : memberTypeComparers[memberType.BaseType];
|
||||||
|
|
||||||
private readonly Dictionary<string, Func<object>> memberValues;
|
|
||||||
|
|
||||||
// Instantiate comparers for every exposed member object type.
|
// Instantiate comparers for every exposed member object type.
|
||||||
private static readonly Dictionary<Type, IComparer> memberTypeComparers = new()
|
private static readonly Dictionary<Type, IComparer> memberTypeComparers = new()
|
||||||
{
|
{
|
||||||
@@ -258,7 +253,7 @@ namespace LibationUiBase.GridView
|
|||||||
PictureStorage.PictureCached += PictureStorage_PictureCached;
|
PictureStorage.PictureCached += PictureStorage_PictureCached;
|
||||||
|
|
||||||
// Mutable property. Set the field so PropertyChanged isn't fired.
|
// Mutable property. Set the field so PropertyChanged isn't fired.
|
||||||
_cover = Liberate.LoadImage(picture);
|
_lazyCover = new Lazy<object>(() => Liberate.LoadImage(picture));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PictureStorage_PictureCached(object sender, PictureCachedEventArgs e)
|
private void PictureStorage_PictureCached(object sender, PictureCachedEventArgs e)
|
||||||
@@ -272,7 +267,8 @@ namespace LibationUiBase.GridView
|
|||||||
// logic validation
|
// logic validation
|
||||||
if (e.Definition.PictureId == Book.PictureId)
|
if (e.Definition.PictureId == Book.PictureId)
|
||||||
{
|
{
|
||||||
Cover = Liberate.LoadImage(e.Picture);
|
_lazyCover = new Lazy<object>(() => Liberate.LoadImage(e.Picture));
|
||||||
|
RaisePropertyChanged(nameof(Cover));
|
||||||
PictureStorage.PictureCached -= PictureStorage_PictureCached;
|
PictureStorage.PictureCached -= PictureStorage_PictureCached;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<IsPublishable>true</IsPublishable>
|
<IsPublishable>true</IsPublishable>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+48
-16
@@ -229,7 +229,7 @@
|
|||||||
badBookGb.Controls.Add(badBookAskRb);
|
badBookGb.Controls.Add(badBookAskRb);
|
||||||
badBookGb.Location = new System.Drawing.Point(7, 6);
|
badBookGb.Location = new System.Drawing.Point(7, 6);
|
||||||
badBookGb.Name = "badBookGb";
|
badBookGb.Name = "badBookGb";
|
||||||
badBookGb.Size = new System.Drawing.Size(836, 76);
|
badBookGb.Size = new System.Drawing.Size(841, 76);
|
||||||
badBookGb.TabIndex = 13;
|
badBookGb.TabIndex = 13;
|
||||||
badBookGb.TabStop = false;
|
badBookGb.TabStop = false;
|
||||||
badBookGb.Text = "[bad book desc]";
|
badBookGb.Text = "[bad book desc]";
|
||||||
@@ -397,6 +397,7 @@
|
|||||||
//
|
//
|
||||||
// tab1ImportantSettings
|
// tab1ImportantSettings
|
||||||
//
|
//
|
||||||
|
tab1ImportantSettings.AutoScroll = true;
|
||||||
tab1ImportantSettings.Controls.Add(groupBox1);
|
tab1ImportantSettings.Controls.Add(groupBox1);
|
||||||
tab1ImportantSettings.Controls.Add(booksGb);
|
tab1ImportantSettings.Controls.Add(booksGb);
|
||||||
tab1ImportantSettings.Controls.Add(logsBtn);
|
tab1ImportantSettings.Controls.Add(logsBtn);
|
||||||
@@ -412,6 +413,7 @@
|
|||||||
//
|
//
|
||||||
// groupBox1
|
// 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(applyDisplaySettingsBtn);
|
||||||
groupBox1.Controls.Add(gridScaleFactorLbl);
|
groupBox1.Controls.Add(gridScaleFactorLbl);
|
||||||
groupBox1.Controls.Add(gridScaleFactorTbar);
|
groupBox1.Controls.Add(gridScaleFactorTbar);
|
||||||
@@ -426,6 +428,7 @@
|
|||||||
//
|
//
|
||||||
// applyDisplaySettingsBtn
|
// applyDisplaySettingsBtn
|
||||||
//
|
//
|
||||||
|
applyDisplaySettingsBtn.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||||
applyDisplaySettingsBtn.Location = new System.Drawing.Point(689, 26);
|
applyDisplaySettingsBtn.Location = new System.Drawing.Point(689, 26);
|
||||||
applyDisplaySettingsBtn.Name = "applyDisplaySettingsBtn";
|
applyDisplaySettingsBtn.Name = "applyDisplaySettingsBtn";
|
||||||
applyDisplaySettingsBtn.Size = new System.Drawing.Size(148, 34);
|
applyDisplaySettingsBtn.Size = new System.Drawing.Size(148, 34);
|
||||||
@@ -554,6 +557,7 @@
|
|||||||
//
|
//
|
||||||
// tab2ImportLibrary
|
// tab2ImportLibrary
|
||||||
//
|
//
|
||||||
|
tab2ImportLibrary.AutoScroll = true;
|
||||||
tab2ImportLibrary.Controls.Add(autoDownloadEpisodesCb);
|
tab2ImportLibrary.Controls.Add(autoDownloadEpisodesCb);
|
||||||
tab2ImportLibrary.Controls.Add(autoScanCb);
|
tab2ImportLibrary.Controls.Add(autoScanCb);
|
||||||
tab2ImportLibrary.Controls.Add(showImportedStatsCb);
|
tab2ImportLibrary.Controls.Add(showImportedStatsCb);
|
||||||
@@ -599,6 +603,7 @@
|
|||||||
//
|
//
|
||||||
// tab3DownloadDecrypt
|
// tab3DownloadDecrypt
|
||||||
//
|
//
|
||||||
|
tab3DownloadDecrypt.AutoScroll = true;
|
||||||
tab3DownloadDecrypt.Controls.Add(saveMetadataToFileCbox);
|
tab3DownloadDecrypt.Controls.Add(saveMetadataToFileCbox);
|
||||||
tab3DownloadDecrypt.Controls.Add(useCoverAsFolderIconCb);
|
tab3DownloadDecrypt.Controls.Add(useCoverAsFolderIconCb);
|
||||||
tab3DownloadDecrypt.Controls.Add(inProgressFilesGb);
|
tab3DownloadDecrypt.Controls.Add(inProgressFilesGb);
|
||||||
@@ -764,6 +769,7 @@
|
|||||||
//
|
//
|
||||||
// tab4AudioFileOptions
|
// tab4AudioFileOptions
|
||||||
//
|
//
|
||||||
|
tab4AudioFileOptions.AutoScroll = true;
|
||||||
tab4AudioFileOptions.Controls.Add(fileDownloadQualityCb);
|
tab4AudioFileOptions.Controls.Add(fileDownloadQualityCb);
|
||||||
tab4AudioFileOptions.Controls.Add(fileDownloadQualityLbl);
|
tab4AudioFileOptions.Controls.Add(fileDownloadQualityLbl);
|
||||||
tab4AudioFileOptions.Controls.Add(combineNestedChapterTitlesCbox);
|
tab4AudioFileOptions.Controls.Add(combineNestedChapterTitlesCbox);
|
||||||
@@ -845,7 +851,7 @@
|
|||||||
audiobookFixupsGb.Controls.Add(stripAudibleBrandingCbox);
|
audiobookFixupsGb.Controls.Add(stripAudibleBrandingCbox);
|
||||||
audiobookFixupsGb.Location = new System.Drawing.Point(6, 200);
|
audiobookFixupsGb.Location = new System.Drawing.Point(6, 200);
|
||||||
audiobookFixupsGb.Name = "audiobookFixupsGb";
|
audiobookFixupsGb.Name = "audiobookFixupsGb";
|
||||||
audiobookFixupsGb.Size = new System.Drawing.Size(403, 182);
|
audiobookFixupsGb.Size = new System.Drawing.Size(385, 182);
|
||||||
audiobookFixupsGb.TabIndex = 19;
|
audiobookFixupsGb.TabIndex = 19;
|
||||||
audiobookFixupsGb.TabStop = false;
|
audiobookFixupsGb.TabStop = false;
|
||||||
audiobookFixupsGb.Text = "Audiobook Fix-ups";
|
audiobookFixupsGb.Text = "Audiobook Fix-ups";
|
||||||
@@ -872,6 +878,7 @@
|
|||||||
//
|
//
|
||||||
// chapterTitleTemplateGb
|
// 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(chapterTitleTemplateBtn);
|
||||||
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateTb);
|
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateTb);
|
||||||
chapterTitleTemplateGb.Location = new System.Drawing.Point(3, 388);
|
chapterTitleTemplateGb.Location = new System.Drawing.Point(3, 388);
|
||||||
@@ -903,6 +910,7 @@
|
|||||||
//
|
//
|
||||||
// lameOptionsGb
|
// 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(label20);
|
||||||
lameOptionsGb.Controls.Add(label21);
|
lameOptionsGb.Controls.Add(label21);
|
||||||
lameOptionsGb.Controls.Add(encoderQualityCb);
|
lameOptionsGb.Controls.Add(encoderQualityCb);
|
||||||
@@ -912,9 +920,9 @@
|
|||||||
lameOptionsGb.Controls.Add(label1);
|
lameOptionsGb.Controls.Add(label1);
|
||||||
lameOptionsGb.Controls.Add(lameQualityGb);
|
lameOptionsGb.Controls.Add(lameQualityGb);
|
||||||
lameOptionsGb.Controls.Add(groupBox2);
|
lameOptionsGb.Controls.Add(groupBox2);
|
||||||
lameOptionsGb.Location = new System.Drawing.Point(415, 6);
|
lameOptionsGb.Location = new System.Drawing.Point(397, 6);
|
||||||
lameOptionsGb.Name = "lameOptionsGb";
|
lameOptionsGb.Name = "lameOptionsGb";
|
||||||
lameOptionsGb.Size = new System.Drawing.Size(433, 376);
|
lameOptionsGb.Size = new System.Drawing.Size(450, 376);
|
||||||
lameOptionsGb.TabIndex = 14;
|
lameOptionsGb.TabIndex = 14;
|
||||||
lameOptionsGb.TabStop = false;
|
lameOptionsGb.TabStop = false;
|
||||||
lameOptionsGb.Text = "Mp3 Encoding Options";
|
lameOptionsGb.Text = "Mp3 Encoding Options";
|
||||||
@@ -930,6 +938,7 @@
|
|||||||
//
|
//
|
||||||
// label21
|
// label21
|
||||||
//
|
//
|
||||||
|
label21.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label21.AutoSize = true;
|
label21.AutoSize = true;
|
||||||
label21.Location = new System.Drawing.Point(239, 89);
|
label21.Location = new System.Drawing.Point(239, 89);
|
||||||
label21.Name = "label21";
|
label21.Name = "label21";
|
||||||
@@ -939,33 +948,37 @@
|
|||||||
//
|
//
|
||||||
// encoderQualityCb
|
// 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.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
encoderQualityCb.FormattingEnabled = true;
|
encoderQualityCb.FormattingEnabled = true;
|
||||||
encoderQualityCb.Location = new System.Drawing.Point(337, 86);
|
encoderQualityCb.Location = new System.Drawing.Point(337, 86);
|
||||||
encoderQualityCb.Name = "encoderQualityCb";
|
encoderQualityCb.Name = "encoderQualityCb";
|
||||||
encoderQualityCb.Size = new System.Drawing.Size(90, 23);
|
encoderQualityCb.Size = new System.Drawing.Size(107, 23);
|
||||||
encoderQualityCb.TabIndex = 2;
|
encoderQualityCb.TabIndex = 2;
|
||||||
//
|
//
|
||||||
// maxSampleRateCb
|
// 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.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
maxSampleRateCb.FormattingEnabled = true;
|
maxSampleRateCb.FormattingEnabled = true;
|
||||||
maxSampleRateCb.Location = new System.Drawing.Point(119, 86);
|
maxSampleRateCb.Location = new System.Drawing.Point(119, 86);
|
||||||
maxSampleRateCb.Name = "maxSampleRateCb";
|
maxSampleRateCb.Name = "maxSampleRateCb";
|
||||||
maxSampleRateCb.Size = new System.Drawing.Size(101, 23);
|
maxSampleRateCb.Size = new System.Drawing.Size(76, 23);
|
||||||
maxSampleRateCb.TabIndex = 2;
|
maxSampleRateCb.TabIndex = 2;
|
||||||
//
|
//
|
||||||
// lameDownsampleMonoCbox
|
// 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.Name = "lameDownsampleMonoCbox";
|
||||||
lameDownsampleMonoCbox.Size = new System.Drawing.Size(184, 34);
|
lameDownsampleMonoCbox.Size = new System.Drawing.Size(197, 34);
|
||||||
lameDownsampleMonoCbox.TabIndex = 1;
|
lameDownsampleMonoCbox.TabIndex = 1;
|
||||||
lameDownsampleMonoCbox.Text = "Downsample stereo to mono?\r\n(Recommended)\r\n";
|
lameDownsampleMonoCbox.Text = "Downsample stereo to mono?\r\n(Recommended)\r\n";
|
||||||
lameDownsampleMonoCbox.UseVisualStyleBackColor = true;
|
lameDownsampleMonoCbox.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// lameBitrateGb
|
// 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(LameMatchSourceBRCbox);
|
||||||
lameBitrateGb.Controls.Add(lameConstantBitrateCbox);
|
lameBitrateGb.Controls.Add(lameConstantBitrateCbox);
|
||||||
lameBitrateGb.Controls.Add(label7);
|
lameBitrateGb.Controls.Add(label7);
|
||||||
@@ -977,15 +990,16 @@
|
|||||||
lameBitrateGb.Controls.Add(lameBitrateTb);
|
lameBitrateGb.Controls.Add(lameBitrateTb);
|
||||||
lameBitrateGb.Location = new System.Drawing.Point(6, 116);
|
lameBitrateGb.Location = new System.Drawing.Point(6, 116);
|
||||||
lameBitrateGb.Name = "lameBitrateGb";
|
lameBitrateGb.Name = "lameBitrateGb";
|
||||||
lameBitrateGb.Size = new System.Drawing.Size(421, 113);
|
lameBitrateGb.Size = new System.Drawing.Size(438, 113);
|
||||||
lameBitrateGb.TabIndex = 0;
|
lameBitrateGb.TabIndex = 0;
|
||||||
lameBitrateGb.TabStop = false;
|
lameBitrateGb.TabStop = false;
|
||||||
lameBitrateGb.Text = "Bitrate";
|
lameBitrateGb.Text = "Bitrate";
|
||||||
//
|
//
|
||||||
// LameMatchSourceBRCbox
|
// LameMatchSourceBRCbox
|
||||||
//
|
//
|
||||||
|
LameMatchSourceBRCbox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||||
LameMatchSourceBRCbox.AutoSize = true;
|
LameMatchSourceBRCbox.AutoSize = true;
|
||||||
LameMatchSourceBRCbox.Location = new System.Drawing.Point(275, 76);
|
LameMatchSourceBRCbox.Location = new System.Drawing.Point(254, 76);
|
||||||
LameMatchSourceBRCbox.Name = "LameMatchSourceBRCbox";
|
LameMatchSourceBRCbox.Name = "LameMatchSourceBRCbox";
|
||||||
LameMatchSourceBRCbox.Size = new System.Drawing.Size(140, 19);
|
LameMatchSourceBRCbox.Size = new System.Drawing.Size(140, 19);
|
||||||
LameMatchSourceBRCbox.TabIndex = 3;
|
LameMatchSourceBRCbox.TabIndex = 3;
|
||||||
@@ -1005,6 +1019,7 @@
|
|||||||
//
|
//
|
||||||
// label7
|
// label7
|
||||||
//
|
//
|
||||||
|
label7.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label7.AutoSize = true;
|
label7.AutoSize = true;
|
||||||
label7.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
label7.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
||||||
label7.Location = new System.Drawing.Point(390, 52);
|
label7.Location = new System.Drawing.Point(390, 52);
|
||||||
@@ -1015,6 +1030,7 @@
|
|||||||
//
|
//
|
||||||
// label6
|
// label6
|
||||||
//
|
//
|
||||||
|
label6.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label6.AutoSize = true;
|
label6.AutoSize = true;
|
||||||
label6.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
label6.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
||||||
label6.Location = new System.Drawing.Point(309, 52);
|
label6.Location = new System.Drawing.Point(309, 52);
|
||||||
@@ -1025,6 +1041,7 @@
|
|||||||
//
|
//
|
||||||
// label5
|
// label5
|
||||||
//
|
//
|
||||||
|
label5.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label5.AutoSize = true;
|
label5.AutoSize = true;
|
||||||
label5.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
label5.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
||||||
label5.Location = new System.Drawing.Point(228, 52);
|
label5.Location = new System.Drawing.Point(228, 52);
|
||||||
@@ -1035,6 +1052,7 @@
|
|||||||
//
|
//
|
||||||
// label4
|
// label4
|
||||||
//
|
//
|
||||||
|
label4.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label4.AutoSize = true;
|
label4.AutoSize = true;
|
||||||
label4.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
label4.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
||||||
label4.Location = new System.Drawing.Point(147, 52);
|
label4.Location = new System.Drawing.Point(147, 52);
|
||||||
@@ -1045,6 +1063,7 @@
|
|||||||
//
|
//
|
||||||
// label11
|
// label11
|
||||||
//
|
//
|
||||||
|
label11.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label11.AutoSize = true;
|
label11.AutoSize = true;
|
||||||
label11.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
label11.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
||||||
label11.Location = new System.Drawing.Point(10, 52);
|
label11.Location = new System.Drawing.Point(10, 52);
|
||||||
@@ -1055,6 +1074,7 @@
|
|||||||
//
|
//
|
||||||
// label3
|
// label3
|
||||||
//
|
//
|
||||||
|
label3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label3.AutoSize = true;
|
label3.AutoSize = true;
|
||||||
label3.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
label3.BackColor = System.Drawing.SystemColors.ControlLightLight;
|
||||||
label3.Location = new System.Drawing.Point(71, 52);
|
label3.Location = new System.Drawing.Point(71, 52);
|
||||||
@@ -1071,7 +1091,7 @@
|
|||||||
lameBitrateTb.Maximum = 320;
|
lameBitrateTb.Maximum = 320;
|
||||||
lameBitrateTb.Minimum = 16;
|
lameBitrateTb.Minimum = 16;
|
||||||
lameBitrateTb.Name = "lameBitrateTb";
|
lameBitrateTb.Name = "lameBitrateTb";
|
||||||
lameBitrateTb.Size = new System.Drawing.Size(409, 45);
|
lameBitrateTb.Size = new System.Drawing.Size(408, 45);
|
||||||
lameBitrateTb.SmallChange = 8;
|
lameBitrateTb.SmallChange = 8;
|
||||||
lameBitrateTb.TabIndex = 0;
|
lameBitrateTb.TabIndex = 0;
|
||||||
lameBitrateTb.TickFrequency = 16;
|
lameBitrateTb.TickFrequency = 16;
|
||||||
@@ -1090,6 +1110,7 @@
|
|||||||
//
|
//
|
||||||
// lameQualityGb
|
// 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(label19);
|
||||||
lameQualityGb.Controls.Add(label18);
|
lameQualityGb.Controls.Add(label18);
|
||||||
lameQualityGb.Controls.Add(label17);
|
lameQualityGb.Controls.Add(label17);
|
||||||
@@ -1105,13 +1126,14 @@
|
|||||||
lameQualityGb.Controls.Add(lameVBRQualityTb);
|
lameQualityGb.Controls.Add(lameVBRQualityTb);
|
||||||
lameQualityGb.Location = new System.Drawing.Point(6, 235);
|
lameQualityGb.Location = new System.Drawing.Point(6, 235);
|
||||||
lameQualityGb.Name = "lameQualityGb";
|
lameQualityGb.Name = "lameQualityGb";
|
||||||
lameQualityGb.Size = new System.Drawing.Size(421, 109);
|
lameQualityGb.Size = new System.Drawing.Size(438, 109);
|
||||||
lameQualityGb.TabIndex = 0;
|
lameQualityGb.TabIndex = 0;
|
||||||
lameQualityGb.TabStop = false;
|
lameQualityGb.TabStop = false;
|
||||||
lameQualityGb.Text = "Quality";
|
lameQualityGb.Text = "Quality";
|
||||||
//
|
//
|
||||||
// label19
|
// label19
|
||||||
//
|
//
|
||||||
|
label19.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label19.AutoSize = true;
|
label19.AutoSize = true;
|
||||||
label19.Location = new System.Drawing.Point(349, 52);
|
label19.Location = new System.Drawing.Point(349, 52);
|
||||||
label19.Name = "label19";
|
label19.Name = "label19";
|
||||||
@@ -1121,6 +1143,7 @@
|
|||||||
//
|
//
|
||||||
// label18
|
// label18
|
||||||
//
|
//
|
||||||
|
label18.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label18.AutoSize = true;
|
label18.AutoSize = true;
|
||||||
label18.Location = new System.Drawing.Point(307, 52);
|
label18.Location = new System.Drawing.Point(307, 52);
|
||||||
label18.Name = "label18";
|
label18.Name = "label18";
|
||||||
@@ -1130,6 +1153,7 @@
|
|||||||
//
|
//
|
||||||
// label17
|
// label17
|
||||||
//
|
//
|
||||||
|
label17.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label17.AutoSize = true;
|
label17.AutoSize = true;
|
||||||
label17.Location = new System.Drawing.Point(265, 52);
|
label17.Location = new System.Drawing.Point(265, 52);
|
||||||
label17.Name = "label17";
|
label17.Name = "label17";
|
||||||
@@ -1139,6 +1163,7 @@
|
|||||||
//
|
//
|
||||||
// label16
|
// label16
|
||||||
//
|
//
|
||||||
|
label16.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label16.AutoSize = true;
|
label16.AutoSize = true;
|
||||||
label16.Location = new System.Drawing.Point(223, 52);
|
label16.Location = new System.Drawing.Point(223, 52);
|
||||||
label16.Name = "label16";
|
label16.Name = "label16";
|
||||||
@@ -1148,6 +1173,7 @@
|
|||||||
//
|
//
|
||||||
// label12
|
// label12
|
||||||
//
|
//
|
||||||
|
label12.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label12.AutoSize = true;
|
label12.AutoSize = true;
|
||||||
label12.Location = new System.Drawing.Point(182, 52);
|
label12.Location = new System.Drawing.Point(182, 52);
|
||||||
label12.Name = "label12";
|
label12.Name = "label12";
|
||||||
@@ -1157,6 +1183,7 @@
|
|||||||
//
|
//
|
||||||
// label15
|
// label15
|
||||||
//
|
//
|
||||||
|
label15.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label15.AutoSize = true;
|
label15.AutoSize = true;
|
||||||
label15.Location = new System.Drawing.Point(140, 52);
|
label15.Location = new System.Drawing.Point(140, 52);
|
||||||
label15.Name = "label15";
|
label15.Name = "label15";
|
||||||
@@ -1166,6 +1193,7 @@
|
|||||||
//
|
//
|
||||||
// label9
|
// label9
|
||||||
//
|
//
|
||||||
|
label9.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label9.AutoSize = true;
|
label9.AutoSize = true;
|
||||||
label9.Location = new System.Drawing.Point(97, 52);
|
label9.Location = new System.Drawing.Point(97, 52);
|
||||||
label9.Name = "label9";
|
label9.Name = "label9";
|
||||||
@@ -1175,6 +1203,7 @@
|
|||||||
//
|
//
|
||||||
// label8
|
// label8
|
||||||
//
|
//
|
||||||
|
label8.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label8.AutoSize = true;
|
label8.AutoSize = true;
|
||||||
label8.Location = new System.Drawing.Point(391, 52);
|
label8.Location = new System.Drawing.Point(391, 52);
|
||||||
label8.Name = "label8";
|
label8.Name = "label8";
|
||||||
@@ -1202,6 +1231,7 @@
|
|||||||
//
|
//
|
||||||
// label14
|
// label14
|
||||||
//
|
//
|
||||||
|
label14.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label14.AutoSize = true;
|
label14.AutoSize = true;
|
||||||
label14.Location = new System.Drawing.Point(56, 52);
|
label14.Location = new System.Drawing.Point(56, 52);
|
||||||
label14.Name = "label14";
|
label14.Name = "label14";
|
||||||
@@ -1211,6 +1241,7 @@
|
|||||||
//
|
//
|
||||||
// label2
|
// label2
|
||||||
//
|
//
|
||||||
|
label2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||||
label2.AutoSize = true;
|
label2.AutoSize = true;
|
||||||
label2.Location = new System.Drawing.Point(14, 52);
|
label2.Location = new System.Drawing.Point(14, 52);
|
||||||
label2.Name = "label2";
|
label2.Name = "label2";
|
||||||
@@ -1225,25 +1256,27 @@
|
|||||||
lameVBRQualityTb.Location = new System.Drawing.Point(10, 22);
|
lameVBRQualityTb.Location = new System.Drawing.Point(10, 22);
|
||||||
lameVBRQualityTb.Maximum = 9;
|
lameVBRQualityTb.Maximum = 9;
|
||||||
lameVBRQualityTb.Name = "lameVBRQualityTb";
|
lameVBRQualityTb.Name = "lameVBRQualityTb";
|
||||||
lameVBRQualityTb.Size = new System.Drawing.Size(405, 45);
|
lameVBRQualityTb.Size = new System.Drawing.Size(404, 45);
|
||||||
lameVBRQualityTb.TabIndex = 0;
|
lameVBRQualityTb.TabIndex = 0;
|
||||||
lameVBRQualityTb.Value = 9;
|
lameVBRQualityTb.Value = 9;
|
||||||
//
|
//
|
||||||
// groupBox2
|
// 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(lameTargetQualityRb);
|
||||||
groupBox2.Controls.Add(lameTargetBitrateRb);
|
groupBox2.Controls.Add(lameTargetBitrateRb);
|
||||||
groupBox2.Location = new System.Drawing.Point(6, 22);
|
groupBox2.Location = new System.Drawing.Point(6, 22);
|
||||||
groupBox2.Name = "groupBox2";
|
groupBox2.Name = "groupBox2";
|
||||||
groupBox2.Size = new System.Drawing.Size(214, 58);
|
groupBox2.Size = new System.Drawing.Size(189, 58);
|
||||||
groupBox2.TabIndex = 0;
|
groupBox2.TabIndex = 0;
|
||||||
groupBox2.TabStop = false;
|
groupBox2.TabStop = false;
|
||||||
groupBox2.Text = "Target";
|
groupBox2.Text = "Target";
|
||||||
//
|
//
|
||||||
// lameTargetQualityRb
|
// lameTargetQualityRb
|
||||||
//
|
//
|
||||||
|
lameTargetQualityRb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||||
lameTargetQualityRb.AutoSize = true;
|
lameTargetQualityRb.AutoSize = true;
|
||||||
lameTargetQualityRb.Location = new System.Drawing.Point(139, 22);
|
lameTargetQualityRb.Location = new System.Drawing.Point(118, 22);
|
||||||
lameTargetQualityRb.Name = "lameTargetQualityRb";
|
lameTargetQualityRb.Name = "lameTargetQualityRb";
|
||||||
lameTargetQualityRb.Size = new System.Drawing.Size(63, 19);
|
lameTargetQualityRb.Size = new System.Drawing.Size(63, 19);
|
||||||
lameTargetQualityRb.TabIndex = 0;
|
lameTargetQualityRb.TabIndex = 0;
|
||||||
@@ -1321,7 +1354,6 @@
|
|||||||
Controls.Add(tabControl);
|
Controls.Add(tabControl);
|
||||||
Controls.Add(cancelBtn);
|
Controls.Add(cancelBtn);
|
||||||
Controls.Add(saveBtn);
|
Controls.Add(saveBtn);
|
||||||
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
|
||||||
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||||
MaximizeBox = false;
|
MaximizeBox = false;
|
||||||
MinimizeBox = false;
|
MinimizeBox = false;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, 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="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">
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -16,7 +16,27 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell
|
internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell
|
||||||
{
|
{
|
||||||
private static readonly Brush DISABLED_GRAY = new SolidBrush(Color.FromArgb(0x60, Color.LightGray));
|
#region Accessibility
|
||||||
|
private string accessibilityName => "Liberate Image Button";
|
||||||
|
private string accessibilityDescription = "undefined";
|
||||||
|
protected override AccessibleObject CreateAccessibilityInstance() => new MyAccessibilityObject(accessibilityName, accessibilityDescription);
|
||||||
|
protected class MyAccessibilityObject : DataGridViewCellAccessibleObject
|
||||||
|
{
|
||||||
|
public override string Name => _name;
|
||||||
|
public override string Description => _description;
|
||||||
|
|
||||||
|
private string _name { get; }
|
||||||
|
private string _description { get; }
|
||||||
|
|
||||||
|
public MyAccessibilityObject(string name, string description) : base()
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
_description = description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static readonly Brush DISABLED_GRAY = new SolidBrush(Color.FromArgb(0x60, Color.LightGray));
|
||||||
private static readonly Color HiddenForeColor = 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)
|
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 +51,8 @@ namespace LibationWinForms.GridView
|
|||||||
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
|
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
|
||||||
|
|
||||||
DrawButtonImage(graphics, (Image)status.ButtonImage, cellBounds);
|
DrawButtonImage(graphics, (Image)status.ButtonImage, cellBounds);
|
||||||
ToolTipText = status.ToolTip;
|
accessibilityDescription = status.ToolTip;
|
||||||
|
ToolTipText = status.ToolTip;
|
||||||
|
|
||||||
if (status.IsUnavailable || status.Opacity < 1)
|
if (status.IsUnavailable || status.Opacity < 1)
|
||||||
graphics.FillRectangle(DISABLED_GRAY, cellBounds);
|
graphics.FillRectangle(DISABLED_GRAY, cellBounds);
|
||||||
|
|||||||
@@ -102,19 +102,19 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
private void productsGrid_CellContextMenuStripNeeded(IGridEntry entry, ContextMenuStrip ctxMenu)
|
private void productsGrid_CellContextMenuStripNeeded(IGridEntry entry, ContextMenuStrip ctxMenu)
|
||||||
{
|
{
|
||||||
|
var ctx = new GridContextMenu(entry, '&');
|
||||||
#region Liberate all Episodes
|
#region Liberate all Episodes
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
if (entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var liberateEpisodesMenuItem = new ToolStripMenuItem()
|
var liberateEpisodesMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "&Liberate All Episodes",
|
Text = ctx.LiberateEpisodesText,
|
||||||
Enabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
Enabled = ctx.LiberateEpisodesEnabled
|
||||||
};
|
};
|
||||||
|
|
||||||
ctxMenu.Items.Add(liberateEpisodesMenuItem);
|
|
||||||
|
|
||||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, (ISeriesEntry)entry);
|
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, (ISeriesEntry)entry);
|
||||||
|
ctxMenu.Items.Add(liberateEpisodesMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -122,61 +122,44 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
var setDownloadMenuItem = new ToolStripMenuItem()
|
var setDownloadMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "Set Download status to '&Downloaded'",
|
Text = ctx.SetDownloadedText,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
Enabled = ctx.SetDownloadedEnabled
|
||||||
};
|
};
|
||||||
|
setDownloadMenuItem.Click += (_, _) => ctx.SetDownloaded();
|
||||||
ctxMenu.Items.Add(setDownloadMenuItem);
|
ctxMenu.Items.Add(setDownloadMenuItem);
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setDownloadMenuItem.Click += (_, _) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
else
|
|
||||||
setDownloadMenuItem.Click += (_, _) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Set Download status to Not Downloaded
|
#region Set Download status to Not Downloaded
|
||||||
|
|
||||||
var setNotDownloadMenuItem = new ToolStripMenuItem()
|
var setNotDownloadMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "Set Download status to '&Not Downloaded'",
|
Text = ctx.SetNotDownloadedText,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
Enabled = ctx.SetNotDownloadedEnabled
|
||||||
};
|
};
|
||||||
|
setNotDownloadMenuItem.Click += (_, _) => ctx.SetNotDownloaded();
|
||||||
ctxMenu.Items.Add(setNotDownloadMenuItem);
|
ctxMenu.Items.Add(setNotDownloadMenuItem);
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setNotDownloadMenuItem.Click += (_, _) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
else
|
|
||||||
setNotDownloadMenuItem.Click += (_, _) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Remove from library
|
#region Remove from library
|
||||||
|
|
||||||
var removeMenuItem = new ToolStripMenuItem() { Text = "&Remove from library" };
|
var removeMenuItem = new ToolStripMenuItem() { Text = ctx.RemoveText };
|
||||||
|
removeMenuItem.Click += async (_, _) => await ctx.RemoveAsync();
|
||||||
ctxMenu.Items.Add(removeMenuItem);
|
ctxMenu.Items.Add(removeMenuItem);
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
removeMenuItem.Click += async (_, _) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
|
||||||
else
|
|
||||||
removeMenuItem.Click += async (_, _) => await Task.Run(entry.LibraryBook.RemoveBook);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
#region Locate file
|
#region Locate file
|
||||||
var locateFileMenuItem = new ToolStripMenuItem() { Text = "&Locate file..." };
|
var locateFileMenuItem = new ToolStripMenuItem() { Text = ctx.LocateFileText };
|
||||||
|
|
||||||
ctxMenu.Items.Add(locateFileMenuItem);
|
ctxMenu.Items.Add(locateFileMenuItem);
|
||||||
|
|
||||||
locateFileMenuItem.Click += (_, _) =>
|
locateFileMenuItem.Click += (_, _) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var openFileDialog = new OpenFileDialog
|
var openFileDialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
Title = ctx.LocateFileDialogTitle,
|
||||||
Filter = "All files (*.*)|*.*",
|
Filter = "All files (*.*)|*.*",
|
||||||
FilterIndex = 1
|
FilterIndex = 1
|
||||||
};
|
};
|
||||||
@@ -185,8 +168,7 @@ namespace LibationWinForms.GridView
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var msg = "Error saving book's location";
|
MessageBoxLib.ShowAdminAlert(this, ctx.LocateFileErrorMessage, ctx.LocateFileErrorMessage, ex);
|
||||||
MessageBoxLib.ShowAdminAlert(this, msg, msg, ex);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,13 +177,11 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
var convertToMp3MenuItem = new ToolStripMenuItem
|
var convertToMp3MenuItem = new ToolStripMenuItem
|
||||||
{
|
{
|
||||||
Text = "&Convert to Mp3",
|
Text = ctx.ConvertToMp3Text,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
Enabled = ctx.ConvertToMp3Enabled
|
||||||
};
|
};
|
||||||
|
|
||||||
ctxMenu.Items.Add(convertToMp3MenuItem);
|
|
||||||
|
|
||||||
convertToMp3MenuItem.Click += (_, e) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
convertToMp3MenuItem.Click += (_, e) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
||||||
|
ctxMenu.Items.Add(convertToMp3MenuItem);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -211,10 +191,9 @@ namespace LibationWinForms.GridView
|
|||||||
{
|
{
|
||||||
var reDownloadMenuItem = new ToolStripMenuItem()
|
var reDownloadMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "Re-download this audiobook",
|
Text = ctx.ReDownloadText,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
Enabled = ctx.ReDownloadEnabled
|
||||||
};
|
};
|
||||||
|
|
||||||
ctxMenu.Items.Add(reDownloadMenuItem);
|
ctxMenu.Items.Add(reDownloadMenuItem);
|
||||||
reDownloadMenuItem.Click += (s, _) =>
|
reDownloadMenuItem.Click += (s, _) =>
|
||||||
{
|
{
|
||||||
@@ -223,6 +202,35 @@ namespace LibationWinForms.GridView
|
|||||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
#region Edit Templates
|
||||||
|
void editTemplate<T>(LibraryBook libraryBook, string existingTemplate, Action<string> setNewTemplate)
|
||||||
|
where T : Templates, LibationFileManager.ITemplate, new()
|
||||||
|
{
|
||||||
|
var template = ctx.CreateTemplateEditor<T>(libraryBook, existingTemplate);
|
||||||
|
var form = new EditTemplateDialog(template);
|
||||||
|
if (form.ShowDialog(this) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
setNewTemplate(template.EditingTemplate.TemplateText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.Liberate.IsSeries)
|
||||||
|
{
|
||||||
|
var folderTemplateMenuItem = new ToolStripMenuItem { Text = ctx.FolderTemplateText };
|
||||||
|
var fileTemplateMenuItem = new ToolStripMenuItem { Text = ctx.FileTemplateText };
|
||||||
|
var multiFileTemplateMenuItem = new ToolStripMenuItem { Text = ctx.MultipartTemplateText };
|
||||||
|
folderTemplateMenuItem.Click += (s, _) => editTemplate<Templates.FolderTemplate>(entry.LibraryBook, Configuration.Instance.FolderTemplate, t => Configuration.Instance.FolderTemplate = t);
|
||||||
|
fileTemplateMenuItem.Click += (s, _) => editTemplate<Templates.FileTemplate>(entry.LibraryBook, Configuration.Instance.FileTemplate, t => Configuration.Instance.FileTemplate = t);
|
||||||
|
multiFileTemplateMenuItem.Click += (s, _) => editTemplate<Templates.ChapterFileTemplate>(entry.LibraryBook, Configuration.Instance.ChapterFileTemplate, t => Configuration.Instance.ChapterFileTemplate = t);
|
||||||
|
|
||||||
|
var editTemplatesMenuItem = new ToolStripMenuItem { Text = ctx.EditTemplatesText };
|
||||||
|
editTemplatesMenuItem.DropDownItems.AddRange(new[] { folderTemplateMenuItem, fileTemplateMenuItem, multiFileTemplateMenuItem });
|
||||||
|
|
||||||
|
ctxMenu.Items.Add(new ToolStripSeparator());
|
||||||
|
ctxMenu.Items.Add(editTemplatesMenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
ctxMenu.Items.Add(new ToolStripSeparator());
|
ctxMenu.Items.Add(new ToolStripSeparator());
|
||||||
@@ -231,11 +239,9 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var bookRecordMenuItem = new ToolStripMenuItem { Text = "View &Bookmarks/Clips" };
|
var bookRecordMenuItem = new ToolStripMenuItem { Text = ctx.ViewBookmarksText };
|
||||||
|
|
||||||
ctxMenu.Items.Add(bookRecordMenuItem);
|
|
||||||
|
|
||||||
bookRecordMenuItem.Click += (_, _) => new BookRecordsDialog(entry.LibraryBook).ShowDialog(this);
|
bookRecordMenuItem.Click += (_, _) => new BookRecordsDialog(entry.LibraryBook).ShowDialog(this);
|
||||||
|
ctxMenu.Items.Add(bookRecordMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -243,13 +249,9 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
if (entry.Book.SeriesLink.Any())
|
if (entry.Book.SeriesLink.Any())
|
||||||
{
|
{
|
||||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
var viewSeriesMenuItem = new ToolStripMenuItem { Text = ctx.ViewSeriesText };
|
||||||
|
|
||||||
var viewSeriesMenuItem = new ToolStripMenuItem { Text = header };
|
|
||||||
|
|
||||||
ctxMenu.Items.Add(viewSeriesMenuItem);
|
|
||||||
|
|
||||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
||||||
|
ctxMenu.Items.Add(viewSeriesMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ApplicationIcon>libation.ico</ApplicationIcon>
|
<ApplicationIcon>libation.ico</ApplicationIcon>
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
<!-- Version is now in AppScaffolding.csproj -->
|
<!-- Version is now in AppScaffolding.csproj -->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<RuntimeHostConfigurationOption Include="System.Net.DisableIPv6" Value="true" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -37,7 +41,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="7.3.0.1" />
|
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="8.0.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ namespace LibationWinForms.ProcessQueue
|
|||||||
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var quality
|
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.PictureLarge, PictureSize.Native)
|
||||||
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\bin\Publish\classic</PublishDir>
|
<PublishDir>..\bin\Publish\classic</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\..\bin\Publish\Linux-chardonnay</PublishDir>
|
<PublishDir>..\..\bin\Publish\Linux-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -1,28 +1,39 @@
|
|||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256.0px" height="256.0px" viewBox="0 0 512 512" enable-background="new 0 0 512 512">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 524 524" enable-background="new 0 0 524 524">
|
||||||
<path id="glass" d=
|
<defs>
|
||||||
"M139,2
|
<g id="glass">
|
||||||
A 192,200 0 0 0 103,84
|
<path fill-rule="evenodd" d=
|
||||||
A 222,334 41 0 0 241,320
|
"M262,8
|
||||||
V478
|
h-117
|
||||||
H160
|
a 192,200 0 0 0 -36,82
|
||||||
A 16,16 0 0 0 160,510
|
a 222,334 41 0 0 138,236
|
||||||
H352
|
v158
|
||||||
A16 16 0 0 0 352,478
|
h-81
|
||||||
H271
|
a 16,16 0 0 0 0,32
|
||||||
V320
|
h192
|
||||||
A 222,334 -41 0 0 409,84
|
a 16 16 0 0 0 0,-32
|
||||||
A 192,200 0 0 0 373,2
|
h-81
|
||||||
M355,32
|
v-158
|
||||||
A 192,200 0 0 1 381,127
|
a 222,334 -41 0 0 138,-236
|
||||||
A 187.5,334 -35 0 1 256,286
|
a 192,200 0 0 0 -36,-82
|
||||||
A 187.5,334 35 0 1 131,127
|
h-117
|
||||||
A 192,200 0 0 1 157,32
|
m-99,30
|
||||||
H355
|
a 192,200 0 0 0 -26,95
|
||||||
z" />
|
a 187.5,334 35 0 0 125,159
|
||||||
|
a 187.5,334 -35 0 0 125,-159
|
||||||
<path id="wine-level" d=
|
a 192,200 0 0 0 -26,-95
|
||||||
"M146,128
|
h-198
|
||||||
A 168,300 35 0 0 256,270
|
z"/>
|
||||||
A 168,300 -35 0 0 366,128
|
</g>
|
||||||
z"/>
|
<g id="wine-level">
|
||||||
|
<path d=
|
||||||
|
"M158,136
|
||||||
|
a 168,305 35 0 0 104,136
|
||||||
|
a 168,305 -35 0 0 104,-136
|
||||||
|
z"/>
|
||||||
|
</g>
|
||||||
|
</defs>
|
||||||
|
<use href="#glass" stroke="#ffffffa0" stroke-width="16" fill="Transparent" />
|
||||||
|
<use href="#wine-level" stroke="#ffffffa0" stroke-width="16" fill="Transparent" />
|
||||||
|
<use href="#glass" fill="Black" />
|
||||||
|
<use href="#wine-level" fill="Black" />
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 968 B |
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<!--<TargetFramework>net7.0-macos</TargetFramework>-->
|
<!--<TargetFramework>net8.0-macos</TargetFramework>-->
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\..\bin\Publish\MacOS-chardonnay</PublishDir>
|
<PublishDir>..\..\bin\Publish\MacOS-chardonnay</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<PublishDir>..\..\bin\Publish\classic</PublishDir>
|
<PublishDir>..\..\bin\Publish\classic</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1901.177" />
|
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dinah.Core" Version="7.3.0.1" />
|
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ using FluentAssertions;
|
|||||||
using FluentAssertions.Common;
|
using FluentAssertions.Common;
|
||||||
using Microsoft.VisualStudio.TestPlatform.Common.Filtering;
|
using Microsoft.VisualStudio.TestPlatform.Common.Filtering;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
|
||||||
using Moq.Protected;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="Moq" Version="4.18.4" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="Moq" Version="4.18.4" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ using LibationSearchEngine;
|
|||||||
using Lucene.Net.Analysis.Standard;
|
using Lucene.Net.Analysis.Standard;
|
||||||
using Microsoft.VisualStudio.TestPlatform.Common.Filtering;
|
using Microsoft.VisualStudio.TestPlatform.Common.Filtering;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
|
||||||
using Moq.Protected;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user