using ApplicationServices; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Platform.Storage; using DataLayer; using LibationAvalonia.ViewModels; using LibationFileManager; using ReactiveUI; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace LibationAvalonia.Dialogs { public partial class LocateAudiobooksDialog : DialogWindow { private event EventHandler FileFound; private readonly CancellationTokenSource tokenSource = new(); private readonly List foundAsins = new(); private readonly LocatedAudiobooksViewModel _viewModel; public LocateAudiobooksDialog() { InitializeComponent(); DataContext = _viewModel = new(); this.RestoreSizeAndLocation(Configuration.Instance); if (Design.IsDesignMode) { _viewModel.FoundFiles.Add(new("[0000001]", "Filename 1.m4b")); _viewModel.FoundFiles.Add(new("[0000002]", "Filename 2.m4b")); } else { Opened += LocateAudiobooksDialog_Opened; FileFound += LocateAudiobooks_FileFound; Closing += LocateAudiobooksDialog_Closing; } } private void LocateAudiobooksDialog_Closing(object sender, System.ComponentModel.CancelEventArgs e) { tokenSource.Cancel(); //If this dialog is closed before it's completed, Closing is fired //once for the form closing and again for the MessageBox closing. Closing -= LocateAudiobooksDialog_Closing; this.SaveSizeAndLocation(Configuration.Instance); } private void LocateAudiobooks_FileFound(object sender, FilePathCache.CacheEntry e) { var newItem = new Tuple($"[{e.Id}]", Path.GetFileName(e.Path)); _viewModel.FoundFiles.Add(newItem); foundAudiobooksLB.SelectedItem = newItem; if (!foundAsins.Any(asin => asin == e.Id)) { foundAsins.Add(e.Id); _viewModel.FoundAsins = foundAsins.Count; } } private async void LocateAudiobooksDialog_Opened(object sender, EventArgs e) { var folderPicker = new FolderPickerOpenOptions { Title = "Select the folder to search for audiobooks", AllowMultiple = false, SuggestedStartLocation = await StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix) }; var selectedFolder = (await StorageProvider.OpenFolderPickerAsync(folderPicker))?.SingleOrDefault()?.TryGetLocalPath(); if (selectedFolder is null || !Directory.Exists(selectedFolder)) { await CancelAndCloseAsync(); return; } using var context = DbContexts.GetContext(); await foreach (var book in AudioFileStorage.FindAudiobooksAsync(selectedFolder, tokenSource.Token)) { try { FilePathCache.Insert(book); var lb = context.GetLibraryBook_Flat_NoTracking(book.Id); if (lb.Book.UserDefinedItem.BookStatus is not LiberatedStatus.Liberated) await Task.Run(() => lb.UpdateBookStatus(LiberatedStatus.Liberated)); FileFound?.Invoke(this, book); } catch (Exception ex) { Serilog.Log.Error(ex, "Error adding found audiobook file to Libation. {@audioFile}", book); } } await MessageBox.Show(this, $"Libation has found {foundAsins.Count} unique audiobooks and added them to its database. ", $"Found {foundAsins.Count} Audiobooks"); await SaveAndCloseAsync(); } } public class LocatedAudiobooksViewModel : ViewModelBase { private int _foundAsins = 0; public AvaloniaList> FoundFiles { get; } = new(); public int FoundAsins { get => _foundAsins; set => this.RaiseAndSetIfChanged(ref _foundAsins, value); } } }