diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml
index 3f3a8fd0..86468524 100644
--- a/.github/workflows/build-linux.yml
+++ b/.github/workflows/build-linux.yml
@@ -15,6 +15,21 @@ on:
description: 'Skip running unit tests'
required: false
default: true
+ runs_on:
+ type: string
+ description: 'The GitHub hosted runner to use'
+ required: true
+ OS:
+ type: string
+ description: >
+ The operating system targeted by the build.
+
+ There must be a corresponding Bundle_$OS.sh script file in ./Scripts
+ required: true
+ architecture:
+ type: string
+ description: 'CPU architecture targeted by the build.'
+ required: true
env:
DOTNET_CONFIGURATION: 'Release'
@@ -23,11 +38,8 @@ env:
jobs:
build:
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [ubuntu-latest, macos-latest]
- arch: [x64, arm64]
+ name: '${{ inputs.OS }}-${{ inputs.architecture }}'
+ runs-on: ${{ inputs.runs_on }}
steps:
- uses: actions/checkout@v3
- name: Setup .NET
@@ -48,6 +60,7 @@ jobs:
version="$(grep -Eio -m 1 '.*' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')"
fi
echo "version=${version}" >> "${GITHUB_OUTPUT}"
+
- name: Unit test
if: ${{ inputs.run_unit_tests }}
working-directory: ./Source
@@ -56,52 +69,64 @@ jobs:
- name: Publish
id: publish
working-directory: ./Source
- run: |
- os=${{ matrix.os }}
- target_os="$(echo ${os/-latest/} | sed 's/ubuntu/linux/')"
- display_os="$(echo ${target_os/macos/macOS} | sed 's/linux/Linux/')"
+ run: |
+ if [[ "${{ inputs.OS }}" == "MacOS" ]]
+ then
+ display_os="macOS"
+ RUNTIME_ID="osx-${{ inputs.architecture }}"
+ else
+ display_os="Linux"
+ RUNTIME_ID="linux-${{ inputs.architecture }}"
+ fi
+
+ OUTPUT="bin/Publish/${display_os}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }}"
+
echo "display_os=${display_os}" >> $GITHUB_OUTPUT
- RUNTIME_IDENTIFIER="$(echo ${target_os/macos/osx})-${{ matrix.arch }}"
- echo "$RUNTIME_IDENTIFIER"
+ echo "Runtime Identifier: $RUNTIME_ID"
+ echo "Output Directory: $OUTPUT"
+
dotnet publish \
LibationAvalonia/LibationAvalonia.csproj \
- --runtime "$RUNTIME_IDENTIFIER" \
+ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ --output $OUTPUT \
-p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \
LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \
- --runtime "$RUNTIME_IDENTIFIER" \
+ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ --output $OUTPUT \
-p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \
LibationCli/LibationCli.csproj \
- --runtime "$RUNTIME_IDENTIFIER" \
+ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ --output $OUTPUT \
-p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \
HangoverAvalonia/HangoverAvalonia.csproj \
- --runtime "$RUNTIME_IDENTIFIER" \
+ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ --output $OUTPUT \
-p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
+
- name: Build bundle
id: bundle
- working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }}
+ working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }}
run: |
BUNDLE_DIR=$(pwd)
echo "Bundle dir: ${BUNDLE_DIR}"
cd ..
- SCRIPT=../../../Scripts/Bundle_${{ steps.publish.outputs.display_os }}.sh
+ SCRIPT=../../../Scripts/Bundle_${{ inputs.OS }}.sh
chmod +rx ${SCRIPT}
- ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ matrix.arch }}"
+ ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ inputs.architecture }}"
artifact=$(ls ./bundle)
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
+
- name: Publish bundle
uses: actions/upload-artifact@v3
with:
name: ${{ steps.bundle.outputs.artifact }}
path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}
- if-no-files-found: error
\ No newline at end of file
+ if-no-files-found: error
+ retention-days: 7
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index 605016a1..a14c5a38 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -22,6 +22,7 @@ env:
jobs:
build:
+ name: '${{ matrix.os }}-${{ matrix.release_name }}'
runs-on: windows-latest
strategy:
matrix:
@@ -110,4 +111,4 @@ jobs:
name: ${{ steps.zip.outputs.artifact }}.zip
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
if-no-files-found: error
-
+ retention-days: 7
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b6cf9787..ce1186ac 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -17,14 +17,34 @@ on:
default: true
jobs:
+
windows:
uses: ./.github/workflows/build-windows.yml
with:
version_override: ${{ inputs.version_override }}
run_unit_tests: ${{ inputs.run_unit_tests }}
-
+
linux:
+ strategy:
+ matrix:
+ OS: [Redhat, Debian]
+ architecture: [x64, arm64]
uses: ./.github/workflows/build-linux.yml
with:
version_override: ${{ inputs.version_override }}
+ runs_on: ubuntu-latest
+ OS: ${{ matrix.OS }}
+ architecture: ${{ matrix.architecture }}
+ run_unit_tests: ${{ inputs.run_unit_tests }}
+
+ macos:
+ strategy:
+ matrix:
+ architecture: [x64, arm64]
+ uses: ./.github/workflows/build-linux.yml
+ with:
+ version_override: ${{ inputs.version_override }}
+ runs_on: macos-latest
+ OS: MacOS
+ architecture: ${{ matrix.architecture }}
run_unit_tests: ${{ inputs.run_unit_tests }}
diff --git a/.releaseindex.json b/.releaseindex.json
index 5e44f230..9d9dea23 100644
--- a/.releaseindex.json
+++ b/.releaseindex.json
@@ -1,8 +1,10 @@
{
- "WindowsClassic": "Classic-Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip",
- "WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip",
- "LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.deb",
- "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-x64\\.tgz",
- "LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.deb",
- "MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-arm64\\.tgz"
+ "WindowsClassic": "Classic-Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip",
+ "WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip",
+ "LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.deb",
+ "LinuxAvalonia_RPM": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.rpm",
+ "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-x64\\.tgz",
+ "LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.deb",
+ "LinuxAvalonia_Arm64_RPM": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.rpm",
+ "MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-arm64\\.tgz"
}
diff --git a/Scripts/Bundle_Linux.sh b/Scripts/Bundle_Debian.sh
similarity index 100%
rename from Scripts/Bundle_Linux.sh
rename to Scripts/Bundle_Debian.sh
diff --git a/Scripts/Bundle_Redhat.sh b/Scripts/Bundle_Redhat.sh
new file mode 100644
index 00000000..77bb4769
--- /dev/null
+++ b/Scripts/Bundle_Redhat.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+
+BIN_DIR=$1; shift
+VERSION=$1; shift
+ARCH=$1; shift
+
+if [ -z "$BIN_DIR" ]
+then
+ echo "This script must be called with a the Libation Linux bins directory as an argument."
+ exit
+fi
+
+if [ ! -d "$BIN_DIR" ]
+then
+ echo "The directory \"$BIN_DIR\" does not exist."
+ exit
+fi
+
+if [ -z "$VERSION" ]
+then
+ echo "This script must be called with the Libation version number as an argument."
+ exit
+fi
+
+if [ -z "$ARCH" ]
+then
+ echo "This script must be called with the Libation cpu architecture as an argument."
+ exit
+fi
+
+contains() { case "$1" in *"$2"*) true ;; *) false ;; esac }
+
+if ! contains "$BIN_DIR" "$ARCH"
+then
+ echo "This script must be called with a Libation binaries for ${ARCH}."
+ exit
+fi
+
+BASEDIR=$(pwd)
+
+delfiles=('libmp3lame.arm64.dylib' 'libmp3lame.x64.dylib' 'libmp3lame.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.arm64.dylib' 'ffmpegaac.x64.dylib' 'ffmpegaac.x64.dll' 'ffmpegaac.x86.dll' 'LinuxConfigApp' 'LinuxConfigApp.deps.json' 'LinuxConfigApp.runtimeconfig.json')
+if [[ "$ARCH" == "x64" ]]
+then
+ delfiles+=('libmp3lame.arm64.so' 'ffmpegaac.arm64.so')
+ ARCH_RPM="x86_64"
+ ARCH="amd64"
+else
+ delfiles+=('libmp3lame.x64.so' 'ffmpegaac.x64.so')
+ ARCH_RPM="aarch64"
+fi
+
+notinstalled=('libcoreclrtraceptprovider.so' 'libation_glass.svg' 'Libation.desktop')
+
+mkdir -p ~/rpmbuild/SPECS
+mkdir ~/rpmbuild/BUILD
+mkdir ~/rpmbuild/RPMS
+
+echo "Name: libation
+Version: ${VERSION}
+Release: 1
+Summary: Liberate your Audible Library
+
+License: GPLv3+
+URL: https://github.com/rmcrackan/Libation
+Source0: https://github.com/rmcrackan/Libation
+
+Requires: bash
+
+
+%define __os_install_post %{nil}
+
+%description
+Liberate your Audible Library
+
+%install
+mkdir -p %{buildroot}%{_libdir}/%{name}
+mkdir -p %{buildroot}%{_datadir}/icons/hicolor/scalable/apps
+mkdir -p %{buildroot}%{_datadir}/applications
+
+if test -f 'libcoreclrtraceptprovider.so'; then
+ rm 'libcoreclrtraceptprovider.so'
+fi
+
+touch appsettings.json
+chmod 666 appsettings.json
+
+install -m 666 libation_glass.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/libation.svg
+install -m 666 Libation.desktop %{buildroot}%{_datadir}/applications/Libation.desktop
+
+rm libation_glass.svg
+rm Libation.desktop
+
+install * %{buildroot}%{_libdir}/%{name}/
+
+%post
+
+ln -s %{_libdir}/%{name}/Libation %{_bindir}/libation
+ln -s %{_libdir}/%{name}/Hangover %{_bindir}/hangover
+ln -s %{_libdir}/%{name}/LibationCli %{_bindir}/libationcli
+
+gtk-update-icon-cache -f %{_datadir}/icons/hicolor/
+
+%postun
+
+rm %{_bindir}/libation
+rm %{_bindir}/hangover
+rm %{_bindir}/libationcli
+
+if ! grep -q 'fs.inotify.max_user_instances=524288' /etc/sysctl.conf; then
+ echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p
+fi
+
+%files
+%{_datadir}/icons/hicolor/scalable/apps/libation.svg
+%{_datadir}/applications/Libation.desktop
+%{_libdir}/%{name}/appsettings.json" >> ~/rpmbuild/SPECS/libation.spec
+
+
+cd "$BIN_DIR"
+
+for f in *; do
+ if [[ " ${delfiles[*]} " =~ " ${f} " ]]; then
+ echo "Deleting $f"
+ elif [[ ! " ${notinstalled[*]} " =~ " ${f} " ]]; then
+ echo "%{_libdir}/%{name}/${f}" >> ~/rpmbuild/SPECS/libation.spec
+ cp $f ~/rpmbuild/BUILD/
+ else
+ cp $f ~/rpmbuild/BUILD/
+ fi
+done
+
+cd ~/rpmbuild/SPECS/
+rpmbuild -bb --target $ARCH_RPM libation.spec
+
+cd $BASEDIR
+RPM_FILE=$(ls ~/rpmbuild/RPMS/${ARCH_RPM})
+
+mkdir bundle
+
+mv ~/rpmbuild/RPMS/${ARCH_RPM}/$RPM_FILE "./bundle/Libation.${VERSION}-linux-chardonnay-${ARCH}.rpm"
diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs
index efaaf63b..e474191f 100644
--- a/Source/AppScaffolding/LibationScaffolding.cs
+++ b/Source/AppScaffolding/LibationScaffolding.cs
@@ -330,7 +330,18 @@ namespace AppScaffolding
//Download the release index
var bts = await gitHubClient.Repository.Content.GetRawContent(ownerAccount, repoName, ".releaseindex.json");
var releaseIndex = JObject.Parse(System.Text.Encoding.ASCII.GetString(bts));
- var regexPattern = releaseIndex.Value(ReleaseIdentifier.ToString());
+
+ string regexPattern;
+
+ try
+ {
+ regexPattern = releaseIndex.Value(InteropFactory.Create().ReleaseIdString);
+ }
+ catch
+ {
+ regexPattern = releaseIndex.Value(ReleaseIdentifier.ToString());
+ }
+
var regex = new System.Text.RegularExpressions.Regex(regexPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
//https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#get-the-latest-release
diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs
index c9c202ae..be96e3f0 100644
--- a/Source/AudibleUtilities/ApiExtended.cs
+++ b/Source/AudibleUtilities/ApiExtended.cs
@@ -249,8 +249,26 @@ namespace AudibleUtilities
}
}
- foreach (var child in children)
+ int lastEpNum = -1, dupeCount = 0;
+ foreach (var child in children.OrderBy(i => i.EpisodeNumber).ThenBy(i => i.PublicationDateTime))
{
+ string sequence;
+ if (child.EpisodeNumber is null)
+ {
+ // This should properly be Single() not FirstOrDefault(), but FirstOrDefault is defensive for malformed data from audible
+ sequence = parent.Relationships.FirstOrDefault(r => r.Asin == child.Asin)?.Sort?.ToString() ?? "0";
+ }
+ else
+ {
+ //multipart episodes may have the same episode number
+ if (child.EpisodeNumber == lastEpNum)
+ dupeCount++;
+ else
+ lastEpNum = child.EpisodeNumber.Value;
+
+ sequence = (lastEpNum + dupeCount).ToString();
+ }
+
// use parent's 'DateAdded'. DateAdded is just a convenience prop for: PurchaseDate.UtcDateTime
child.PurchaseDate = parent.PurchaseDate;
// parent is essentially a series
@@ -259,8 +277,7 @@ namespace AudibleUtilities
new Series
{
Asin = parent.Asin,
- // This should properly be Single() not FirstOrDefault(), but FirstOrDefault is defensive for malformed data from audible
- Sequence = parent.Relationships.FirstOrDefault(r => r.Asin == child.Asin)?.Sort?.ToString() ?? "0",
+ Sequence = sequence,
Title = parent.TitleWithSubtitle
}
};
diff --git a/Source/HangoverAvalonia/Controls/CheckedListBox.axaml b/Source/HangoverAvalonia/Controls/CheckedListBox.axaml
index df1c6319..b7d8c94d 100644
--- a/Source/HangoverAvalonia/Controls/CheckedListBox.axaml
+++ b/Source/HangoverAvalonia/Controls/CheckedListBox.axaml
@@ -24,7 +24,7 @@
diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj
index fb32461e..676b4164 100644
--- a/Source/HangoverAvalonia/HangoverAvalonia.csproj
+++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj
@@ -66,13 +66,13 @@
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/Source/LibationAvalonia/App.axaml b/Source/LibationAvalonia/App.axaml
index ce461dcf..6716b9de 100644
--- a/Source/LibationAvalonia/App.axaml
+++ b/Source/LibationAvalonia/App.axaml
@@ -53,15 +53,15 @@
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/LibationAvalonia/Assets/DataGridFluentTheme.xaml b/Source/LibationAvalonia/Assets/DataGridFluentTheme.xaml
deleted file mode 100644
index 82ef3f10..00000000
--- a/Source/LibationAvalonia/Assets/DataGridFluentTheme.xaml
+++ /dev/null
@@ -1,588 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0.6
- 0.8
-
- M1875 1011l-787 787v-1798h-128v1798l-787 -787l-90 90l941 941l941 -941z
- M1965 947l-941 -941l-941 941l90 90l787 -787v1798h128v-1798l787 787z
- M515 93l930 931l-930 931l90 90l1022 -1021l-1022 -1021z
- M109 486 19 576 1024 1581 2029 576 1939 486 1024 1401z
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Source/LibationAvalonia/Controls/CheckedListBox.axaml b/Source/LibationAvalonia/Controls/CheckedListBox.axaml
index cf70be9a..66625cbc 100644
--- a/Source/LibationAvalonia/Controls/CheckedListBox.axaml
+++ b/Source/LibationAvalonia/Controls/CheckedListBox.axaml
@@ -24,7 +24,7 @@
diff --git a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml
index c61583eb..00577f6f 100644
--- a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml
@@ -23,7 +23,7 @@
CanUserSortColumns="False"
AutoGenerateColumns="False"
IsReadOnly="False"
- Items="{Binding Accounts}"
+ ItemsSource="{Binding Accounts}"
GridLinesVisibility="All">
@@ -64,14 +64,11 @@
-
-
-
-
-
-
-
-
+
+
@@ -96,13 +93,10 @@
-
-
-
-
-
-
-
+
diff --git a/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml b/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml
index b28db5c7..92f6252e 100644
--- a/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml
@@ -24,7 +24,7 @@
CanUserSortColumns="True"
AutoGenerateColumns="False"
IsReadOnly="False"
- Items="{Binding DataGridCollectionView}"
+ ItemsSource="{Binding DataGridCollectionView}"
GridLinesVisibility="All">
diff --git a/Source/LibationAvalonia/Dialogs/DialogWindow.cs b/Source/LibationAvalonia/Dialogs/DialogWindow.cs
index a46aea77..e6213841 100644
--- a/Source/LibationAvalonia/Dialogs/DialogWindow.cs
+++ b/Source/LibationAvalonia/Dialogs/DialogWindow.cs
@@ -41,9 +41,9 @@ namespace LibationAvalonia.Dialogs
}
protected virtual void SaveAndClose() => Close(DialogResult.OK);
- protected virtual Task SaveAndCloseAsync() => Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(SaveAndClose);
+ protected virtual async Task SaveAndCloseAsync() => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(SaveAndClose);
protected virtual void CancelAndClose() => Close(DialogResult.Cancel);
- protected virtual Task CancelAndCloseAsync() => Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(CancelAndClose);
+ protected virtual async Task CancelAndCloseAsync() => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(CancelAndClose);
private async void DialogWindow_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
{
diff --git a/Source/LibationAvalonia/Dialogs/EditQuickFilters.axaml b/Source/LibationAvalonia/Dialogs/EditQuickFilters.axaml
index db6dee86..54aad592 100644
--- a/Source/LibationAvalonia/Dialogs/EditQuickFilters.axaml
+++ b/Source/LibationAvalonia/Dialogs/EditQuickFilters.axaml
@@ -23,7 +23,7 @@
CanUserSortColumns="False"
AutoGenerateColumns="False"
IsReadOnly="False"
- Items="{Binding Filters}"
+ ItemsSource="{Binding Filters}"
GridLinesVisibility="All">
@@ -44,14 +44,11 @@
-
-
-
-
-
-
-
-
+
diff --git a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
index 4039abf5..f8d8a42b 100644
--- a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
+++ b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
@@ -24,7 +24,7 @@
BeginningEdit="ReplacementGrid_BeginningEdit"
CellEditEnding="ReplacementGrid_CellEditEnding"
KeyDown="ReplacementGrid_KeyDown"
- Items="{Binding replacements}">
+ ItemsSource="{Binding replacements}">
diff --git a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml
index 4632519b..cd5a9ba6 100644
--- a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml
@@ -45,7 +45,7 @@
GridLinesVisibility="All"
AutoGenerateColumns="False"
DoubleTapped="EditTemplateViewModel_DoubleTapped"
- Items="{Binding ListItems}" >
+ ItemsSource="{Binding ListItems}" >
diff --git a/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs
index 2fce4497..4d6c230b 100644
--- a/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs
@@ -53,7 +53,7 @@ namespace LibationAvalonia.Dialogs.Login
public async void CopyUrlToClipboard_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
- => await Application.Current.Clipboard.SetTextAsync(ExternalLoginUrl);
+ => await App.MainWindow.Clipboard.SetTextAsync(ExternalLoginUrl);
public void LaunchInBrowser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> Go.To.Url(ExternalLoginUrl);
diff --git a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml
index ccadfc6f..c98ce952 100644
--- a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml
@@ -2,10 +2,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="650"
- MinWidth="950" MinHeight="650"
- MaxWidth="950" MaxHeight="650"
- Width="950" Height="650"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650"
+ MinWidth="800" MinHeight="650"
+ MaxWidth="800" MaxHeight="650"
+ Width="800" Height="650"
x:Class="LibationAvalonia.Dialogs.SearchSyntaxDialog"
Title="Filter Options"
WindowStartupLocation="CenterOwner"
@@ -16,48 +16,55 @@
RowDefinitions="Auto,Auto,*"
ColumnDefinitions="Auto,Auto,Auto,Auto">
-
+
+
+
+
-
-
-
-
-
-
-
-
diff --git a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs
index 4c3c45f9..07992c0b 100644
--- a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs
@@ -25,6 +25,9 @@ Find books between 1-100 minutes long
length:[1 TO 100]
Find books exactly 1 hr long
length:60
+Find books published from 2020-1-1 to
+2023-12-31
+ datepublished:[20200101 TO 20231231]
" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchNumberFields());
diff --git a/Source/LibationAvalonia/FormSaveExtension.cs b/Source/LibationAvalonia/FormSaveExtension.cs
index c9bca50b..0a9f0123 100644
--- a/Source/LibationAvalonia/FormSaveExtension.cs
+++ b/Source/LibationAvalonia/FormSaveExtension.cs
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Platform;
using LibationFileManager;
using System;
using System.Linq;
@@ -111,12 +112,12 @@ namespace LibationAvalonia
public static void HideMinMaxBtns(this Window form)
{
- if (Design.IsDesignMode || !Configuration.IsWindows)
+ if (Design.IsDesignMode || !Configuration.IsWindows || form.TryGetPlatformHandle() is not IPlatformHandle handle)
return;
- var handle = form.PlatformImpl.Handle.Handle;
- var currentStyle = GetWindowLong(handle, GWL_STYLE);
- SetWindowLong(handle, GWL_STYLE, currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
+ var currentStyle = GetWindowLong(handle.Handle, GWL_STYLE);
+
+ SetWindowLong(handle.Handle, GWL_STYLE, currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
}
const long WS_MINIMIZEBOX = 0x00020000L;
diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj
index 744f3e98..39448922 100644
--- a/Source/LibationAvalonia/LibationAvalonia.csproj
+++ b/Source/LibationAvalonia/LibationAvalonia.csproj
@@ -32,8 +32,8 @@
-
-
+
+
@@ -70,13 +70,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml
index 555576dc..03323d4e 100644
--- a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml
+++ b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml
@@ -46,7 +46,7 @@
VerticalCacheLength="1.2"
HorizontalCacheLength="1"
Background="Transparent"
- Items="{Binding Items}"
+ ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource elementFactory}" />
@@ -81,7 +81,7 @@
-
+
diff --git a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs
index 70c95408..0b7761d8 100644
--- a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs
+++ b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs
@@ -130,7 +130,7 @@ namespace LibationAvalonia.Views
private async void LogCopyBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
string logText = string.Join("\r\n", _viewModel.LogEntries.Select(r => $"{r.LogDate.ToShortDateString()} {r.LogDate.ToShortTimeString()}\t{r.LogMessage}"));
- await Application.Current.Clipboard.SetTextAsync(logText);
+ await App.MainWindow.Clipboard.SetTextAsync(logText);
}
private async void cancelAllBtn_Click(object sender, EventArgs e)
diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml
index 62207098..a7fb4bf9 100644
--- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml
+++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml
@@ -15,7 +15,7 @@
ClipboardCopyMode="IncludeHeader"
GridLinesVisibility="All"
AutoGenerateColumns="False"
- Items="{Binding GridEntries}"
+ ItemsSource="{Binding GridEntries}"
CanUserSortColumns="True" BorderThickness="3"
CanUserReorderColumns="True">
diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
index 51860b77..9fe44d1b 100644
--- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
+++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
@@ -231,7 +231,7 @@ namespace LibationAvalonia.Views
var menuItem = new MenuItem { Header = "_Copy Cell Contents" };
menuItem.Click += async (s, e)
- => await Application.Current.Clipboard.SetTextAsync(args.CellClipboardContents);
+ => await App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents);
args.ContextMenuItems.Add(menuItem);
}
diff --git a/Source/LibationAvalonia/Views/SeriesViewGrid.axaml b/Source/LibationAvalonia/Views/SeriesViewGrid.axaml
index ad7d3a91..69e3326a 100644
--- a/Source/LibationAvalonia/Views/SeriesViewGrid.axaml
+++ b/Source/LibationAvalonia/Views/SeriesViewGrid.axaml
@@ -11,7 +11,7 @@
ClipboardCopyMode="IncludeHeader"
GridLinesVisibility="All"
AutoGenerateColumns="False"
- Items="{Binding SeriesEntries}"
+ ItemsSource="{Binding SeriesEntries}"
CanUserSortColumns="True"
CanUserReorderColumns="True"
BorderThickness="3">
diff --git a/Source/LibationFileManager/IInteropFunctions.cs b/Source/LibationFileManager/IInteropFunctions.cs
index 7b0df53c..a79cc0f3 100644
--- a/Source/LibationFileManager/IInteropFunctions.cs
+++ b/Source/LibationFileManager/IInteropFunctions.cs
@@ -16,6 +16,7 @@ namespace LibationFileManager
Process RunAsRoot(string exe, string args);
void InstallUpgrade(string upgradeBundle);
bool CanUpgrade { get; }
+ string ReleaseIdString { get; }
}
public class WebViewNavigationEventArgs : EventArgs
diff --git a/Source/LibationFileManager/NullInteropFunctions.cs b/Source/LibationFileManager/NullInteropFunctions.cs
index aba0b46f..b72e354d 100644
--- a/Source/LibationFileManager/NullInteropFunctions.cs
+++ b/Source/LibationFileManager/NullInteropFunctions.cs
@@ -15,6 +15,7 @@ namespace LibationFileManager
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
public bool CanUpgrade => throw new PlatformNotSupportedException();
+ public string ReleaseIdString => throw new PlatformNotSupportedException();
public Process RunAsRoot(string exe, string args) => throw new PlatformNotSupportedException();
public void InstallUpgrade(string updateBundle) => throw new PlatformNotSupportedException();
}
diff --git a/Source/LibationSearchEngine/LuceneExtensions.cs b/Source/LibationSearchEngine/LuceneExtensions.cs
index 0a0c2071..20c3eaa9 100644
--- a/Source/LibationSearchEngine/LuceneExtensions.cs
+++ b/Source/LibationSearchEngine/LuceneExtensions.cs
@@ -37,6 +37,8 @@ namespace LibationSearchEngine
internal static string ToLuceneString(this float f) => ((double)f).ToLuceneString();
internal static string ToLuceneString(this DateTime dt)
=> dt.ToString("yyyyMMdd") + DECIMAL_PRECISION;
+ internal static string ToLuceneString(this DateTime? dt)
+ => dt?.ToLuceneString() ?? "";
internal static string ToLuceneString(this double d)
=> d.ToString("0" + DECIMAL_PRECISION).PadLeft(PAD_DIGITS + DECIMAL_PRECISION.Length, '0');
}
diff --git a/Source/LibationSearchEngine/SearchEngine.cs b/Source/LibationSearchEngine/SearchEngine.cs
index a24266cd..693775f3 100644
--- a/Source/LibationSearchEngine/SearchEngine.cs
+++ b/Source/LibationSearchEngine/SearchEngine.cs
@@ -46,9 +46,6 @@ namespace LibationSearchEngine
= new ReadOnlyDictionary>(
new Dictionary>
{
- [nameof(LibraryBook.DateAdded)] = lb => lb.DateAdded.ToLuceneString(),
- [nameof(Book.DatePublished)] = lb => lb.Book.DatePublished?.ToLuceneString(),
-
[nameof(Book.Title)] = lb => lb.Book.Title,
[ALL_AUTHOR_NAMES] = lb => lb.Book.AuthorNames(),
["Author"] = lb => lb.Book.AuthorNames(),
@@ -91,7 +88,13 @@ namespace LibationSearchEngine
["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
["UserRating"] = lb => userOverallRating(lb.Book),
- ["MyRating"] = lb => userOverallRating(lb.Book)
+ ["MyRating"] = lb => userOverallRating(lb.Book),
+
+ [nameof(LibraryBook.DateAdded)] = lb => lb.DateAdded.ToLuceneString(),
+ [nameof(Book.DatePublished)] = lb => lb.Book.DatePublished?.ToLuceneString(),
+
+ ["LastDownload"] = lb => lb.Book.UserDefinedItem.LastDownloaded.ToLuceneString(),
+ ["LastDownloaded"] = lb => lb.Book.UserDefinedItem.LastDownloaded.ToLuceneString()
}
);
@@ -127,6 +130,9 @@ namespace LibationSearchEngine
["Episode"] = lb => lb.Book.IsEpisodeChild(),
["Episodes"] = lb => lb.Book.IsEpisodeChild(),
["IsEpisode"] = lb => lb.Book.IsEpisodeChild(),
+
+ ["Absent"] = lb => lb.AbsentFromLastScan,
+ ["AbsentFromLastScan"] = lb => lb.AbsentFromLastScan,
}
);
@@ -287,7 +293,13 @@ namespace LibationSearchEngine
var v2 = liberatedError(book);
d.RemoveField("liberatederror");
d.AddBool("LiberatedError", v2);
- });
+
+ var v3 = book.UserDefinedItem.LastDownloaded?.ToLuceneString() ?? "";
+ d.RemoveField("LastDownload");
+ d.AddNotAnalyzed("LastDownload", v3);
+ d.RemoveField("LastDownloaded");
+ d.AddNotAnalyzed("LastDownloaded", v3);
+ });
public void UpdateUserRatings(Book book)
=>updateDocument(
diff --git a/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.Designer.cs b/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.Designer.cs
index 7600c226..f1aecf39 100644
--- a/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.Designer.cs
+++ b/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.Designer.cs
@@ -1,132 +1,135 @@
namespace LibationWinForms.Dialogs
{
- partial class SearchSyntaxDialog
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
+ partial class SearchSyntaxDialog
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
- #region Windows Form Designer generated code
+ #region Windows Form Designer generated code
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- this.label1 = new System.Windows.Forms.Label();
- this.label2 = new System.Windows.Forms.Label();
- this.label3 = new System.Windows.Forms.Label();
- this.label4 = new System.Windows.Forms.Label();
- this.label5 = new System.Windows.Forms.Label();
- this.closeBtn = new System.Windows.Forms.Button();
- this.SuspendLayout();
- //
- // label1
- //
- this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(12, 9);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(358, 52);
- this.label1.TabIndex = 0;
- this.label1.Text = "Full Lucene query syntax is supported\r\nFields with similar names are synomyns (eg" +
- ": Author, Authors, AuthorNames)\r\n\r\nTAG FORMAT: [tagName]";
- //
- // label2
- //
- this.label2.AutoSize = true;
- this.label2.Location = new System.Drawing.Point(12, 71);
- this.label2.Name = "label2";
- this.label2.Size = new System.Drawing.Size(118, 65);
- this.label2.TabIndex = 1;
- this.label2.Text = "STRING FIELDS\r\n\r\nSearch for wizard of oz:\r\n title:oz\r\n title:\"wizard of o" +
- "z\"";
- //
- // label3
- //
- this.label3.AutoSize = true;
- this.label3.Location = new System.Drawing.Point(233, 71);
- this.label3.Name = "label3";
- this.label3.Size = new System.Drawing.Size(195, 78);
- this.label3.TabIndex = 2;
- this.label3.Text = "NUMBER FIELDS\r\n\r\nFind books between 1-100 minutes long\r\n length:[1 TO 100]\r\nF" +
- "ind books exactly 1 hr long\r\n length:60";
- //
- // label4
- //
- this.label4.AutoSize = true;
- this.label4.Location = new System.Drawing.Point(454, 71);
- this.label4.Name = "label4";
- this.label4.Size = new System.Drawing.Size(168, 52);
- this.label4.TabIndex = 3;
- this.label4.Text = "BOOLEAN (TRUE/FALSE) FIELDS\r\n\r\nFind books that you haven\'t rated:\r\n -IsRated";
- //
- // label5
- //
- this.label5.AutoSize = true;
- this.label5.Location = new System.Drawing.Point(673, 71);
- this.label5.Name = "label5";
- this.label5.Size = new System.Drawing.Size(257, 78);
- this.label5.TabIndex = 4;
- this.label5.Text = "ID FIELDS\r\n\r\nAlice\'s Adventures in Wonderland (ID: B015D78L0U)\r\n id:B015D78L0" +
- "U\r\n\r\nAll of these are synonyms for the ID field";
- //
- // closeBtn
- //
- this.closeBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.closeBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.closeBtn.Location = new System.Drawing.Point(890, 465);
- this.closeBtn.Name = "closeBtn";
- this.closeBtn.Size = new System.Drawing.Size(75, 23);
- this.closeBtn.TabIndex = 5;
- this.closeBtn.Text = "Close";
- this.closeBtn.UseVisualStyleBackColor = true;
- this.closeBtn.Click += new System.EventHandler(this.CloseBtn_Click);
- //
- // SearchSyntaxDialog
- //
- this.AcceptButton = this.closeBtn;
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.CancelButton = this.closeBtn;
- this.ClientSize = new System.Drawing.Size(977, 500);
- this.Controls.Add(this.closeBtn);
- this.Controls.Add(this.label5);
- this.Controls.Add(this.label4);
- this.Controls.Add(this.label3);
- this.Controls.Add(this.label2);
- this.Controls.Add(this.label1);
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "SearchSyntaxDialog";
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
- this.Text = "Filter options";
- this.ResumeLayout(false);
- this.PerformLayout();
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SearchSyntaxDialog));
+ label1 = new System.Windows.Forms.Label();
+ label2 = new System.Windows.Forms.Label();
+ label3 = new System.Windows.Forms.Label();
+ label4 = new System.Windows.Forms.Label();
+ label5 = new System.Windows.Forms.Label();
+ closeBtn = new System.Windows.Forms.Button();
+ SuspendLayout();
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Location = new System.Drawing.Point(14, 10);
+ label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ label1.Name = "label1";
+ label1.Size = new System.Drawing.Size(410, 60);
+ label1.TabIndex = 0;
+ label1.Text = "Full Lucene query syntax is supported\r\nFields with similar names are synomyns (eg: Author, Authors, AuthorNames)\r\n\r\nTAG FORMAT: [tagName]";
+ //
+ // label2
+ //
+ label2.AutoSize = true;
+ label2.Location = new System.Drawing.Point(14, 82);
+ label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ label2.Name = "label2";
+ label2.Size = new System.Drawing.Size(129, 75);
+ label2.TabIndex = 1;
+ label2.Text = "STRING FIELDS\r\n\r\nSearch for wizard of oz:\r\n title:oz\r\n title:\"wizard of oz\"";
+ //
+ // label3
+ //
+ label3.AutoSize = true;
+ label3.Location = new System.Drawing.Point(272, 82);
+ label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ label3.Name = "label3";
+ label3.Size = new System.Drawing.Size(224, 135);
+ label3.TabIndex = 2;
+ label3.Text = resources.GetString("label3.Text");
+ //
+ // label4
+ //
+ label4.AutoSize = true;
+ label4.Location = new System.Drawing.Point(530, 82);
+ label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ label4.Name = "label4";
+ label4.Size = new System.Drawing.Size(187, 60);
+ label4.TabIndex = 3;
+ label4.Text = "BOOLEAN (TRUE/FALSE) FIELDS\r\n\r\nFind books that you haven't rated:\r\n -IsRated";
+ //
+ // label5
+ //
+ label5.AutoSize = true;
+ label5.Location = new System.Drawing.Point(785, 82);
+ label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ label5.Name = "label5";
+ label5.Size = new System.Drawing.Size(278, 90);
+ label5.TabIndex = 4;
+ label5.Text = "ID FIELDS\r\n\r\nAlice's Adventures in Wonderland (ID: B015D78L0U)\r\n id:B015D78L0U\r\n\r\nAll of these are synonyms for the ID field";
+ //
+ // closeBtn
+ //
+ closeBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ closeBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ closeBtn.Location = new System.Drawing.Point(1038, 537);
+ closeBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ closeBtn.Name = "closeBtn";
+ closeBtn.Size = new System.Drawing.Size(88, 27);
+ closeBtn.TabIndex = 5;
+ closeBtn.Text = "Close";
+ closeBtn.UseVisualStyleBackColor = true;
+ closeBtn.Click += CloseBtn_Click;
+ //
+ // SearchSyntaxDialog
+ //
+ AcceptButton = closeBtn;
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ CancelButton = closeBtn;
+ ClientSize = new System.Drawing.Size(1140, 577);
+ Controls.Add(closeBtn);
+ Controls.Add(label5);
+ Controls.Add(label4);
+ Controls.Add(label3);
+ Controls.Add(label2);
+ Controls.Add(label1);
+ Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ MaximizeBox = false;
+ MinimizeBox = false;
+ Name = "SearchSyntaxDialog";
+ StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ Text = "Filter options";
+ ResumeLayout(false);
+ PerformLayout();
+ }
- }
+ #endregion
- #endregion
-
- private System.Windows.Forms.Label label1;
- private System.Windows.Forms.Label label2;
- private System.Windows.Forms.Label label3;
- private System.Windows.Forms.Label label4;
- private System.Windows.Forms.Label label5;
- private System.Windows.Forms.Button closeBtn;
- }
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Button closeBtn;
+ }
}
\ No newline at end of file
diff --git a/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.resx b/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.resx
index e8ae276d..395c5678 100644
--- a/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.resx
+++ b/Source/LibationWinForms/Dialogs/SearchSyntaxDialog.resx
@@ -1,5 +1,4 @@
-
-
+
@@ -58,4 +57,15 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ NUMBER FIELDS
+
+Find books between 1-100 minutes long
+ length:[1 TO 100]
+Find books exactly 1 hr long
+ length:60
+Find books published from 2020-1-1 to
+2023-12-31
+ datepublished:[20200101 TO 20231231]
+
\ No newline at end of file
diff --git a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs
index d3d76482..d005c122 100644
--- a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs
+++ b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs
@@ -1,4 +1,5 @@
-using LibationFileManager;
+using AppScaffolding;
+using LibationFileManager;
using System.Diagnostics;
namespace LinuxConfigApp
@@ -24,12 +25,17 @@ namespace LinuxConfigApp
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
+ public string ReleaseIdString => LibationScaffolding.ReleaseIdentifier.ToString() + (File.Exists("/bin/yum") ? "_RPM" : "");
+
//only run the auto upgrader if the current app was installed from the
- //.deb package. Try to detect this by checking if the symlink exists.
+ //.deb or .rpm package. Try to detect this by checking if the symlink exists.
public bool CanUpgrade => Directory.Exists("/usr/lib/libation");
public void InstallUpgrade(string upgradeBundle)
{
- RunAsRoot("apt", $"install '{upgradeBundle}'");
+ if (File.Exists("/bin/yum"))
+ RunAsRoot("yum", $"install '{upgradeBundle}'");
+ else
+ RunAsRoot("apt", $"install '{upgradeBundle}'");
}
public Process RunAsRoot(string exe, string args)
diff --git a/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs b/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs
index 0cc75660..ca48996a 100644
--- a/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs
+++ b/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs
@@ -24,6 +24,8 @@ namespace MacOSConfigApp
//the running process, so don't upgrade unless it's "installed" in /Applications
public bool CanUpgrade => Directory.Exists(AppPath);
+ public string ReleaseIdString => AppScaffolding.LibationScaffolding.ReleaseIdentifier.ToString();
+
public void InstallUpgrade(string upgradeBundle)
{
Serilog.Log.Information($"Extracting upgrade bundle to {AppPath}");
diff --git a/Source/LoadByOS/WindowsConfigApp/WinInterop.cs b/Source/LoadByOS/WindowsConfigApp/WinInterop.cs
index bf8eae77..32fce3da 100644
--- a/Source/LoadByOS/WindowsConfigApp/WinInterop.cs
+++ b/Source/LoadByOS/WindowsConfigApp/WinInterop.cs
@@ -25,6 +25,9 @@ namespace WindowsConfigApp
=> new DirectoryInfo(directory)?.DeleteIcon();
public bool CanUpgrade => true;
+
+ public string ReleaseIdString => AppScaffolding.LibationScaffolding.ReleaseIdentifier.ToString();
+
public void InstallUpgrade(string upgradeBundle)
{
var thisExe = Environment.ProcessPath;