Allow Libation to start with an invalid Books directory
- Configuration.LibationSettingsAreValid is true if Books property exists and is any non-null, non-empty string. - If LibationSettingsAreValid is false, Libation will prompt user to set up Libation. - When the main window is shown, Libation checks if the books directory exists, and if it doesn't, user is notified and prompted to change their setting - When a user tries to liberate or convert a book, Books directory is validated and user notified if it does not exist.
This commit is contained in:
parent
db588629c0
commit
ac4c168725
@ -120,7 +120,10 @@ namespace LibationAvalonia
|
|||||||
ShowMainWindow(desktop);
|
ShowMainWindow(desktop);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await CancelInstallation();
|
{
|
||||||
|
e.Cancel = true;
|
||||||
|
await CancelInstallation(setupDialog);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (setupDialog.IsReturningUser)
|
else if (setupDialog.IsReturningUser)
|
||||||
{
|
{
|
||||||
@ -128,7 +131,8 @@ namespace LibationAvalonia
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await CancelInstallation();
|
e.Cancel = true;
|
||||||
|
await CancelInstallation(setupDialog);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,11 +143,11 @@ namespace LibationAvalonia
|
|||||||
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
|
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await MessageBox.ShowAdminAlert(null, body, title, ex);
|
await MessageBox.ShowAdminAlert(setupDialog, body, title, ex);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
await MessageBox.Show(setupDialog, $"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -190,6 +194,7 @@ namespace LibationAvalonia
|
|||||||
{
|
{
|
||||||
// path did not result in valid settings
|
// path did not result in valid settings
|
||||||
var continueResult = await MessageBox.Show(
|
var continueResult = await MessageBox.Show(
|
||||||
|
libationFilesDialog,
|
||||||
$"No valid settings were found at this location.\r\nWould you like to create a new install settings in this folder?\r\n\r\n{libationFilesDialog.SelectedDirectory}",
|
$"No valid settings were found at this location.\r\nWould you like to create a new install settings in this folder?\r\n\r\n{libationFilesDialog.SelectedDirectory}",
|
||||||
"New install?",
|
"New install?",
|
||||||
MessageBoxButtons.YesNo,
|
MessageBoxButtons.YesNo,
|
||||||
@ -207,18 +212,18 @@ namespace LibationAvalonia
|
|||||||
ShowMainWindow(desktop);
|
ShowMainWindow(desktop);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await CancelInstallation();
|
await CancelInstallation(libationFilesDialog);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await CancelInstallation();
|
await CancelInstallation(libationFilesDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
libationFilesDialog.Close();
|
libationFilesDialog.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
static async Task CancelInstallation()
|
static async Task CancelInstallation(Window window)
|
||||||
{
|
{
|
||||||
await MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
await MessageBox.Show(window, "Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using FileManager;
|
||||||
using LibationAvalonia.ViewModels.Settings;
|
using LibationAvalonia.ViewModels.Settings;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationUiBase.Forms;
|
using LibationUiBase.Forms;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationAvalonia.Dialogs
|
namespace LibationAvalonia.Dialogs
|
||||||
@ -39,6 +41,21 @@ namespace LibationAvalonia.Dialogs
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
public async void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
=> await SaveAndCloseAsync();
|
{
|
||||||
|
LongPath lonNewBooks = settingsDisp.ImportantSettings.GetBooksDirectory();
|
||||||
|
if (!System.IO.Directory.Exists(lonNewBooks))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.IO.Directory.CreateDirectory(lonNewBooks);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await MessageBox.Show(this, $"Error creating Books Location:\n\n{ex.Message}", "Error creating directory", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await SaveAndCloseAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,10 +36,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
|||||||
|
|
||||||
public void SaveSettings(Configuration config)
|
public void SaveSettings(Configuration config)
|
||||||
{
|
{
|
||||||
LongPath lonNewBooks = Configuration.GetKnownDirectory(BooksDirectory) is Configuration.KnownDirectories.None ? BooksDirectory : System.IO.Path.Combine(BooksDirectory, "Books");
|
config.Books = GetBooksDirectory();
|
||||||
if (!System.IO.Directory.Exists(lonNewBooks))
|
|
||||||
System.IO.Directory.CreateDirectory(lonNewBooks);
|
|
||||||
config.Books = lonNewBooks;
|
|
||||||
config.SavePodcastsToParentFolder = SavePodcastsToParentFolder;
|
config.SavePodcastsToParentFolder = SavePodcastsToParentFolder;
|
||||||
config.OverwriteExisting = OverwriteExisting;
|
config.OverwriteExisting = OverwriteExisting;
|
||||||
config.CreationTime = CreationTime.Value;
|
config.CreationTime = CreationTime.Value;
|
||||||
@ -47,6 +44,9 @@ namespace LibationAvalonia.ViewModels.Settings
|
|||||||
config.LogLevel = LoggingLevel;
|
config.LogLevel = LoggingLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LongPath GetBooksDirectory()
|
||||||
|
=> Configuration.GetKnownDirectory(BooksDirectory) is Configuration.KnownDirectories.None ? BooksDirectory : System.IO.Path.Combine(BooksDirectory, "Books");
|
||||||
|
|
||||||
private static float scaleFactorToLinearRange(float scaleFactor)
|
private static float scaleFactorToLinearRange(float scaleFactor)
|
||||||
=> float.Round(100 * MathF.Log2(scaleFactor));
|
=> float.Round(100 * MathF.Log2(scaleFactor));
|
||||||
private static float linearRangeToScaleFactor(float value)
|
private static float linearRangeToScaleFactor(float value)
|
||||||
|
|||||||
@ -135,6 +135,20 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
private async void MainWindow_Opened(object sender, EventArgs e)
|
private async void MainWindow_Opened(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (AudibleFileStorage.BooksDirectory is null)
|
||||||
|
{
|
||||||
|
var result = await MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Please set a valid Books location in the settings dialog.",
|
||||||
|
"Books Directory Not Set",
|
||||||
|
MessageBoxButtons.OKCancel,
|
||||||
|
MessageBoxIcon.Warning,
|
||||||
|
MessageBoxDefaultButton.Button1);
|
||||||
|
|
||||||
|
if (result is DialogResult.OK)
|
||||||
|
await new SettingsDialog().ShowDialog(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (Configuration.Instance.FirstLaunch)
|
if (Configuration.Instance.FirstLaunch)
|
||||||
{
|
{
|
||||||
var result = await MessageBox.Show(this, "Would you like a guided tour to get started?", "Libation Walkthrough", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
|
var result = await MessageBox.Show(this, "Would you like a guided tour to get started?", "Libation Walkthrough", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using CommandLine;
|
using CommandLine;
|
||||||
|
using LibationFileManager;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationCli
|
namespace LibationCli
|
||||||
@ -6,6 +8,15 @@ namespace LibationCli
|
|||||||
[Verb("convert", HelpText = "Convert mp4 to mp3.")]
|
[Verb("convert", HelpText = "Convert mp4 to mp3.")]
|
||||||
public class ConvertOptions : ProcessableOptionsBase
|
public class ConvertOptions : ProcessableOptionsBase
|
||||||
{
|
{
|
||||||
protected override Task ProcessAsync() => RunAsync(CreateProcessable<FileLiberator.ConvertToMp3>());
|
protected override Task ProcessAsync()
|
||||||
|
{
|
||||||
|
if (AudibleFileStorage.BooksDirectory is null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Error: Books directory is not set. Please configure the 'Books' setting in Settings.json.");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RunAsync(CreateProcessable<FileLiberator.ConvertToMp3>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
using CommandLine;
|
using CommandLine;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using FileLiberator;
|
using FileLiberator;
|
||||||
|
using LibationFileManager;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationCli
|
namespace LibationCli
|
||||||
@ -13,9 +15,17 @@ namespace LibationCli
|
|||||||
public bool PdfOnly { get; set; }
|
public bool PdfOnly { get; set; }
|
||||||
|
|
||||||
protected override Task ProcessAsync()
|
protected override Task ProcessAsync()
|
||||||
=> PdfOnly
|
{
|
||||||
|
if (AudibleFileStorage.BooksDirectory is null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Error: Books directory is not set. Please configure the 'Books' setting in Settings.json.");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PdfOnly
|
||||||
? RunAsync(CreateProcessable<DownloadPdf>())
|
? RunAsync(CreateProcessable<DownloadPdf>())
|
||||||
: RunAsync(CreateBackupBook());
|
: RunAsync(CreateBackupBook());
|
||||||
|
}
|
||||||
|
|
||||||
private static Processable CreateBackupBook()
|
private static Processable CreateBackupBook()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -45,13 +45,24 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
public static AudioFileStorage Audio { get; } = new AudioFileStorage();
|
public static AudioFileStorage Audio { get; } = new AudioFileStorage();
|
||||||
|
|
||||||
public static LongPath BooksDirectory
|
/// <summary>
|
||||||
|
/// The fully-qualified Books durectory path if the directory exists, otherwise null.
|
||||||
|
/// </summary>
|
||||||
|
public static LongPath? BooksDirectory
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
|
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
|
||||||
Configuration.Instance.Books = Configuration.DefaultBooksDirectory;
|
return null;
|
||||||
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
|
try
|
||||||
|
{
|
||||||
|
return Directory.CreateDirectory(Configuration.Instance.Books)?.FullName;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Serilog.Log.Error(ex, "Error creating Books directory: {@BooksDirectory}", Configuration.Instance.Books);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -129,8 +140,9 @@ namespace LibationFileManager
|
|||||||
protected override LongPath? GetFilePathCustom(string productId)
|
protected override LongPath? GetFilePathCustom(string productId)
|
||||||
=> GetFilePathsCustom(productId).FirstOrDefault();
|
=> GetFilePathsCustom(productId).FirstOrDefault();
|
||||||
|
|
||||||
private static BackgroundFileSystem newBookDirectoryFiles()
|
private static BackgroundFileSystem? newBookDirectoryFiles()
|
||||||
=> new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
|
=> BooksDirectory is LongPath books ? new BackgroundFileSystem(books, "*.*", SearchOption.AllDirectories)
|
||||||
|
: null;
|
||||||
|
|
||||||
protected override List<LongPath> GetFilePathsCustom(string productId)
|
protected override List<LongPath> GetFilePathsCustom(string productId)
|
||||||
{
|
{
|
||||||
@ -140,6 +152,7 @@ namespace LibationFileManager
|
|||||||
BookDirectoryFiles = newBookDirectoryFiles();
|
BookDirectoryFiles = newBookDirectoryFiles();
|
||||||
|
|
||||||
var regex = GetBookSearchRegex(productId);
|
var regex = GetBookSearchRegex(productId);
|
||||||
|
var diskFiles = BookDirectoryFiles?.FindFiles(regex) ?? [];
|
||||||
|
|
||||||
//Find all extant files matching the productId
|
//Find all extant files matching the productId
|
||||||
//using both the file system and the file path cache
|
//using both the file system and the file path cache
|
||||||
@ -148,17 +161,17 @@ namespace LibationFileManager
|
|||||||
.GetFiles(productId)
|
.GetFiles(productId)
|
||||||
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
|
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
|
||||||
.Select(c => c.path)
|
.Select(c => c.path)
|
||||||
.Union(BookDirectoryFiles.FindFiles(regex))
|
.Union(diskFiles)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
{
|
{
|
||||||
if (BookDirectoryFiles is null)
|
if (BookDirectoryFiles is null && BooksDirectory is not null)
|
||||||
lock (bookDirectoryFilesLocker)
|
lock (bookDirectoryFilesLocker)
|
||||||
BookDirectoryFiles = newBookDirectoryFiles();
|
BookDirectoryFiles = newBookDirectoryFiles();
|
||||||
else
|
|
||||||
BookDirectoryFiles?.RefreshFiles();
|
BookDirectoryFiles?.RefreshFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LongPath? GetPath(string productId) => GetFilePath(productId);
|
public LongPath? GetPath(string productId) => GetFilePath(productId);
|
||||||
|
|||||||
@ -36,12 +36,12 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
[return: NotNullIfNotNull(nameof(defaultValue))]
|
[return: NotNullIfNotNull(nameof(defaultValue))]
|
||||||
public T? GetNonString<T>(T defaultValue, [CallerMemberName] string propertyName = "")
|
public T? GetNonString<T>(T defaultValue, [CallerMemberName] string propertyName = "")
|
||||||
=> Settings.GetNonString(propertyName, defaultValue);
|
=> Settings is null ? default : Settings.GetNonString(propertyName, defaultValue);
|
||||||
|
|
||||||
|
|
||||||
[return: NotNullIfNotNull(nameof(defaultValue))]
|
[return: NotNullIfNotNull(nameof(defaultValue))]
|
||||||
public string? GetString(string? defaultValue = null, [CallerMemberName] string propertyName = "")
|
public string? GetString(string? defaultValue = null, [CallerMemberName] string propertyName = "")
|
||||||
=> Settings.GetString(propertyName, defaultValue);
|
=> Settings?.GetString(propertyName, defaultValue);
|
||||||
|
|
||||||
public object? GetObject([CallerMemberName] string propertyName = "") => Settings.GetObject(propertyName);
|
public object? GetObject([CallerMemberName] string propertyName = "") => Settings.GetObject(propertyName);
|
||||||
|
|
||||||
@ -132,13 +132,13 @@ namespace LibationFileManager
|
|||||||
/// True if the Books directory can be written to with 255 unicode character filenames
|
/// True if the Books directory can be written to with 255 unicode character filenames
|
||||||
/// <para/> Does not persist. Check and set this value at runtime and whenever Books is changed.
|
/// <para/> Does not persist. Check and set this value at runtime and whenever Books is changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool BooksCanWrite255UnicodeChars => m_BooksCanWrite255UnicodeChars ??= FileSystemTest.CanWrite255UnicodeChars(Books);
|
public bool BooksCanWrite255UnicodeChars => m_BooksCanWrite255UnicodeChars ??= FileSystemTest.CanWrite255UnicodeChars(AudibleFileStorage.BooksDirectory);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the Books directory can be written to with filenames containing characters invalid on Windows (:, *, ?, <, >, |)
|
/// True if the Books directory can be written to with filenames containing characters invalid on Windows (:, *, ?, <, >, |)
|
||||||
/// <para/> Always false on Windows platforms.
|
/// <para/> Always false on Windows platforms.
|
||||||
/// <para/> Does not persist. Check and set this value at runtime and whenever Books is changed.
|
/// <para/> Does not persist. Check and set this value at runtime and whenever Books is changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool BooksCanWriteWindowsInvalidChars => !IsWindows && (m_BooksCanWriteWindowsInvalidChars ??= FileSystemTest.CanWriteWindowsInvalidChars(Books));
|
public bool BooksCanWriteWindowsInvalidChars => !IsWindows && (m_BooksCanWriteWindowsInvalidChars ??= FileSystemTest.CanWriteWindowsInvalidChars(AudibleFileStorage.BooksDirectory));
|
||||||
|
|
||||||
[Description("Overwrite existing files if they already exist?")]
|
[Description("Overwrite existing files if they already exist?")]
|
||||||
public bool OverwriteExisting { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
public bool OverwriteExisting { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||||
|
|||||||
@ -3,48 +3,58 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace LibationFileManager
|
namespace LibationFileManager
|
||||||
{
|
{
|
||||||
public partial class Configuration : PropertyChangeFilter
|
public partial class Configuration : PropertyChangeFilter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if <see cref="SettingsFilePath"/> exists and the <see cref="Books"/> property has a non-null, non-empty value.
|
||||||
|
/// Does not verify the existence of the <see cref="Books"/> directory.
|
||||||
|
/// </summary>
|
||||||
public bool LibationSettingsAreValid => SettingsFileIsValid(SettingsFilePath);
|
public bool LibationSettingsAreValid => SettingsFileIsValid(SettingsFilePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if <paramref name="settingsFile"/> exists and the <see cref="Books"/> property has a non-null, non-empty value.
|
||||||
|
/// Does not verify the existence of the <see cref="Books"/> directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="settingsFile">File path to the settings JSON file</param>
|
||||||
public static bool SettingsFileIsValid(string settingsFile)
|
public static bool SettingsFileIsValid(string settingsFile)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(settingsFile)) || !File.Exists(settingsFile))
|
if (!Directory.Exists(Path.GetDirectoryName(settingsFile)) || !File.Exists(settingsFile))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var pDic = new PersistentDictionary(settingsFile, isReadOnly: false);
|
try
|
||||||
|
|
||||||
if (pDic.GetString(nameof(Books)) is not string booksDir)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!Directory.Exists(booksDir))
|
|
||||||
{
|
{
|
||||||
if (Path.GetDirectoryName(settingsFile) is not string dir)
|
var settingsJson = JObject.Parse(File.ReadAllText(settingsFile));
|
||||||
throw new DirectoryNotFoundException(settingsFile);
|
return !string.IsNullOrWhiteSpace(settingsJson[nameof(Books)]?.Value<string>());
|
||||||
|
}
|
||||||
//"Books" is not null, so setup has already been run.
|
catch (Exception ex)
|
||||||
//Since Books can't be found, try to create it
|
{
|
||||||
//and then revert to the default books directory
|
Serilog.Log.Logger.Error(ex, "Failed to load settings file: {@SettingsFile}", settingsFile);
|
||||||
foreach (string d in new string[] { booksDir, DefaultBooksDirectory })
|
try
|
||||||
{
|
{
|
||||||
|
Serilog.Log.Logger.Information("Deleting invalid settings file: {@SettingsFile}", settingsFile);
|
||||||
|
FileUtility.SaferDelete(settingsFile);
|
||||||
|
Serilog.Log.Logger.Information("Creating a new, empty setting file: {@SettingsFile}", settingsFile);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(d);
|
File.WriteAllText(settingsFile, "{}");
|
||||||
|
}
|
||||||
pDic.SetString(nameof(Books), d);
|
catch (Exception createEx)
|
||||||
|
{
|
||||||
return Directory.Exists(d);
|
Serilog.Log.Logger.Error(createEx, "Failed to create new settings file: {@SettingsFile}", settingsFile);
|
||||||
}
|
}
|
||||||
catch { /* Do Nothing */ }
|
|
||||||
}
|
}
|
||||||
|
catch (Exception deleteEx)
|
||||||
|
{
|
||||||
|
Serilog.Log.Logger.Error(deleteEx, "Failed to delete the invalid settings file: {@SettingsFile}", settingsFile);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region singleton stuff
|
#region singleton stuff
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using ApplicationServices;
|
using ApplicationServices;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
|
using LibationFileManager;
|
||||||
using LibationUiBase.Forms;
|
using LibationUiBase.Forms;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -95,6 +96,9 @@ public class ProcessQueueViewModel : ReactiveObject
|
|||||||
|
|
||||||
public bool QueueDownloadPdf(IList<LibraryBook> libraryBooks)
|
public bool QueueDownloadPdf(IList<LibraryBook> libraryBooks)
|
||||||
{
|
{
|
||||||
|
if (!IsBooksDirectoryValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
var needsPdf = libraryBooks.Where(lb => lb.NeedsPdfDownload()).ToArray();
|
var needsPdf = libraryBooks.Where(lb => lb.NeedsPdfDownload()).ToArray();
|
||||||
if (needsPdf.Length > 0)
|
if (needsPdf.Length > 0)
|
||||||
{
|
{
|
||||||
@ -107,6 +111,9 @@ public class ProcessQueueViewModel : ReactiveObject
|
|||||||
|
|
||||||
public bool QueueConvertToMp3(IList<LibraryBook> libraryBooks)
|
public bool QueueConvertToMp3(IList<LibraryBook> libraryBooks)
|
||||||
{
|
{
|
||||||
|
if (!IsBooksDirectoryValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
//Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing.
|
//Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing.
|
||||||
var preLiberated = libraryBooks.Where(lb => !lb.AbsentFromLastScan && lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated && lb.Book.ContentType is DataLayer.ContentType.Product).ToArray();
|
var preLiberated = libraryBooks.Where(lb => !lb.AbsentFromLastScan && lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated && lb.Book.ContentType is DataLayer.ContentType.Product).ToArray();
|
||||||
if (preLiberated.Length > 0)
|
if (preLiberated.Length > 0)
|
||||||
@ -122,6 +129,9 @@ public class ProcessQueueViewModel : ReactiveObject
|
|||||||
|
|
||||||
public bool QueueDownloadDecrypt(IList<LibraryBook> libraryBooks)
|
public bool QueueDownloadDecrypt(IList<LibraryBook> libraryBooks)
|
||||||
{
|
{
|
||||||
|
if (!IsBooksDirectoryValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (libraryBooks.Count == 1)
|
if (libraryBooks.Count == 1)
|
||||||
{
|
{
|
||||||
var item = libraryBooks[0];
|
var item = libraryBooks[0];
|
||||||
@ -157,6 +167,32 @@ public class ProcessQueueViewModel : ReactiveObject
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsBooksDirectoryValid()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Configuration.Instance.Books))
|
||||||
|
{
|
||||||
|
Serilog.Log.Logger.Error("Books location is not set in configuration.");
|
||||||
|
MessageBoxBase.Show(
|
||||||
|
"Please choose a \"Books location\" folder in the Settings menu.",
|
||||||
|
"Books Directory Not Set",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (AudibleFileStorage.BooksDirectory is null)
|
||||||
|
{
|
||||||
|
Serilog.Log.Logger.Error("Failed to create books directory: {@booksDir}", Configuration.Instance.Books);
|
||||||
|
MessageBoxBase.Show(
|
||||||
|
$"Libation was unable to create the \"Books location\" folder at:\n{Configuration.Instance.Books}\n\nPlease change the Books location in the settings menu.",
|
||||||
|
"Failed to Create Books Directory",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsBookInQueue(LibraryBook libraryBook)
|
private bool IsBookInQueue(LibraryBook libraryBook)
|
||||||
=> Queue.FirstOrDefault(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId) is not ProcessBookViewModel entry ? false
|
=> Queue.FirstOrDefault(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId) is not ProcessBookViewModel entry ? false
|
||||||
: entry.Status is ProcessBookStatus.Cancelled or ProcessBookStatus.Failed ? !Queue.RemoveCompleted(entry)
|
: entry.Status is ProcessBookStatus.Cancelled or ProcessBookStatus.Failed ? !Queue.RemoveCompleted(entry)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class SettingsDialog
|
public partial class SettingsDialog
|
||||||
@ -55,7 +56,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
},
|
},
|
||||||
Configuration.KnownDirectories.UserProfile,
|
Configuration.KnownDirectories.UserProfile,
|
||||||
"Books");
|
"Books");
|
||||||
booksSelectControl.SelectDirectory(config.Books.PathWithoutPrefix);
|
booksSelectControl.SelectDirectory(config.Books?.PathWithoutPrefix ?? "");
|
||||||
|
|
||||||
saveEpisodesToSeriesFolderCbox.Checked = config.SavePodcastsToParentFolder;
|
saveEpisodesToSeriesFolderCbox.Checked = config.SavePodcastsToParentFolder;
|
||||||
overwriteExistingCbox.Checked = config.OverwriteExisting;
|
overwriteExistingCbox.Checked = config.OverwriteExisting;
|
||||||
@ -63,7 +64,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
gridFontScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridFontScaleFactor);
|
gridFontScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridFontScaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Save_Important(Configuration config)
|
private bool Save_Important(Configuration config)
|
||||||
{
|
{
|
||||||
var newBooks = booksSelectControl.SelectedDirectory;
|
var newBooks = booksSelectControl.SelectedDirectory;
|
||||||
|
|
||||||
@ -73,19 +74,29 @@ namespace LibationWinForms.Dialogs
|
|||||||
if (string.IsNullOrWhiteSpace(newBooks))
|
if (string.IsNullOrWhiteSpace(newBooks))
|
||||||
{
|
{
|
||||||
validationError("Cannot set Books Location to blank", "Location is blank");
|
validationError("Cannot set Books Location to blank", "Location is blank");
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
LongPath lonNewBooks = newBooks;
|
||||||
|
if (!Directory.Exists(lonNewBooks))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(lonNewBooks);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
validationError($"Error creating Books Location:\r\n{ex.Message}", "Error creating directory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
LongPath lonNewBooks = newBooks;
|
|
||||||
if (!Directory.Exists(lonNewBooks))
|
|
||||||
Directory.CreateDirectory(lonNewBooks);
|
|
||||||
|
|
||||||
config.Books = newBooks;
|
config.Books = newBooks;
|
||||||
|
|
||||||
{
|
{
|
||||||
var logLevelOld = config.LogLevel;
|
var logLevelOld = config.LogLevel;
|
||||||
var logLevelNew = (Serilog.Events.LogEventLevel)loggingLevelCb.SelectedItem;
|
var logLevelNew = (loggingLevelCb.SelectedItem as Serilog.Events.LogEventLevel?) ?? Serilog.Events.LogEventLevel.Information;
|
||||||
|
|
||||||
config.LogLevel = logLevelNew;
|
config.LogLevel = logLevelNew;
|
||||||
|
|
||||||
@ -97,9 +108,9 @@ namespace LibationWinForms.Dialogs
|
|||||||
config.SavePodcastsToParentFolder = saveEpisodesToSeriesFolderCbox.Checked;
|
config.SavePodcastsToParentFolder = saveEpisodesToSeriesFolderCbox.Checked;
|
||||||
config.OverwriteExisting = overwriteExistingCbox.Checked;
|
config.OverwriteExisting = overwriteExistingCbox.Checked;
|
||||||
|
|
||||||
|
config.CreationTime = (creationTimeCb.SelectedItem as EnumDisplay<Configuration.DateTimeSource>)?.Value ?? Configuration.DateTimeSource.File;
|
||||||
config.CreationTime = ((EnumDisplay<Configuration.DateTimeSource>)creationTimeCb.SelectedItem).Value;
|
config.LastWriteTime = (lastWriteTimeCb.SelectedItem as EnumDisplay<Configuration.DateTimeSource>)?.Value ?? Configuration.DateTimeSource.File;
|
||||||
config.LastWriteTime = ((EnumDisplay<Configuration.DateTimeSource>)lastWriteTimeCb.SelectedItem).Value;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int scaleFactorToLinearRange(float scaleFactor)
|
private static int scaleFactorToLinearRange(float scaleFactor)
|
||||||
|
|||||||
@ -43,7 +43,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
|
|
||||||
private void saveBtn_Click(object sender, EventArgs e)
|
private void saveBtn_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Save_Important(config);
|
if (!Save_Important(config)) return;
|
||||||
Save_ImportLibrary(config);
|
Save_ImportLibrary(config);
|
||||||
Save_DownloadDecrypt(config);
|
Save_DownloadDecrypt(config);
|
||||||
Save_AudioSettings(config);
|
Save_AudioSettings(config);
|
||||||
|
|||||||
@ -6,9 +6,29 @@ namespace LibationWinForms
|
|||||||
{
|
{
|
||||||
public partial class Form1
|
public partial class Form1
|
||||||
{
|
{
|
||||||
private void Configure_Settings() { }
|
private void Configure_Settings()
|
||||||
|
{
|
||||||
|
Shown += FormShown_Settings;
|
||||||
|
}
|
||||||
|
|
||||||
private void accountsToolStripMenuItem_Click(object sender, EventArgs e) => new AccountsDialog().ShowDialog();
|
private void FormShown_Settings(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (LibationFileManager.AudibleFileStorage.BooksDirectory is null)
|
||||||
|
{
|
||||||
|
var result = MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Please set a valid Books location in the settings dialog.",
|
||||||
|
"Books Directory Not Set",
|
||||||
|
MessageBoxButtons.OKCancel,
|
||||||
|
MessageBoxIcon.Warning,
|
||||||
|
MessageBoxDefaultButton.Button1);
|
||||||
|
|
||||||
|
if (result is DialogResult.OK)
|
||||||
|
new SettingsDialog().ShowDialog(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void accountsToolStripMenuItem_Click(object sender, EventArgs e) => new AccountsDialog().ShowDialog();
|
||||||
|
|
||||||
private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog();
|
private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog();
|
||||||
|
|
||||||
|
|||||||
@ -148,7 +148,10 @@ namespace LibationWinForms
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (setupDialog.IsNewUser)
|
if (setupDialog.IsNewUser)
|
||||||
|
{
|
||||||
Configuration.SetLibationFiles(defaultLibationFilesDir);
|
Configuration.SetLibationFiles(defaultLibationFilesDir);
|
||||||
|
config.Books = Configuration.DefaultBooksDirectory;
|
||||||
|
}
|
||||||
else if (setupDialog.IsReturningUser)
|
else if (setupDialog.IsReturningUser)
|
||||||
{
|
{
|
||||||
var libationFilesDialog = new LibationFilesDialog();
|
var libationFilesDialog = new LibationFilesDialog();
|
||||||
@ -175,16 +178,11 @@ namespace LibationWinForms
|
|||||||
CancelInstallation();
|
CancelInstallation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
config.Books = Configuration.DefaultBooksDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// INIT DEFAULT SETTINGS
|
if (!config.LibationSettingsAreValid)
|
||||||
// if 'new user' was clicked, or if 'returning user' chose new install: show basic settings dialog
|
CancelInstallation();
|
||||||
config.Books ??= Configuration.DefaultBooksDirectory;
|
|
||||||
|
|
||||||
if (config.LibationSettingsAreValid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CancelInstallation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>migrations which require Forms or are long-running</summary>
|
/// <summary>migrations which require Forms or are long-running</summary>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user