diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml
index 56d1b219..3f3a8fd0 100644
--- a/.github/workflows/build-linux.yml
+++ b/.github/workflows/build-linux.yml
@@ -23,10 +23,10 @@ env:
jobs:
build:
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [Linux, MacOS]
+ os: [ubuntu-latest, macos-latest]
arch: [x64, arm64]
steps:
- uses: actions/checkout@v3
@@ -45,62 +45,63 @@ jobs:
then
version="${inputVersion}"
else
- version="$(grep -oP '(?<=).*(?=.*' ./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
run: dotnet test
- name: Publish
+ id: publish
working-directory: ./Source
run: |
os=${{ matrix.os }}
- RUNTIME_IDENTIFIER="$(echo ${os,} | sed 's/macOS/osx/')-${{ matrix.arch }}"
+ target_os="$(echo ${os/-latest/} | sed 's/ubuntu/linux/')"
+ display_os="$(echo ${target_os/macos/macOS} | sed 's/linux/Linux/')"
+ echo "display_os=${display_os}" >> $GITHUB_OUTPUT
+ RUNTIME_IDENTIFIER="$(echo ${target_os/macos/osx})-${{ matrix.arch }}"
echo "$RUNTIME_IDENTIFIER"
dotnet publish \
LibationAvalonia/LibationAvalonia.csproj \
--runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
- -p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml
+ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ -p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \
- LoadByOS/${{ matrix.os }}ConfigApp/${{ matrix.os }}ConfigApp.csproj \
+ LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \
--runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
- -p:PublishProfile=LoadByOS/Properties/${{ matrix.os }}ConfigApp/PublishProfiles/${{ matrix.os }}Profile.pubxml
+ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ -p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \
LibationCli/LibationCli.csproj \
--runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
- -p:PublishProfile=LibationCli/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml
+ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ -p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \
HangoverAvalonia/HangoverAvalonia.csproj \
--runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \
- --output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
- -p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml
-
+ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
+ -p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
- name: Build bundle
id: bundle
- working-directory: ./Source/bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }}
+ working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }}
run: |
BUNDLE_DIR=$(pwd)
echo "Bundle dir: ${BUNDLE_DIR}"
cd ..
- SCRIPT=../../../Scripts/Bundle_${{ matrix.os }}.sh
+ SCRIPT=../../../Scripts/Bundle_${{ steps.publish.outputs.display_os }}.sh
chmod +rx ${SCRIPT}
${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ matrix.arch }}"
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
+ if-no-files-found: error
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 00000000..9940d7d0
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,21 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/Source/bin/Avalonia/Debug/Libation.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "console": "internalConsole"
+ }
+
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 00000000..2ba35f87
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "dependsOn": [
+ "build_libation",
+ "build_linuxconfigapp"
+ ]
+ },
+ {
+ "label": "build_libation",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "${workspaceFolder}/Source/LibationAvalonia/LibationAvalonia.csproj"
+ ],
+ "group": "build",
+ "presentation": {
+ //"reveal": "silent"
+ },
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "build_linuxconfigapp",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "${workspaceFolder}/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj"
+ ],
+ "group": "build",
+ "presentation": {
+ //"reveal": "silent"
+ },
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Documentation/InstallOnMac.md b/Documentation/InstallOnMac.md
index 7d4a9af3..45e0be78 100644
--- a/Documentation/InstallOnMac.md
+++ b/Documentation/InstallOnMac.md
@@ -13,14 +13,10 @@ This walkthrough should get you up and running with Libation on your Mac.
- Move the extracted Libation app bundle to your applications folder.
- Open a terminal (Go > Utilities > Terminal)
- Copy/paste/run the following command (you'll be prompted to enter your password)
- - macOS x64
- ```Console
- sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
- ```
- - macOS arm64
- ```Console
- codesign --force --deep -s - /Applications/Libation.app && sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
- ```
+
+ ```Console
+ sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
+ ```
- Close the terminal and use Libation!
## Running Hangover
diff --git a/Scripts/Bundle_Linux.sh b/Scripts/Bundle_Linux.sh
index a5f842ef..9fcb1437 100644
--- a/Scripts/Bundle_Linux.sh
+++ b/Scripts/Bundle_Linux.sh
@@ -88,38 +88,27 @@ cp $FOLDER_EXEC/Libation.desktop $FOLDER_DESKTOP/Libation.desktop
echo "Creating pre-install file..."
echo "#!/bin/bash
-
# Pre-install script, removes previous installation program files and sym links
-
echo \"Removing previously created symlinks...\"
-
rm /usr/bin/libation
rm /usr/bin/hangover
rm /usr/bin/libationcli
-
echo \"Removing previously installed Libation files...\"
-
rm -r /usr/lib/libation
-
# making sure it won't stop installation
exit 0
" >> $FOLDER_DEBIAN/preinst
echo "Creating post-install file..."
echo "#!/bin/bash
-
gtk-update-icon-cache -f /usr/share/icons/hicolor/
-
ln -s /usr/lib/libation/Libation /usr/bin/libation
ln -s /usr/lib/libation/Hangover /usr/bin/hangover
ln -s /usr/lib/libation/LibationCli /usr/bin/libationcli
-
# Increase the maximum number of inotify instances
-
-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
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
@@ -139,6 +128,11 @@ echo "Changing permissions for pre- and post-install files..."
chmod +x "$FOLDER_DEBIAN/preinst"
chmod +x "$FOLDER_DEBIAN/postinst"
+if [ "$(uname -s)" == "Darwin" ]; then
+ echo "macOS detected, installing dpkg"
+ brew install dpkg
+fi
+
DEB_FILE=Libation.${VERSION}-linux-chardonnay-${ARCH}.deb
echo "Creating $DEB_FILE"
dpkg-deb -Zxz --build $DEB_DIR ./$DEB_FILE
@@ -149,4 +143,4 @@ mv $DEB_FILE ./bundle/$DEB_FILE
rm -r "$BIN_DIR"
-echo "Done!"
+echo "Done!"
\ No newline at end of file
diff --git a/Scripts/Bundle_MacOS.sh b/Scripts/Bundle_MacOS.sh
index d9bd31b9..57bc60e1 100644
--- a/Scripts/Bundle_MacOS.sh
+++ b/Scripts/Bundle_MacOS.sh
@@ -96,6 +96,9 @@ done
APP_FILE=Libation.${VERSION}-macOS-chardonnay-${ARCH}.tgz
+echo "Signing executables in: $BUNDLE"
+codesign --force --deep -s - $BUNDLE
+
echo "Creating app bundle: $APP_FILE"
tar -czvf $APP_FILE $BUNDLE
@@ -105,4 +108,4 @@ mv $APP_FILE ./bundle/$APP_FILE
rm -r $BUNDLE
-echo "Done!"
+echo "Done!"
\ No newline at end of file
diff --git a/Source/AaxDecrypter/AudiobookDownloadBase.cs b/Source/AaxDecrypter/AudiobookDownloadBase.cs
index fff17d58..9f8bb535 100644
--- a/Source/AaxDecrypter/AudiobookDownloadBase.cs
+++ b/Source/AaxDecrypter/AudiobookDownloadBase.cs
@@ -3,7 +3,6 @@ using Dinah.Core.Net.Http;
using Dinah.Core.StepRunner;
using FileManager;
using System;
-using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
@@ -225,6 +224,7 @@ namespace AaxDecrypter
}
finally
{
+ nfsp.NetworkFileStream.RequestHeaders["User-Agent"] = DownloadOptions.UserAgent;
nfsp.NetworkFileStream.SpeedLimit = DownloadOptions.DownloadSpeedBps;
}
diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs
index 46f173ac..376bde2c 100644
--- a/Source/AudibleUtilities/ApiExtended.cs
+++ b/Source/AudibleUtilities/ApiExtended.cs
@@ -39,42 +39,6 @@ namespace AudibleUtilities
return new ApiExtended(api);
}
- /// Get api from existing tokens else login with native api callbacks.
- public static async Task CreateAsync(Account account, ILoginCallback loginCallback)
- {
- Serilog.Log.Logger.Information("{@DebugInfo}", new
- {
- LoginType = nameof(ILoginCallback),
- Account = account?.MaskedLogEntry ?? "[null]",
- LocaleName = account?.Locale?.Name
- });
-
- var api = await EzApiCreator.GetApiAsync(
- loginCallback,
- account.Locale,
- AudibleApiStorage.AccountsSettingsFile,
- account.GetIdentityTokensJsonPath());
- return new ApiExtended(api);
- }
-
- /// Get api from existing tokens else login with external browser
- public static async Task CreateAsync(Account account, ILoginExternal loginExternal)
- {
- Serilog.Log.Logger.Information("{@DebugInfo}", new
- {
- LoginType = nameof(ILoginExternal),
- Account = account?.MaskedLogEntry ?? "[null]",
- LocaleName = account?.Locale?.Name
- });
-
- var api = await EzApiCreator.GetApiAsync(
- loginExternal,
- account.Locale,
- AudibleApiStorage.AccountsSettingsFile,
- account.GetIdentityTokensJsonPath());
- return new ApiExtended(api);
- }
-
/// Get api from existing tokens. Assumes you have valid login tokens. Else exception
public static async Task CreateAsync(Account account)
{
diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj
index 95ffd248..48394512 100644
--- a/Source/AudibleUtilities/AudibleUtilities.csproj
+++ b/Source/AudibleUtilities/AudibleUtilities.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/Source/AudibleUtilities/Mkb79Auth.cs b/Source/AudibleUtilities/Mkb79Auth.cs
index f3bc6db5..2e4c56ef 100644
--- a/Source/AudibleUtilities/Mkb79Auth.cs
+++ b/Source/AudibleUtilities/Mkb79Auth.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using AudibleApi;
using AudibleApi.Authorization;
+using AudibleApi.Cryptography;
using Dinah.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -178,7 +179,7 @@ namespace AudibleUtilities
LocaleCode = account.Locale.CountryCode,
RefreshToken = account.IdentityTokens.RefreshToken.Value,
StoreAuthenticationCookie = account.IdentityTokens.StoreAuthenticationCookie,
- WebsiteCookies = new(account.IdentityTokens.Cookies.ToKeyValuePair()),
+ WebsiteCookies = new(account.IdentityTokens.Cookies),
};
}
diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj
index c00bc51c..6db44c40 100644
--- a/Source/HangoverAvalonia/HangoverAvalonia.csproj
+++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj
@@ -21,13 +21,7 @@
-
- en;es
+ en
diff --git a/Source/HangoverWinForms/HangoverWinForms.csproj b/Source/HangoverWinForms/HangoverWinForms.csproj
index dd37f2e3..78b131cf 100644
--- a/Source/HangoverWinForms/HangoverWinForms.csproj
+++ b/Source/HangoverWinForms/HangoverWinForms.csproj
@@ -16,13 +16,7 @@
-
- en;es
+ en
- copyused
true
libation.ico
Libation
@@ -17,13 +15,7 @@
-
- en;es
+ en
@@ -109,7 +101,7 @@
-
+
diff --git a/Source/LibationAvalonia/ViewModels/MainWindowViewModel.cs b/Source/LibationAvalonia/ViewModels/MainWindowViewModel.cs
index 0fca0bb4..8f5fa93a 100644
--- a/Source/LibationAvalonia/ViewModels/MainWindowViewModel.cs
+++ b/Source/LibationAvalonia/ViewModels/MainWindowViewModel.cs
@@ -25,6 +25,9 @@ namespace LibationAvalonia.ViewModels
public ProcessQueueViewModel ProcessQueue { get; } = new ProcessQueueViewModel();
public ProductsDisplayViewModel ProductsDisplay { get; } = new ProductsDisplayViewModel();
+ private double? _downloadProgress = null;
+ public double? DownloadProgress { get => _downloadProgress; set => this.RaiseAndSetIfChanged(ref _downloadProgress, value); }
+
/// Library filterting query
public string FilterString { get => _filterString; set => this.RaiseAndSetIfChanged(ref _filterString, value); }
diff --git a/Source/LibationAvalonia/Views/MainWindow.ScanAuto.cs b/Source/LibationAvalonia/Views/MainWindow.ScanAuto.cs
index 422872e4..f201e57f 100644
--- a/Source/LibationAvalonia/Views/MainWindow.ScanAuto.cs
+++ b/Source/LibationAvalonia/Views/MainWindow.ScanAuto.cs
@@ -9,7 +9,6 @@ using System.Linq;
namespace LibationAvalonia.Views
{
- //DONE
public partial class MainWindow
{
private InterruptableTimer autoScanTimer;
@@ -17,11 +16,7 @@ namespace LibationAvalonia.Views
private void Configure_ScanAuto()
{
// creating InterruptableTimer inside 'Configure_' is a break from the pattern. As long as no one else needs to access or subscribe to it, this is ok
- var hours = 0;
- var minutes = 5;
- var seconds = 0;
- var _5_minutes = new TimeSpan(hours, minutes, seconds);
- autoScanTimer = new InterruptableTimer(_5_minutes);
+ autoScanTimer = new InterruptableTimer(TimeSpan.FromMinutes(5));
// subscribe as async/non-blocking. I'd actually rather prefer blocking but real-world testing found that caused a deadlock in the AudibleAPI
autoScanTimer.Elapsed += async (_, __) =>
@@ -44,9 +39,9 @@ namespace LibationAvalonia.Views
};
_viewModel.AutoScanChecked = Configuration.Instance.AutoScan;
-
+
// if enabled: begin on load
- Load += startAutoScan;
+ Opened += startAutoScan;
// if new 'default' account is added, run autoscan
AccountsSettingsPersister.Saving += accountsPreSave;
diff --git a/Source/LibationAvalonia/Views/MainWindow.Update.cs b/Source/LibationAvalonia/Views/MainWindow.Update.cs
deleted file mode 100644
index e466c41a..00000000
--- a/Source/LibationAvalonia/Views/MainWindow.Update.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using AppScaffolding;
-using LibationAvalonia.Dialogs;
-using LibationFileManager;
-using System;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace LibationAvalonia.Views
-{
- public partial class MainWindow
- {
- private void Configure_Update()
- {
- Opened += async (_, _) => await checkForUpdates();
- }
-
- private async Task checkForUpdates()
- {
- async Task downloadUpdate(UpgradeProperties upgradeProperties)
- {
- if (upgradeProperties.ZipUrl is null)
- {
- Serilog.Log.Logger.Warning("Download link for new version not found");
- return null;
- }
-
- //Silently download the update in the background, save it to a temp file.
-
- var zipFile = Path.Combine(Path.GetTempPath(), Path.GetFileName(upgradeProperties.ZipUrl));
-
- Serilog.Log.Logger.Information($"Downloading {zipFile}");
-
- try
- {
- System.Net.Http.HttpClient cli = new();
- using var fs = File.OpenWrite(zipFile);
- using var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl));
- await dlStream.CopyToAsync(fs);
- }
- catch (Exception ex)
- {
- Serilog.Log.Logger.Error(ex, "Failed to download the update: {pdate}", upgradeProperties.ZipUrl);
- return null;
- }
- return zipFile;
- }
-
- try
- {
- var upgradeProperties = await Task.Run(LibationScaffolding.GetLatestRelease);
- if (upgradeProperties is null) return;
-
- const string ignoreUpdate = "IgnoreUpdate";
- var config = Configuration.Instance;
-
- if (config.GetString(propertyName: ignoreUpdate) == upgradeProperties.LatestRelease.ToString())
- return;
-
- var interop = InteropFactory.Create();
-
- if (!interop.CanUpdate)
- Serilog.Log.Logger.Information("Can't perform update automatically");
-
- var notificationResult = await new UpgradeNotificationDialog(upgradeProperties, interop.CanUpdate).ShowDialog(this);
-
- if (notificationResult == DialogResult.Ignore)
- config.SetString(upgradeProperties.LatestRelease.ToString(), ignoreUpdate);
-
- if (notificationResult != DialogResult.OK) return;
-
- //Download the update file in the background,
- string updateBundle = await downloadUpdate(upgradeProperties);
-
- if (string.IsNullOrEmpty(updateBundle) || !File.Exists(updateBundle)) return;
-
- //Install the update
- Serilog.Log.Logger.Information($"Begin running auto-updater");
- interop.InstallUpdate(updateBundle);
- Serilog.Log.Logger.Information($"Completed running auto-updater");
- }
- catch (Exception ex)
- {
- Serilog.Log.Logger.Error(ex, "An error occured while checking for app updates.");
- }
- }
- }
-}
diff --git a/Source/LibationAvalonia/Views/MainWindow.Upgrade.cs b/Source/LibationAvalonia/Views/MainWindow.Upgrade.cs
new file mode 100644
index 00000000..02b315ba
--- /dev/null
+++ b/Source/LibationAvalonia/Views/MainWindow.Upgrade.cs
@@ -0,0 +1,34 @@
+using Avalonia.Threading;
+using LibationAvalonia.Dialogs;
+using LibationUiBase;
+using System.Threading.Tasks;
+
+namespace LibationAvalonia.Views
+{
+ public partial class MainWindow
+ {
+ private void Configure_Upgrade()
+ {
+ setProgressVisible(false);
+#if !DEBUG
+ async Task upgradeAvailable(UpgradeEventArgs e)
+ {
+ var notificationResult = await new UpgradeNotificationDialog(e.UpgradeProperties, e.CapUpgrade).ShowDialogAsync(this);
+
+ e.Ignore = notificationResult == DialogResult.Ignore;
+ e.InstallUpgrade = notificationResult == DialogResult.OK;
+ }
+
+ var upgrader = new Upgrader();
+ upgrader.DownloadProgress += async (_, e) => await Dispatcher.UIThread.InvokeAsync(() => _viewModel.DownloadProgress = e.ProgressPercentage);
+ upgrader.DownloadBegin += async (_, _) => await Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(true));
+ upgrader.DownloadCompleted += async (_, _) => await Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(false));
+
+ Opened += async (_, _) => await upgrader.CheckForUpgradeAsync(upgradeAvailable);
+#endif
+ }
+
+ private void setProgressVisible(bool visible) => _viewModel.DownloadProgress = visible ? 0 : null;
+
+ }
+}
diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml b/Source/LibationAvalonia/Views/MainWindow.axaml
index c1a44e47..8b2fffb8 100644
--- a/Source/LibationAvalonia/Views/MainWindow.axaml
+++ b/Source/LibationAvalonia/Views/MainWindow.axaml
@@ -194,9 +194,16 @@
-
-
-
+
+
+
+
+
+
+
+
diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs
index 33094e6f..88f8a705 100644
--- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs
+++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs
@@ -40,9 +40,7 @@ namespace LibationAvalonia.Views
Configure_Export();
Configure_Settings();
Configure_ProcessQueue();
-#if !DEBUG
- Configure_Update();
-#endif
+ Configure_Upgrade();
Configure_Filter();
// misc which belongs in winforms app but doesn't have a UI element
Configure_NonUI();
diff --git a/Source/LibationCli/LibationCli.csproj b/Source/LibationCli/LibationCli.csproj
index b61341eb..04926587 100644
--- a/Source/LibationCli/LibationCli.csproj
+++ b/Source/LibationCli/LibationCli.csproj
@@ -11,13 +11,7 @@
-
- en;es
+ en
-
- en;es
+ en
@@ -44,7 +37,6 @@
-
diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs
index 28148e21..5afd05b1 100644
--- a/Source/LibationWinForms/Program.cs
+++ b/Source/LibationWinForms/Program.cs
@@ -51,9 +51,6 @@ namespace LibationWinForms
MessageBoxLib.VerboseLoggingWarning_ShowIfTrue();
-#if !DEBUG
- checkForUpdate();
-#endif
// logging is init'd here
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
}
@@ -165,31 +162,6 @@ namespace LibationWinForms
// - long running. won't get a chance to finish in cli. don't move to app scaffolding
}
- private static void checkForUpdate()
- {
- AppScaffolding.UpgradeProperties upgradeProperties;
-
- try
- {
- upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease();
- if (upgradeProperties is null)
- return;
- }
- catch (Exception ex)
- {
- MessageBoxLib.ShowAdminAlert(null, "Error checking for update", "Error checking for update", ex);
- return;
- }
-
- if (upgradeProperties.ZipUrl is null)
- {
- MessageBox.Show(upgradeProperties.HtmlUrl, "New version available");
- return;
- }
-
- Updater.Run(upgradeProperties);
- }
-
private static void postLoggingGlobalExceptionHandling()
{
// this line is all that's needed for strict handling
diff --git a/Source/LibationWinForms/Updater.cs b/Source/LibationWinForms/Updater.cs
deleted file mode 100644
index 3bb6a926..00000000
--- a/Source/LibationWinForms/Updater.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Windows.Forms;
-using AppScaffolding;
-using AutoUpdaterDotNET;
-using LibationFileManager;
-using LibationWinForms.Dialogs;
-
-namespace LibationWinForms
-{
- public static class Updater
- {
- public static void Run(UpgradeProperties upgradeProperties)
- {
- string latestVersionOnServer = upgradeProperties.LatestRelease.ToString();
- string downloadZipUrl = upgradeProperties.ZipUrl;
- AutoUpdater.ParseUpdateInfoEvent +=
- args => args.UpdateInfo = new()
- {
- CurrentVersion = latestVersionOnServer,
- DownloadURL = downloadZipUrl,
- ChangelogURL = LibationScaffolding.RepositoryLatestUrl
- };
-
- void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args)
- {
- if (args is null || !args.IsUpdateAvailable)
- return;
-
- const string ignoreUpdate = "IgnoreUpdate";
- var config = Configuration.Instance;
-
- if (config.GetString(propertyName: ignoreUpdate) == args.CurrentVersion)
- return;
-
- var notificationResult = new UpgradeNotificationDialog(upgradeProperties).ShowDialog();
-
- if (notificationResult == DialogResult.Ignore)
- config.SetString(upgradeProperties.LatestRelease.ToString(), ignoreUpdate);
-
- if (notificationResult != DialogResult.Yes) return;
-
- try
- {
- Serilog.Log.Logger.Information("Start upgrade. {@DebugInfo}", new { CurrentlyInstalled = args.InstalledVersion, TargetVersion = args.CurrentVersion });
- AutoUpdater.DownloadUpdate(args);
- }
- catch (Exception ex)
- {
- MessageBoxLib.ShowAdminAlert(null, "Error downloading update", "Error downloading update", ex);
- }
- }
-
- AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent;
- AutoUpdater.Start(LibationScaffolding.RepositoryLatestUrl);
- }
- }
-}
diff --git a/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj b/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj
index 855b7034..a28cc197 100644
--- a/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj
+++ b/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj
@@ -11,13 +11,7 @@
-
- en;es
+ en
@@ -31,7 +25,7 @@
-
+
diff --git a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs
index bd6458b0..b9dd02e5 100644
--- a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs
+++ b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs
@@ -23,12 +23,12 @@ namespace LinuxConfigApp
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
- //only run the auto updater if the current app was installed from the
+ //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.
- public bool CanUpdate => Directory.Exists("/usr/lib/libation");
- public void InstallUpdate(string updateBundle)
+ public bool CanUpgrade => Directory.Exists("/usr/lib/libation");
+ public void InstallUpgrade(string upgradeBundle)
{
- RunAsRoot("apt", $"install '{updateBundle}'");
+ RunAsRoot("apt", $"install '{upgradeBundle}'");
}
public Process RunAsRoot(string exe, string args)
diff --git a/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj b/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj
index 865067f1..1d61b115 100644
--- a/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj
+++ b/Source/LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj
@@ -11,13 +11,7 @@
-
- en;es
+ en
@@ -31,7 +25,7 @@
-
+
diff --git a/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs b/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs
index a8993345..23f26a7c 100644
--- a/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs
+++ b/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs
@@ -13,15 +13,15 @@ namespace MacOSConfigApp
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
//I haven't figured out how to find the app bundle's directory from within
- //the running process, so don't update unless it's "installed" in /Applications
- public bool CanUpdate => Directory.Exists(AppPath);
+ //the running process, so don't upgrade unless it's "installed" in /Applications
+ public bool CanUpgrade => Directory.Exists(AppPath);
- public void InstallUpdate(string updateBundle)
+ public void InstallUpgrade(string upgradeBundle)
{
- Serilog.Log.Information($"Extracting update bundle to {AppPath}");
+ Serilog.Log.Information($"Extracting upgrade bundle to {AppPath}");
//tar wil overwrite existing without elevated privileges
- Process.Start("tar", $"-xf \"{updateBundle}\" -C \"/Applications\"").WaitForExit();
+ Process.Start("tar", $"-xf \"{upgradeBundle}\" -C \"/Applications\"").WaitForExit();
//For now, it seems like this step is unnecessary. We can overwrite and
//run Libation without needing to re-add the exception. This is insurance.
diff --git a/Source/LoadByOS/WindowsConfigApp/FolderIcon.cs b/Source/LoadByOS/WindowsConfigApp/FolderIcon.cs
new file mode 100644
index 00000000..e35eb57c
--- /dev/null
+++ b/Source/LoadByOS/WindowsConfigApp/FolderIcon.cs
@@ -0,0 +1,106 @@
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Png;
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace WindowsConfigApp
+{
+ internal static partial class FolderIcon
+ {
+ // https://stackoverflow.com/a/21389253
+ public static byte[] ToIcon(this Image img)
+ {
+ using var ms = new MemoryStream();
+ using var bw = new BinaryWriter(ms);
+ // Header
+ bw.Write((short)0); // 0-1 : reserved
+ bw.Write((short)1); // 2-3 : 1=ico, 2=cur
+ bw.Write((short)1); // 4-5 : number of images
+ // Image directory
+ var w = img.Width;
+ if (w >= 256) w = 0;
+ bw.Write((byte)w); // 0 : width of image
+ var h = img.Height;
+ if (h >= 256) h = 0;
+ bw.Write((byte)h); // 1 : height of image
+ bw.Write((byte)0); // 2 : number of colors in palette
+ bw.Write((byte)0); // 3 : reserved
+ bw.Write((short)0); // 4 : number of color planes
+ bw.Write((short)0); // 6 : bits per pixel
+ var sizeHere = ms.Position;
+ bw.Write((int)0); // 8 : image size
+ var start = (int)ms.Position + 4;
+ bw.Write(start); // 12: offset of image data
+ // Image data
+ img.Save(ms, new PngEncoder());
+ var imageSize = (int)ms.Position - start;
+ ms.Seek(sizeHere, SeekOrigin.Begin);
+ bw.Write(imageSize);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ // And load it
+ return ms.ToArray();
+ }
+
+ public static void DeleteIcon(this DirectoryInfo directoryInfo) => DeleteIcon(directoryInfo.FullName);
+ public static void DeleteIcon(string dir)
+ {
+ string[] array = new string[3] { "desktop.ini", "Icon.ico", ".hidden" };
+ foreach (string path in array)
+ {
+ string text = Path.Combine(dir, path);
+ if (File.Exists(text))
+ {
+ File.SetAttributes(text, File.GetAttributes(text) | FileAttributes.Normal);
+ new FileInfo(text).IsReadOnly = false;
+ File.Delete(text);
+ }
+ }
+
+ refresh();
+ }
+
+ // https://github.com/dimuththarindu/FIC-Folder-Icon-Changer/blob/master/project/FIC/Classes/IconCustomizer.cs
+
+ public static void SetIcon(this DirectoryInfo directoryInfo, string icoPath, string folderType)
+ => SetIcon(directoryInfo.FullName, icoPath, folderType);
+
+ public static void SetIcon(string dir, string icoPath, string folderType)
+ {
+ var desktop_ini = Path.Combine(dir, "desktop.ini");
+ var Icon_ico = Path.Combine(dir, "Icon.ico");
+ var hidden = Path.Combine(dir, ".hidden");
+
+ //deleting existing files
+ DeleteIcon(dir);
+
+ //copying Icon file //overwriting
+ File.Copy(icoPath, Icon_ico, true);
+
+ //writing configuration file
+ string[] desktopLines = { "[.ShellClassInfo]", "IconResource=Icon.ico,0", "[ViewState]", "Mode=", "Vid=", $"FolderType={folderType}" };
+ File.WriteAllLines(desktop_ini, desktopLines);
+
+ //configure file 2
+ string[] hiddenLines = { "desktop.ini", "Icon.ico" };
+ File.WriteAllLines(hidden, hiddenLines);
+
+ //making system files
+ File.SetAttributes(desktop_ini, File.GetAttributes(desktop_ini) | FileAttributes.Hidden | FileAttributes.System | FileAttributes.ReadOnly);
+ File.SetAttributes(Icon_ico, File.GetAttributes(Icon_ico) | FileAttributes.Hidden | FileAttributes.System | FileAttributes.ReadOnly);
+ File.SetAttributes(hidden, File.GetAttributes(hidden) | FileAttributes.Hidden | FileAttributes.System | FileAttributes.ReadOnly);
+
+ // this strangely completes the process. also hides these 3 hidden system files, even if "show hidden items" is checked
+ File.SetAttributes(dir, File.GetAttributes(dir) | FileAttributes.ReadOnly);
+
+ refresh();
+ }
+
+ private static void refresh() => SHChangeNotify(0x08000000, 0x0000, 0, 0); //SHCNE_ASSOCCHANGED SHCNF_IDLIST
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ private static extern void SHChangeNotify(int wEventId, int uFlags, nint dwItem1, nint dwItem2);
+ }
+}
diff --git a/Source/LoadByOS/WindowsConfigApp/WinInterop.cs b/Source/LoadByOS/WindowsConfigApp/WinInterop.cs
index 42cded34..5aef4bea 100644
--- a/Source/LoadByOS/WindowsConfigApp/WinInterop.cs
+++ b/Source/LoadByOS/WindowsConfigApp/WinInterop.cs
@@ -1,12 +1,9 @@
-using System;
-using System.Collections.Generic;
+using SixLabors.ImageSharp;
using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Dinah.Core.WindowsDesktop;
-using Dinah.Core.WindowsDesktop.Drawing;
using LibationFileManager;
+using System.IO;
+using System;
+using Dinah.Core;
namespace WindowsConfigApp
{
@@ -21,11 +18,11 @@ namespace WindowsConfigApp
try
{
- var icon = ImageReader.ToIcon(image);
+ var icon = Image.Load(File.ReadAllBytes(image)).ToIcon();
iconPath = Path.Combine(directory, $"{Guid.NewGuid()}.ico");
- icon.Save(iconPath);
+ File.WriteAllBytes(iconPath, icon);
- new DirectoryInfo(directory).SetIcon(iconPath, Directories.FolderTypes.Music);
+ new DirectoryInfo(directory)?.SetIcon(iconPath, "Music");
}
finally
{
@@ -36,8 +33,9 @@ namespace WindowsConfigApp
public void DeleteFolderIcon(string directory)
=> new DirectoryInfo(directory)?.DeleteIcon();
- public bool CanUpdate => true;
- public void InstallUpdate(string updateBundle)
+
+ public bool CanUpgrade => true;
+ public void InstallUpgrade(string upgradeBundle)
{
var thisExe = Environment.ProcessPath;
var thisDir = Path.GetDirectoryName(thisExe);
@@ -45,7 +43,10 @@ namespace WindowsConfigApp
File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true);
- RunAsRoot(zipExtractor, $"--input \"{updateBundle}\" --output \"{thisDir}\" --executable \"{thisExe}\"");
+ RunAsRoot(zipExtractor,
+ $"--input {upgradeBundle.SurroundWithQuotes()} " +
+ $"--output {thisDir.SurroundWithQuotes()} " +
+ $"--executable {thisExe.SurroundWithQuotes()}");
}
public Process RunAsRoot(string exe, string args)
diff --git a/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj b/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj
index 0dba0cbf..2057f3a8 100644
--- a/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj
+++ b/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj
@@ -2,24 +2,15 @@
WinExe
- net7.0-windows
+ net7.0
true
- true
- enable
true
- win-x64
false
false
-
- en;es
+ en
@@ -33,11 +24,7 @@
-
-
-
-
-
+