diff --git a/Documentation/InstallOnMac.md b/Documentation/InstallOnMac.md
index 6c958533..e10b3728 100644
--- a/Documentation/InstallOnMac.md
+++ b/Documentation/InstallOnMac.md
@@ -23,6 +23,17 @@ This walkthrough should get you up and running with Libation on your Mac.
```
- 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
Libation comes with a recovery app called Hangover. You can start it by running this command:
diff --git a/Source/AaxDecrypter/AaxDecrypter.csproj b/Source/AaxDecrypter/AaxDecrypter.csproj
index c065bf6d..51f76329 100644
--- a/Source/AaxDecrypter/AaxDecrypter.csproj
+++ b/Source/AaxDecrypter/AaxDecrypter.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs
index 5179aec2..46287d6d 100644
--- a/Source/ApplicationServices/LibraryCommands.cs
+++ b/Source/ApplicationServices/LibraryCommands.cs
@@ -119,9 +119,14 @@ namespace ApplicationServices
logTime($"pre {nameof(scanAccountsAsync)} all");
var libraryOptions = new LibraryOptions
- {
- ResponseGroups = LibraryOptions.ResponseGroupOptions.ALL_OPTIONS,
- ImageSizes = LibraryOptions.ImageSizeOptions._500 | LibraryOptions.ImageSizeOptions._1215
+ {
+ ResponseGroups
+ = LibraryOptions.ResponseGroupOptions.Rating | LibraryOptions.ResponseGroupOptions.Media
+ | LibraryOptions.ResponseGroupOptions.Relationships | LibraryOptions.ResponseGroupOptions.ProductDesc
+ | LibraryOptions.ResponseGroupOptions.Contributors | LibraryOptions.ResponseGroupOptions.ProvidedReview
+ | LibraryOptions.ResponseGroupOptions.ProductPlans | LibraryOptions.ResponseGroupOptions.Series
+ | LibraryOptions.ResponseGroupOptions.CategoryLadders | LibraryOptions.ResponseGroupOptions.ProductExtendedAttrs,
+ ImageSizes = LibraryOptions.ImageSizeOptions._500 | LibraryOptions.ImageSizeOptions._1215
};
var importItems = await scanAccountsAsync(apiExtendedfunc, accounts, libraryOptions);
logTime($"post {nameof(scanAccountsAsync)} all");
diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs
index be96e3f0..201e2c8b 100644
--- a/Source/AudibleUtilities/ApiExtended.cs
+++ b/Source/AudibleUtilities/ApiExtended.cs
@@ -207,7 +207,11 @@ namespace AudibleUtilities
try
{
var sw = Stopwatch.StartNew();
- var items = await Api.GetCatalogProductsAsync(asins, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS);
+ var items = await Api.GetCatalogProductsAsync(asins, CatalogOptions.ResponseGroupOptions.Rating | CatalogOptions.ResponseGroupOptions.Media
+ | CatalogOptions.ResponseGroupOptions.Relationships | CatalogOptions.ResponseGroupOptions.ProductDesc
+ | CatalogOptions.ResponseGroupOptions.Contributors | CatalogOptions.ResponseGroupOptions.ProvidedReview
+ | CatalogOptions.ResponseGroupOptions.ProductPlans | CatalogOptions.ResponseGroupOptions.Series
+ | CatalogOptions.ResponseGroupOptions.CategoryLadders | CatalogOptions.ResponseGroupOptions.ProductExtendedAttrs);
sw.Stop();
Serilog.Log.Logger.Debug($"Batch {batchNum} End: Retrieved {items.Count} items in {sw.ElapsedMilliseconds} ms");
diff --git a/Source/FileLiberator/ConvertToMp3.cs b/Source/FileLiberator/ConvertToMp3.cs
index a03fb34e..89976d16 100644
--- a/Source/FileLiberator/ConvertToMp3.cs
+++ b/Source/FileLiberator/ConvertToMp3.cs
@@ -60,6 +60,11 @@ namespace FileLiberator
config.LameMatchSourceBR,
chapters);
+ if (m4bBook.AppleTags.Tracks is (int trackNum, int trackCount))
+ {
+ lameConfig.ID3.Track = trackCount > 0 ? $"{trackNum}/{trackCount}" : trackNum.ToString();
+ }
+
using var mp3File = File.Open(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite);
try
{
diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj
index 7e213bb4..31c93b43 100644
--- a/Source/HangoverAvalonia/HangoverAvalonia.csproj
+++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj
@@ -67,13 +67,13 @@
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml
index b82b437a..e611e50d 100644
--- a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml
@@ -27,6 +27,6 @@
Margin="5"
Padding="30,3,30,3"
Content="Save"
- Command="{Binding SaveButtonAsync}" />
+ Click="Save_Click" />
diff --git a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs
index 05a4ef01..a20a588a 100644
--- a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs
@@ -1,11 +1,9 @@
-using Avalonia.Controls;
using LibationFileManager;
using System.Collections.Generic;
-using System.Threading.Tasks;
namespace LibationAvalonia.Dialogs
{
- public partial class LibationFilesDialog : Window
+ public partial class LibationFilesDialog : DialogWindow
{
private class DirSelectOptions
{
@@ -18,28 +16,26 @@ namespace LibationAvalonia.Dialogs
public string Directory { get; set; } = Configuration.GetKnownDirectoryPath(Configuration.KnownDirectories.UserProfile);
}
- private DirSelectOptions dirSelectOptions;
+
+ private readonly DirSelectOptions dirSelectOptions;
public string SelectedDirectory => dirSelectOptions.Directory;
- public DialogResult DialogResult { get; private set; }
- public LibationFilesDialog()
+
+ public LibationFilesDialog() : base(saveAndRestorePosition: false)
{
InitializeComponent();
DataContext = dirSelectOptions = new();
}
- public async Task SaveButtonAsync()
+ public async void Save_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
- var libationDir = dirSelectOptions.Directory;
-
- if (!System.IO.Directory.Exists(libationDir))
+ if (!System.IO.Directory.Exists(SelectedDirectory))
{
- await MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + libationDir, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error, saveAndRestorePosition: false);
+ await MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + SelectedDirectory, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error, saveAndRestorePosition: false);
return;
}
- DialogResult = DialogResult.OK;
- Close(DialogResult);
+ await SaveAndCloseAsync();
}
}
}
diff --git a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml
index 47d7cc82..5ecbb30f 100644
--- a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml
@@ -2,8 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="750"
- MinWidth="900" MinHeight="750"
+ mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="200"
+ MinWidth="900" MinHeight="200"
Width="900" Height="750"
x:Class="LibationAvalonia.Dialogs.SettingsDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
@@ -46,39 +46,41 @@
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
+
-
+
-
-
-
+
+
+
diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj
index e06adfa6..6723f7e6 100644
--- a/Source/LibationAvalonia/LibationAvalonia.csproj
+++ b/Source/LibationAvalonia/LibationAvalonia.csproj
@@ -70,13 +70,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Source/LibationFileManager/AudibleFileStorage.cs b/Source/LibationFileManager/AudibleFileStorage.cs
index 8ca7a356..4e91d850 100644
--- a/Source/LibationFileManager/AudibleFileStorage.cs
+++ b/Source/LibationFileManager/AudibleFileStorage.cs
@@ -8,20 +8,21 @@ using Dinah.Core;
using System.Threading.Tasks;
using System.Threading;
using FileManager;
+using AaxDecrypter;
#nullable enable
namespace LibationFileManager
{
- public abstract class AudibleFileStorage
- {
- protected abstract LongPath? GetFilePathCustom(string productId);
- protected abstract List GetFilePathsCustom(string productId);
+ public abstract class AudibleFileStorage
+ {
+ protected abstract LongPath? GetFilePathCustom(string productId);
+ protected abstract List GetFilePathsCustom(string productId);
- #region static
- public static LongPath DownloadsInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DownloadsInProgress")).FullName;
- public static LongPath DecryptInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DecryptInProgress")).FullName;
+ #region static
+ public static LongPath DownloadsInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DownloadsInProgress")).FullName;
+ public static LongPath DecryptInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DecryptInProgress")).FullName;
- static AudibleFileStorage()
+ static AudibleFileStorage()
{
//Clean up any partially-decrypted files from previous Libation instances.
//Do no clean DownloadsInProgressDirectory because those files are resumable
@@ -31,103 +32,103 @@ namespace LibationFileManager
private static AaxcFileStorage AAXC { get; } = new AaxcFileStorage();
- public static bool AaxcExists(string productId) => AAXC.Exists(productId);
+ public static bool AaxcExists(string productId) => AAXC.Exists(productId);
- public static AudioFileStorage Audio { get; } = new AudioFileStorage();
+ public static AudioFileStorage Audio { get; } = new AudioFileStorage();
- public static LongPath BooksDirectory
- {
- get
- {
- if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
- Configuration.Instance.Books = Path.Combine(Configuration.UserProfile, "Books");
- return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
- }
- }
- #endregion
+ public static LongPath BooksDirectory
+ {
+ get
+ {
+ if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
+ Configuration.Instance.Books = Path.Combine(Configuration.UserProfile, "Books");
+ return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
+ }
+ }
+ #endregion
- #region instance
- private FileType FileType { get; }
- private string regexTemplate { get; }
+ #region instance
+ private FileType FileType { get; }
+ private string regexTemplate { get; }
- protected AudibleFileStorage(FileType fileType)
- {
- FileType = fileType;
+ protected AudibleFileStorage(FileType fileType)
+ {
+ FileType = fileType;
- var extAggr = FileTypes.GetExtensions(FileType).Aggregate((a, b) => $"{a}|{b}");
- regexTemplate = $@"{{0}}.*?\.({extAggr})$";
- }
+ var extAggr = FileTypes.GetExtensions(FileType).Aggregate((a, b) => $"{a}|{b}");
+ regexTemplate = $@"{{0}}.*?\.({extAggr})$";
+ }
- protected LongPath? GetFilePath(string productId)
- {
- // primary lookup
- var cachedFile = FilePathCache.GetFirstPath(productId, FileType);
- if (cachedFile is not null && File.Exists(cachedFile))
- return cachedFile;
+ protected LongPath? GetFilePath(string productId)
+ {
+ // primary lookup
+ var cachedFile = FilePathCache.GetFirstPath(productId, FileType);
+ if (cachedFile is not null && File.Exists(cachedFile))
+ return cachedFile;
- // secondary lookup attempt
- var firstOrNull = GetFilePathCustom(productId);
- if (firstOrNull is not null)
- FilePathCache.Insert(productId, firstOrNull);
+ // secondary lookup attempt
+ var firstOrNull = GetFilePathCustom(productId);
+ if (firstOrNull is not null)
+ FilePathCache.Insert(productId, firstOrNull);
- return firstOrNull;
- }
+ return firstOrNull;
+ }
- public List GetPaths(string productId)
- => GetFilePathsCustom(productId);
+ public List GetPaths(string productId)
+ => GetFilePathsCustom(productId);
- protected Regex GetBookSearchRegex(string productId)
- {
- var pattern = string.Format(regexTemplate, productId);
- return new Regex(pattern, RegexOptions.IgnoreCase);
- }
- #endregion
- }
+ protected Regex GetBookSearchRegex(string productId)
+ {
+ var pattern = string.Format(regexTemplate, productId);
+ return new Regex(pattern, RegexOptions.IgnoreCase);
+ }
+ #endregion
+ }
- internal class AaxcFileStorage : AudibleFileStorage
- {
- internal AaxcFileStorage() : base(FileType.AAXC) { }
+ internal class AaxcFileStorage : AudibleFileStorage
+ {
+ internal AaxcFileStorage() : base(FileType.AAXC) { }
- protected override LongPath? GetFilePathCustom(string productId)
- => GetFilePathsCustom(productId).FirstOrDefault();
+ protected override LongPath? GetFilePathCustom(string productId)
+ => GetFilePathsCustom(productId).FirstOrDefault();
- protected override List GetFilePathsCustom(string productId)
- {
- var regex = GetBookSearchRegex(productId);
- return FileUtility
- .SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
- .Where(s => regex.IsMatch(s)).ToList();
- }
+ protected override List GetFilePathsCustom(string productId)
+ {
+ var regex = GetBookSearchRegex(productId);
+ return FileUtility
+ .SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
+ .Where(s => regex.IsMatch(s)).ToList();
+ }
- public bool Exists(string productId) => GetFilePath(productId) is not null;
- }
+ public bool Exists(string productId) => GetFilePath(productId) is not null;
+ }
- public class AudioFileStorage : AudibleFileStorage
- {
- internal AudioFileStorage() : base(FileType.Audio)
- => BookDirectoryFiles ??= newBookDirectoryFiles();
+ public class AudioFileStorage : AudibleFileStorage
+ {
+ internal AudioFileStorage() : base(FileType.Audio)
+ => BookDirectoryFiles ??= newBookDirectoryFiles();
- private static BackgroundFileSystem? BookDirectoryFiles { get; set; }
- private static object bookDirectoryFilesLocker { get; } = new();
+ private static BackgroundFileSystem? BookDirectoryFiles { get; set; }
+ private static object bookDirectoryFilesLocker { get; } = new();
private static EnumerationOptions enumerationOptions { get; } = new()
{
RecurseSubdirectories = true,
IgnoreInaccessible = true,
- MatchCasing = MatchCasing.CaseInsensitive
+ AttributesToSkip = FileAttributes.Hidden,
};
protected override LongPath? GetFilePathCustom(string productId)
- => GetFilePathsCustom(productId).FirstOrDefault();
+ => GetFilePathsCustom(productId).FirstOrDefault();
- private static BackgroundFileSystem newBookDirectoryFiles()
- => new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
+ private static BackgroundFileSystem newBookDirectoryFiles()
+ => new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
protected override List GetFilePathsCustom(string productId)
- {
- // If user changed the BooksDirectory: reinitialize
- lock (bookDirectoryFilesLocker)
- if (BooksDirectory != BookDirectoryFiles?.RootDirectory)
- BookDirectoryFiles = newBookDirectoryFiles();
+ {
+ // If user changed the BooksDirectory: reinitialize
+ lock (bookDirectoryFilesLocker)
+ if (BooksDirectory != BookDirectoryFiles?.RootDirectory)
+ BookDirectoryFiles = newBookDirectoryFiles();
var regex = GetBookSearchRegex(productId);
@@ -135,44 +136,60 @@ namespace LibationFileManager
//using both the file system and the file path cache
return
FilePathCache
- .GetFiles(productId)
- .Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
- .Select(c => c.path)
- .Union(BookDirectoryFiles.FindFiles(regex))
- .ToList();
- }
+ .GetFiles(productId)
+ .Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
+ .Select(c => c.path)
+ .Union(BookDirectoryFiles.FindFiles(regex))
+ .ToList();
+ }
- public void Refresh()
- {
- if (BookDirectoryFiles is null)
- lock (bookDirectoryFilesLocker)
- BookDirectoryFiles = newBookDirectoryFiles();
- else
- BookDirectoryFiles?.RefreshFiles();
- }
+ public void Refresh()
+ {
+ if (BookDirectoryFiles is null)
+ lock (bookDirectoryFilesLocker)
+ BookDirectoryFiles = newBookDirectoryFiles();
+ else
+ BookDirectoryFiles?.RefreshFiles();
+ }
- public LongPath? GetPath(string productId) => GetFilePath(productId);
+ public LongPath? GetPath(string productId) => GetFilePath(productId);
public static async IAsyncEnumerable FindAudiobooksAsync(LongPath searchDirectory, [EnumeratorCancellation] CancellationToken cancellationToken)
{
ArgumentValidator.EnsureNotNull(searchDirectory, nameof(searchDirectory));
- foreach (LongPath path in Directory.EnumerateFiles(searchDirectory, "*.M4B", enumerationOptions))
+ foreach (LongPath path in Directory.EnumerateFiles(searchDirectory, "*.*", enumerationOptions))
{
if (cancellationToken.IsCancellationRequested)
yield break;
+ if (getFormatByExtension(path) is not OutputFormat format)
+ continue;
+
FilePathCache.CacheEntry? audioFile = default;
try
{
- using var fileStream = File.OpenRead(path);
+ if (format is OutputFormat.M4b)
+ {
+ var tags = await Task.Run(() => AAXClean.AppleTags.FromFile(path));
- var mp4File = await Task.Run(() => new AAXClean.Mp4File(fileStream), cancellationToken);
+ if (tags?.Asin is not null)
+ audioFile = new FilePathCache.CacheEntry(tags.Asin, FileType.Audio, path);
+ }
+ else
+ {
+ using var fileStream = File.OpenRead(path);
+ var id3 = await Task.Run(() => NAudio.Lame.ID3.Id3Tag.Create(fileStream));
- if (mp4File?.AppleTags?.Asin is not null)
- audioFile = new FilePathCache.CacheEntry(mp4File.AppleTags.Asin, FileType.Audio, path);
+ var asin = id3?.Children
+ .OfType()
+ .FirstOrDefault(f => f.FieldName == "AUDIBLE_ASIN")
+ ?.FieldValue;
+ if (!string.IsNullOrWhiteSpace(asin))
+ audioFile = new FilePathCache.CacheEntry(asin, FileType.Audio, path);
+ }
}
catch (Exception ex)
{
@@ -186,6 +203,15 @@ namespace LibationFileManager
if (audioFile is not null)
yield return audioFile;
}
+
+ static OutputFormat? getFormatByExtension(string path)
+ {
+ var ext = Path.GetExtension(path).ToLower();
+
+ return ext == ".mp3" ? OutputFormat.Mp3
+ : ext == ".m4b" ? OutputFormat.M4b
+ : null;
+ }
}
}
}
diff --git a/Source/LibationFileManager/Configuration.LibationFiles.cs b/Source/LibationFileManager/Configuration.LibationFiles.cs
index 00246d99..c7118fcf 100644
--- a/Source/LibationFileManager/Configuration.LibationFiles.cs
+++ b/Source/LibationFileManager/Configuration.LibationFiles.cs
@@ -6,6 +6,7 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Serilog;
using Dinah.Core.Logging;
+using System.Diagnostics;
#nullable enable
namespace LibationFileManager
@@ -75,17 +76,19 @@ namespace LibationFileManager
const string appsettings_filename = "appsettings.json";
//Possible appsettings.json locations, in order of preference.
- string[] possibleAppsettingsFiles = new[]
+ string[] possibleAppsettingsDirectories = new[]
{
- Path.Combine(ProcessDirectory, appsettings_filename),
- Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation", appsettings_filename),
- Path.Combine(UserProfile, appsettings_filename),
- Path.Combine(Path.GetTempPath(), "Libation", appsettings_filename)
+ ProcessDirectory,
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation"),
+ UserProfile,
+ Path.Combine(Path.GetTempPath(), "Libation")
};
//Try to find and validate appsettings.json in each folder
- foreach (var appsettingsFile in possibleAppsettingsFiles)
+ foreach (var dir in possibleAppsettingsDirectories)
{
+ var appsettingsFile = Path.Combine(dir, appsettings_filename);
+
if (File.Exists(appsettingsFile))
{
try
@@ -104,10 +107,13 @@ namespace LibationFileManager
//Valid appsettings.json not found. Try to create it in each folder.
var endingContents = new JObject { { LIBATION_FILES_KEY, UserProfile } }.ToString(Formatting.Indented);
- foreach (var appsettingsFile in possibleAppsettingsFiles)
+ foreach (var dir in possibleAppsettingsDirectories)
{
+ var appsettingsFile = Path.Combine(dir, appsettings_filename);
+
try
{
+ Directory.CreateDirectory(dir);
File.WriteAllText(appsettingsFile, endingContents);
return appsettingsFile;
}
@@ -121,16 +127,56 @@ namespace LibationFileManager
}
private static string getLibationFilesSettingFromJson()
- {
- // do not check whether directory exists. special/meta directory (eg: AppDir) is valid
- // verify from live file. no try/catch. want failures to be visible
- var jObjFinal = JObject.Parse(File.ReadAllText(AppsettingsJsonFile));
+ {
+ // do not check whether directory exists. special/meta directory (eg: AppDir) is valid
+ // verify from live file. no try/catch. want failures to be visible
+ var jObjFinal = JObject.Parse(File.ReadAllText(AppsettingsJsonFile));
if (jObjFinal[LIBATION_FILES_KEY]?.Value() is not string valueFinal)
throw new InvalidDataException($"{LIBATION_FILES_KEY} not found in {AppsettingsJsonFile}");
- return valueFinal;
- }
+ if (IsWindows)
+ {
+ valueFinal = Environment.ExpandEnvironmentVariables(valueFinal);
+ }
+ else
+ {
+ //If the shell command fails and returns null, proceed with the verbatim
+ //LIBATION_FILES_KEY path and hope for the best. If Libation can't find
+ //anything at this path it will set LIBATION_FILES_KEY to UserProfile
+ valueFinal = runShellCommand("echo " + valueFinal) ?? valueFinal;
+ }
+
+ return valueFinal;
+
+ static string? runShellCommand(string command)
+ {
+ var psi = new ProcessStartInfo
+ {
+ FileName = "/bin/sh",
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ ArgumentList =
+ {
+ "-c",
+ command
+ }
+ };
+
+ try
+ {
+ var proc = Process.Start(psi);
+ proc?.WaitForExit();
+ return proc?.StandardOutput?.ReadToEnd()?.Trim();
+ }
+ catch (Exception e)
+ {
+ Serilog.Log.Error(e, "Failed to run shell command. {Arguments}", psi.ArgumentList);
+ return null;
+ }
+ }
+ }
public static void SetLibationFiles(string directory)
{
diff --git a/Source/LibationUiBase/GridView/GridContextMenu.cs b/Source/LibationUiBase/GridView/GridContextMenu.cs
index 15b0f099..9e9c78ae 100644
--- a/Source/LibationUiBase/GridView/GridContextMenu.cs
+++ b/Source/LibationUiBase/GridView/GridContextMenu.cs
@@ -95,20 +95,4 @@ public class GridContextMenu
return TemplateEditor.CreateFilenameEditor(Configuration.Instance.Books, existingTemplate, folderDto, fileDto);
}
-
-
-}
-class Command : ICommand
-{
- public event EventHandler CanExecuteChanged;
-
- public bool CanExecute(object parameter)
- {
- throw new NotImplementedException();
- }
-
- public void Execute(object parameter)
- {
- throw new NotImplementedException();
- }
}
\ No newline at end of file
diff --git a/Source/LibationUiBase/LibationUiBase.csproj b/Source/LibationUiBase/LibationUiBase.csproj
index b2743cb7..8c2a055d 100644
--- a/Source/LibationUiBase/LibationUiBase.csproj
+++ b/Source/LibationUiBase/LibationUiBase.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs
index bed7a552..f6220294 100644
--- a/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs
+++ b/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs
@@ -229,7 +229,7 @@
badBookGb.Controls.Add(badBookAskRb);
badBookGb.Location = new System.Drawing.Point(7, 6);
badBookGb.Name = "badBookGb";
- badBookGb.Size = new System.Drawing.Size(836, 76);
+ badBookGb.Size = new System.Drawing.Size(841, 76);
badBookGb.TabIndex = 13;
badBookGb.TabStop = false;
badBookGb.Text = "[bad book desc]";
@@ -397,6 +397,7 @@
//
// tab1ImportantSettings
//
+ tab1ImportantSettings.AutoScroll = true;
tab1ImportantSettings.Controls.Add(groupBox1);
tab1ImportantSettings.Controls.Add(booksGb);
tab1ImportantSettings.Controls.Add(logsBtn);
@@ -412,6 +413,7 @@
//
// groupBox1
//
+ groupBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
groupBox1.Controls.Add(applyDisplaySettingsBtn);
groupBox1.Controls.Add(gridScaleFactorLbl);
groupBox1.Controls.Add(gridScaleFactorTbar);
@@ -426,6 +428,7 @@
//
// applyDisplaySettingsBtn
//
+ applyDisplaySettingsBtn.Anchor = System.Windows.Forms.AnchorStyles.Right;
applyDisplaySettingsBtn.Location = new System.Drawing.Point(689, 26);
applyDisplaySettingsBtn.Name = "applyDisplaySettingsBtn";
applyDisplaySettingsBtn.Size = new System.Drawing.Size(148, 34);
@@ -554,6 +557,7 @@
//
// tab2ImportLibrary
//
+ tab2ImportLibrary.AutoScroll = true;
tab2ImportLibrary.Controls.Add(autoDownloadEpisodesCb);
tab2ImportLibrary.Controls.Add(autoScanCb);
tab2ImportLibrary.Controls.Add(showImportedStatsCb);
@@ -599,6 +603,7 @@
//
// tab3DownloadDecrypt
//
+ tab3DownloadDecrypt.AutoScroll = true;
tab3DownloadDecrypt.Controls.Add(saveMetadataToFileCbox);
tab3DownloadDecrypt.Controls.Add(useCoverAsFolderIconCb);
tab3DownloadDecrypt.Controls.Add(inProgressFilesGb);
@@ -764,6 +769,7 @@
//
// tab4AudioFileOptions
//
+ tab4AudioFileOptions.AutoScroll = true;
tab4AudioFileOptions.Controls.Add(fileDownloadQualityCb);
tab4AudioFileOptions.Controls.Add(fileDownloadQualityLbl);
tab4AudioFileOptions.Controls.Add(combineNestedChapterTitlesCbox);
@@ -845,7 +851,7 @@
audiobookFixupsGb.Controls.Add(stripAudibleBrandingCbox);
audiobookFixupsGb.Location = new System.Drawing.Point(6, 200);
audiobookFixupsGb.Name = "audiobookFixupsGb";
- audiobookFixupsGb.Size = new System.Drawing.Size(403, 182);
+ audiobookFixupsGb.Size = new System.Drawing.Size(385, 182);
audiobookFixupsGb.TabIndex = 19;
audiobookFixupsGb.TabStop = false;
audiobookFixupsGb.Text = "Audiobook Fix-ups";
@@ -872,6 +878,7 @@
//
// chapterTitleTemplateGb
//
+ chapterTitleTemplateGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateBtn);
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateTb);
chapterTitleTemplateGb.Location = new System.Drawing.Point(3, 388);
@@ -903,6 +910,7 @@
//
// lameOptionsGb
//
+ lameOptionsGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lameOptionsGb.Controls.Add(label20);
lameOptionsGb.Controls.Add(label21);
lameOptionsGb.Controls.Add(encoderQualityCb);
@@ -912,9 +920,9 @@
lameOptionsGb.Controls.Add(label1);
lameOptionsGb.Controls.Add(lameQualityGb);
lameOptionsGb.Controls.Add(groupBox2);
- lameOptionsGb.Location = new System.Drawing.Point(415, 6);
+ lameOptionsGb.Location = new System.Drawing.Point(397, 6);
lameOptionsGb.Name = "lameOptionsGb";
- lameOptionsGb.Size = new System.Drawing.Size(433, 376);
+ lameOptionsGb.Size = new System.Drawing.Size(450, 376);
lameOptionsGb.TabIndex = 14;
lameOptionsGb.TabStop = false;
lameOptionsGb.Text = "Mp3 Encoding Options";
@@ -930,6 +938,7 @@
//
// label21
//
+ label21.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label21.AutoSize = true;
label21.Location = new System.Drawing.Point(239, 89);
label21.Name = "label21";
@@ -939,33 +948,37 @@
//
// encoderQualityCb
//
+ encoderQualityCb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
encoderQualityCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
encoderQualityCb.FormattingEnabled = true;
encoderQualityCb.Location = new System.Drawing.Point(337, 86);
encoderQualityCb.Name = "encoderQualityCb";
- encoderQualityCb.Size = new System.Drawing.Size(90, 23);
+ encoderQualityCb.Size = new System.Drawing.Size(107, 23);
encoderQualityCb.TabIndex = 2;
//
// maxSampleRateCb
//
+ maxSampleRateCb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
maxSampleRateCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
maxSampleRateCb.FormattingEnabled = true;
maxSampleRateCb.Location = new System.Drawing.Point(119, 86);
maxSampleRateCb.Name = "maxSampleRateCb";
- maxSampleRateCb.Size = new System.Drawing.Size(101, 23);
+ maxSampleRateCb.Size = new System.Drawing.Size(76, 23);
maxSampleRateCb.TabIndex = 2;
//
// lameDownsampleMonoCbox
//
- lameDownsampleMonoCbox.Location = new System.Drawing.Point(237, 30);
+ lameDownsampleMonoCbox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ lameDownsampleMonoCbox.Location = new System.Drawing.Point(247, 29);
lameDownsampleMonoCbox.Name = "lameDownsampleMonoCbox";
- lameDownsampleMonoCbox.Size = new System.Drawing.Size(184, 34);
+ lameDownsampleMonoCbox.Size = new System.Drawing.Size(197, 34);
lameDownsampleMonoCbox.TabIndex = 1;
lameDownsampleMonoCbox.Text = "Downsample stereo to mono?\r\n(Recommended)\r\n";
lameDownsampleMonoCbox.UseVisualStyleBackColor = true;
//
// lameBitrateGb
//
+ lameBitrateGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lameBitrateGb.Controls.Add(LameMatchSourceBRCbox);
lameBitrateGb.Controls.Add(lameConstantBitrateCbox);
lameBitrateGb.Controls.Add(label7);
@@ -977,15 +990,16 @@
lameBitrateGb.Controls.Add(lameBitrateTb);
lameBitrateGb.Location = new System.Drawing.Point(6, 116);
lameBitrateGb.Name = "lameBitrateGb";
- lameBitrateGb.Size = new System.Drawing.Size(421, 113);
+ lameBitrateGb.Size = new System.Drawing.Size(438, 113);
lameBitrateGb.TabIndex = 0;
lameBitrateGb.TabStop = false;
lameBitrateGb.Text = "Bitrate";
//
// LameMatchSourceBRCbox
//
+ LameMatchSourceBRCbox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
LameMatchSourceBRCbox.AutoSize = true;
- LameMatchSourceBRCbox.Location = new System.Drawing.Point(275, 76);
+ LameMatchSourceBRCbox.Location = new System.Drawing.Point(254, 76);
LameMatchSourceBRCbox.Name = "LameMatchSourceBRCbox";
LameMatchSourceBRCbox.Size = new System.Drawing.Size(140, 19);
LameMatchSourceBRCbox.TabIndex = 3;
@@ -1005,6 +1019,7 @@
//
// label7
//
+ label7.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label7.AutoSize = true;
label7.BackColor = System.Drawing.SystemColors.ControlLightLight;
label7.Location = new System.Drawing.Point(390, 52);
@@ -1015,6 +1030,7 @@
//
// label6
//
+ label6.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label6.AutoSize = true;
label6.BackColor = System.Drawing.SystemColors.ControlLightLight;
label6.Location = new System.Drawing.Point(309, 52);
@@ -1025,6 +1041,7 @@
//
// label5
//
+ label5.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label5.AutoSize = true;
label5.BackColor = System.Drawing.SystemColors.ControlLightLight;
label5.Location = new System.Drawing.Point(228, 52);
@@ -1035,6 +1052,7 @@
//
// label4
//
+ label4.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label4.AutoSize = true;
label4.BackColor = System.Drawing.SystemColors.ControlLightLight;
label4.Location = new System.Drawing.Point(147, 52);
@@ -1045,6 +1063,7 @@
//
// label11
//
+ label11.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label11.AutoSize = true;
label11.BackColor = System.Drawing.SystemColors.ControlLightLight;
label11.Location = new System.Drawing.Point(10, 52);
@@ -1055,6 +1074,7 @@
//
// label3
//
+ label3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label3.AutoSize = true;
label3.BackColor = System.Drawing.SystemColors.ControlLightLight;
label3.Location = new System.Drawing.Point(71, 52);
@@ -1071,7 +1091,7 @@
lameBitrateTb.Maximum = 320;
lameBitrateTb.Minimum = 16;
lameBitrateTb.Name = "lameBitrateTb";
- lameBitrateTb.Size = new System.Drawing.Size(409, 45);
+ lameBitrateTb.Size = new System.Drawing.Size(408, 45);
lameBitrateTb.SmallChange = 8;
lameBitrateTb.TabIndex = 0;
lameBitrateTb.TickFrequency = 16;
@@ -1090,6 +1110,7 @@
//
// lameQualityGb
//
+ lameQualityGb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lameQualityGb.Controls.Add(label19);
lameQualityGb.Controls.Add(label18);
lameQualityGb.Controls.Add(label17);
@@ -1105,13 +1126,14 @@
lameQualityGb.Controls.Add(lameVBRQualityTb);
lameQualityGb.Location = new System.Drawing.Point(6, 235);
lameQualityGb.Name = "lameQualityGb";
- lameQualityGb.Size = new System.Drawing.Size(421, 109);
+ lameQualityGb.Size = new System.Drawing.Size(438, 109);
lameQualityGb.TabIndex = 0;
lameQualityGb.TabStop = false;
lameQualityGb.Text = "Quality";
//
// label19
//
+ label19.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label19.AutoSize = true;
label19.Location = new System.Drawing.Point(349, 52);
label19.Name = "label19";
@@ -1121,6 +1143,7 @@
//
// label18
//
+ label18.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label18.AutoSize = true;
label18.Location = new System.Drawing.Point(307, 52);
label18.Name = "label18";
@@ -1130,6 +1153,7 @@
//
// label17
//
+ label17.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label17.AutoSize = true;
label17.Location = new System.Drawing.Point(265, 52);
label17.Name = "label17";
@@ -1139,6 +1163,7 @@
//
// label16
//
+ label16.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label16.AutoSize = true;
label16.Location = new System.Drawing.Point(223, 52);
label16.Name = "label16";
@@ -1148,6 +1173,7 @@
//
// label12
//
+ label12.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label12.AutoSize = true;
label12.Location = new System.Drawing.Point(182, 52);
label12.Name = "label12";
@@ -1157,6 +1183,7 @@
//
// label15
//
+ label15.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label15.AutoSize = true;
label15.Location = new System.Drawing.Point(140, 52);
label15.Name = "label15";
@@ -1166,6 +1193,7 @@
//
// label9
//
+ label9.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label9.AutoSize = true;
label9.Location = new System.Drawing.Point(97, 52);
label9.Name = "label9";
@@ -1175,6 +1203,7 @@
//
// label8
//
+ label8.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label8.AutoSize = true;
label8.Location = new System.Drawing.Point(391, 52);
label8.Name = "label8";
@@ -1202,6 +1231,7 @@
//
// label14
//
+ label14.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label14.AutoSize = true;
label14.Location = new System.Drawing.Point(56, 52);
label14.Name = "label14";
@@ -1211,6 +1241,7 @@
//
// label2
//
+ label2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
label2.AutoSize = true;
label2.Location = new System.Drawing.Point(14, 52);
label2.Name = "label2";
@@ -1225,25 +1256,27 @@
lameVBRQualityTb.Location = new System.Drawing.Point(10, 22);
lameVBRQualityTb.Maximum = 9;
lameVBRQualityTb.Name = "lameVBRQualityTb";
- lameVBRQualityTb.Size = new System.Drawing.Size(405, 45);
+ lameVBRQualityTb.Size = new System.Drawing.Size(404, 45);
lameVBRQualityTb.TabIndex = 0;
lameVBRQualityTb.Value = 9;
//
// groupBox2
//
+ groupBox2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
groupBox2.Controls.Add(lameTargetQualityRb);
groupBox2.Controls.Add(lameTargetBitrateRb);
groupBox2.Location = new System.Drawing.Point(6, 22);
groupBox2.Name = "groupBox2";
- groupBox2.Size = new System.Drawing.Size(214, 58);
+ groupBox2.Size = new System.Drawing.Size(189, 58);
groupBox2.TabIndex = 0;
groupBox2.TabStop = false;
groupBox2.Text = "Target";
//
// lameTargetQualityRb
//
+ lameTargetQualityRb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
lameTargetQualityRb.AutoSize = true;
- lameTargetQualityRb.Location = new System.Drawing.Point(139, 22);
+ lameTargetQualityRb.Location = new System.Drawing.Point(118, 22);
lameTargetQualityRb.Name = "lameTargetQualityRb";
lameTargetQualityRb.Size = new System.Drawing.Size(63, 19);
lameTargetQualityRb.TabIndex = 0;
@@ -1321,7 +1354,6 @@
Controls.Add(tabControl);
Controls.Add(cancelBtn);
Controls.Add(saveBtn);
- FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MaximizeBox = false;
MinimizeBox = false;
diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.resx b/Source/LibationWinForms/Dialogs/SettingsDialog.resx
index a395bffc..af32865e 100644
--- a/Source/LibationWinForms/Dialogs/SettingsDialog.resx
+++ b/Source/LibationWinForms/Dialogs/SettingsDialog.resx
@@ -18,7 +18,7 @@
System.Resources.ResXResourceReader, System.Windows.Forms, ...
System.Resources.ResXResourceWriter, System.Windows.Forms, ...
this is my long stringthis is a comment
- Blue
+ Blue
[base64 mime encoded serialized .NET Framework object]
diff --git a/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj b/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj
index 146a4b64..84ffac3c 100644
--- a/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj
+++ b/Source/LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj
index 5b1de7c6..da0cc4f4 100644
--- a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj
+++ b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj
index ae17ba06..e6f37d71 100644
--- a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj
+++ b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj b/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj
index 55a7622b..2677dd91 100644
--- a/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj
+++ b/Source/_Tests/FileManager.Tests/FileManager.Tests.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj b/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj
index fc056d72..cb7de866 100644
--- a/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj
+++ b/Source/_Tests/LibationFileManager.Tests/LibationFileManager.Tests.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj b/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj
index fada77e1..3da034be 100644
--- a/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj
+++ b/Source/_Tests/LibationSearchEngine.Tests/LibationSearchEngine.Tests.csproj
@@ -7,8 +7,8 @@
-
-
+
+