From 77562fa6373ea5312bf511599895acb13387fdf6 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:08:17 +0200 Subject: [PATCH 01/11] Unit test updates --- .github/workflows/run_unit_tests.yml | 4 ++-- .../Utility/AudioConverterServiceUnitTest.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 3fd1655a..e436b851 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -10,12 +10,12 @@ jobs: # use ubuntu-latest image to run steps on runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v4.1.2 # sets up .NET # version can be found here https://dotnet.microsoft.com/en-us/download/dotnet/7.0 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: '7.0.101' diff --git a/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs b/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs index 3a3e39d3..4176f28f 100644 --- a/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs +++ b/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs @@ -25,6 +25,7 @@ internal class AudioConverterServiceUnitTest : IAudioConverterService public Task SplitAudiofileAsync(Audiofile audiofile, TimeSpan from, TimeSpan? to = null) { + ProgressChanged?.Invoke(this, 100); // This implementation does nothing with audio processing, so we only return some fake data return Task.FromResult(null); } From 26dddd47b36391fe865c49cb0ca5b5cba4a28e11 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:37:18 +0200 Subject: [PATCH 02/11] Localized validation messages --- .../Resources/Localization/ValidationMessage/de.json | 3 ++- .../Resources/Localization/ValidationMessage/en.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json index d0f65374..a4893844 100644 --- a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json +++ b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json @@ -37,6 +37,7 @@ "{0} should be equal or less to '{1}'!": "{0} sollte kleiner oder gleich '{1}' sein!", "Filename": "Dateiname", "Artist": "Künstler", - "Title": "Titel" + "Title": "Titel", + "Exportprofile": "Exportprofil" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json index 8f217b4c..2880c68d 100644 --- a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json +++ b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json @@ -37,6 +37,7 @@ "{0} should be equal or less to '{1}'!": "{0} should be equal or less to '{1}'!", "Filename": "Filename", "Artist": "Artist", - "Title": "Title" + "Title": "Title", + "Exportprofile": "Exportprofile" } } \ No newline at end of file From d2f300ef4443e317050d029e65ac9f8b73330b0e Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:43:17 +0200 Subject: [PATCH 03/11] localized validation messages --- .../Resources/Localization/ValidationMessage/de.json | 3 ++- .../Resources/Localization/ValidationMessage/en.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json index a4893844..c4a91e06 100644 --- a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json +++ b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json @@ -38,6 +38,7 @@ "Filename": "Dateiname", "Artist": "Künstler", "Title": "Titel", - "Exportprofile": "Exportprofil" + "Exportprofile": "Exportprofil", + "ApplicationOptions": "Applikationsoptionen" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json index 2880c68d..d08f0bd6 100644 --- a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json +++ b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json @@ -38,6 +38,7 @@ "Filename": "Filename", "Artist": "Artist", "Title": "Title", - "Exportprofile": "Exportprofile" + "Exportprofile": "Exportprofile", + "ApplicationOptions": "Application options" } } \ No newline at end of file From 9e65aa25ca3b3cb08d710c8053aca19f66fcf21c Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:37:00 +0200 Subject: [PATCH 04/11] removed audio processing with ffmpeg --- .../AudioCuesheetEditor.csproj | 1 - .../Model/IO/Audio/AudioConverterService.cs | 118 ------------------ .../Model/IO/Audio/IAudioConverterService.cs | 23 ---- .../Model/IO/Export/ExportAudiofile.cs | 23 ---- .../Model/IO/Export/Exportfile.cs | 1 - .../Model/IO/Export/ExportfileGenerator.cs | 66 +--------- .../Model/IO/Export/SplitPoint.cs | 1 + AudioCuesheetEditor/Program.cs | 1 - .../Localization/ModalExportdialog/de.json | 1 - .../Localization/ModalExportdialog/en.json | 1 - AudioCuesheetEditor/Shared/MainLayout.razor | 3 +- .../Shared/ModalExportdialog.razor | 28 +---- .../IO/Export/ExportfileGeneratorTests.cs | 46 +++---- .../Utility/AudioConverterServiceUnitTest.cs | 33 ----- .../Utility/TestHelper.cs | 2 - 15 files changed, 35 insertions(+), 313 deletions(-) delete mode 100644 AudioCuesheetEditor/Model/IO/Audio/AudioConverterService.cs delete mode 100644 AudioCuesheetEditor/Model/IO/Audio/IAudioConverterService.cs delete mode 100644 AudioCuesheetEditor/Model/IO/Export/ExportAudiofile.cs delete mode 100644 AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index caae1e57..1f86a34b 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -97,7 +97,6 @@ - diff --git a/AudioCuesheetEditor/Model/IO/Audio/AudioConverterService.cs b/AudioCuesheetEditor/Model/IO/Audio/AudioConverterService.cs deleted file mode 100644 index 2aa9edaf..00000000 --- a/AudioCuesheetEditor/Model/IO/Audio/AudioConverterService.cs +++ /dev/null @@ -1,118 +0,0 @@ -//This file is part of AudioCuesheetEditor. - -//AudioCuesheetEditor is free software: you can redistribute it and/or modify -//it under the terms of the GNU General Public License as published by -//the Free Software Foundation, either version 3 of the License, or -//(at your option) any later version. - -//AudioCuesheetEditor is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. - -//You should have received a copy of the GNU General Public License -//along with Foobar. If not, see -//. -using FFmpegBlazor; -using Microsoft.JSInterop; - -namespace AudioCuesheetEditor.Model.IO.Audio -{ - public class AudioConverterService : IAudioConverterService, IDisposable - { - private readonly IJSRuntime _jSRuntime; - private FFMPEG? ffMPEGInstance; - private bool disposedValue; - - public event EventHandler? ProgressChanged; - - public AudioConverterService(IJSRuntime jSRuntime) - { - _jSRuntime = jSRuntime; - } - - public void Dispose() - { - // Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(bool disposing)" ein. - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - - public Boolean IsReady => (ffMPEGInstance != null) && ffMPEGInstance.IsLoaded; - - public async Task SplitAudiofileAsync(Audiofile audiofile, TimeSpan from, TimeSpan? to = null) - { - if (IsReady == false) - { - await InitAsync(); - } - if (ffMPEGInstance != null) - { - await audiofile.LoadContentStream(); - if (audiofile.ContentStream != null) - { - using var memoryStream = new MemoryStream(); - audiofile.ContentStream.Seek(0, SeekOrigin.Begin); - audiofile.ContentStream.CopyTo(memoryStream); - var buffer = memoryStream.ToArray(); - ffMPEGInstance.WriteFile(audiofile.Name, buffer); - var splitAudiofilename = String.Format("output-{0}{1}", Guid.NewGuid(), audiofile.AudioCodec?.FileExtension); - if (to == null) - { - await ffMPEGInstance.Run("-ss", from.ToString("hh\\:mm\\:ss\\.fff"), "-i", audiofile.Name, "-c", "copy", splitAudiofilename); - } - else - { - await ffMPEGInstance.Run("-ss", from.ToString("hh\\:mm\\:ss\\.fff"), "-i", audiofile.Name, "-to", to.Value.ToString("hh\\:mm\\:ss\\.fff"), "-c", "copy", splitAudiofilename); - } - ffMPEGInstance.UnlinkFile(audiofile.Name); - var res = await ffMPEGInstance.ReadFile(splitAudiofilename); - return res; - } - else - { - throw new Exception("ContentStream wasn't loaded!"); - } - } - return null; - } - - public async Task InitAsync() - { - //initialize FFmpegFactory - await FFmpegFactory.Init(_jSRuntime); - if (ffMPEGInstance == null) - { - ffMPEGInstance = FFmpegFactory.CreateFFmpeg(new FFmpegConfig() { Log = true }); - await ffMPEGInstance.Load(true); - - ffMPEGInstance.Progress += FFMPEGInstance_Progress; - } - } - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // Verwalteten Zustand (verwaltete Objekte) bereinigen - if (ffMPEGInstance != null) - { - ffMPEGInstance.Progress -= FFMPEGInstance_Progress; - } - - } - - // Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben - // Große Felder auf NULL setzen - disposedValue = true; - } - } - - private void FFMPEGInstance_Progress(Progress p) - { - ProgressChanged?.Invoke(this, Convert.ToInt32(p.Ratio * 100)); - } - } -} diff --git a/AudioCuesheetEditor/Model/IO/Audio/IAudioConverterService.cs b/AudioCuesheetEditor/Model/IO/Audio/IAudioConverterService.cs deleted file mode 100644 index b060702d..00000000 --- a/AudioCuesheetEditor/Model/IO/Audio/IAudioConverterService.cs +++ /dev/null @@ -1,23 +0,0 @@ -//This file is part of AudioCuesheetEditor. - -//AudioCuesheetEditor is free software: you can redistribute it and/or modify -//it under the terms of the GNU General Public License as published by -//the Free Software Foundation, either version 3 of the License, or -//(at your option) any later version. - -//AudioCuesheetEditor is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. - -//You should have received a copy of the GNU General Public License -//along with Foobar. If not, see -//. -namespace AudioCuesheetEditor.Model.IO.Audio -{ - public interface IAudioConverterService - { - public event EventHandler? ProgressChanged; - public Task SplitAudiofileAsync(Audiofile audiofile, TimeSpan from, TimeSpan? to = null); - } -} diff --git a/AudioCuesheetEditor/Model/IO/Export/ExportAudiofile.cs b/AudioCuesheetEditor/Model/IO/Export/ExportAudiofile.cs deleted file mode 100644 index e4544286..00000000 --- a/AudioCuesheetEditor/Model/IO/Export/ExportAudiofile.cs +++ /dev/null @@ -1,23 +0,0 @@ -//This file is part of AudioCuesheetEditor. - -//AudioCuesheetEditor is free software: you can redistribute it and/or modify -//it under the terms of the GNU General Public License as published by -//the Free Software Foundation, either version 3 of the License, or -//(at your option) any later version. - -//AudioCuesheetEditor is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. - -//You should have received a copy of the GNU General Public License -//along with Foobar. If not, see -//. -namespace AudioCuesheetEditor.Model.IO.Export -{ - public class ExportAudiofile - { - public string? Name { get; set; } - public byte[]? Content { get; set; } - } -} diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs index 64b6792b..154a3af4 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs @@ -23,6 +23,5 @@ public class Exportfile public byte[]? Content { get; set; } public TimeSpan? Begin { get; set; } public TimeSpan? End { get; set; } - public ExportAudiofile? ExportAudiofile { get; set; } } } diff --git a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs index 1d155901..ac3a4a5b 100644 --- a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs @@ -35,20 +35,19 @@ public class ExportfileGenerator : Validateable public Cuesheet Cuesheet { get; } public Exportprofile? Exportprofile { get; set; } public ApplicationOptions? ApplicationOptions { get; set; } - public IAudioConverterService? AudioConverterService { get; set; } public ExportType ExportType { get; set; } - public ExportfileGenerator(ExportType exportType, Cuesheet cuesheet, Exportprofile? exportprofile = null, ApplicationOptions? applicationOptions = null, IAudioConverterService? audioConverterService = null) + public ExportfileGenerator(ExportType exportType, Cuesheet cuesheet, Exportprofile? exportprofile = null, ApplicationOptions? applicationOptions = null) { ExportType = exportType; Cuesheet = cuesheet; Exportprofile = exportprofile; ApplicationOptions = applicationOptions; - AudioConverterService = audioConverterService; } - public async Task> GenerateExportfilesAsync() + public IReadOnlyCollection GenerateExportfiles() { + //TODO: Generate export files with start 00:00:00 and each end set correctly! List exportfiles = new(); if (Validate().Status != ValidationStatus.Error) { @@ -80,8 +79,7 @@ public async Task> GenerateExportfilesAsync() } if (content != null) { - var exportAudiofile = await GetAudiofileContentAsync(audioFileName, previousSplitPointMoment, splitPoint); - exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment, End = splitPoint.Moment, ExportAudiofile = exportAudiofile }); + exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment, End = splitPoint.Moment }); } previousSplitPointMoment = splitPoint.Moment; counter++; @@ -105,8 +103,7 @@ public async Task> GenerateExportfilesAsync() } if (content != null) { - var exportAudiofile = await GetAudiofileContentAsync(audioFileName, previousSplitPointMoment); - exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment, ExportAudiofile = exportAudiofile }); + exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment }); } } else @@ -315,38 +312,6 @@ private String WriteExport(String audiofileName, TimeSpan? from = null, SplitPoi return builder.ToString(); } - private async Task GetAudiofileContentAsync(String audiofileName, TimeSpan? from = null, SplitPoint? splitPoint = null) - { - ExportAudiofile? exportAudiofile = null; - if ((from != null) || (splitPoint != null)) - { - TimeSpan start = TimeSpan.Zero; - if (from != null) - { - start = from.Value; - } - else - { - var minBegin = Cuesheet.Tracks.Min(x => x.Begin); - if (minBegin != null) - { - start = minBegin.Value; - } - } - if (AudioConverterService == null) - { - throw new NullReferenceException(); - } - if (Cuesheet.Audiofile == null) - { - throw new NullReferenceException(); - } - var content = await AudioConverterService.SplitAudiofileAsync(Cuesheet.Audiofile, start, splitPoint?.Moment); - exportAudiofile = new() { Name = audiofileName, Content = content }; - } - return exportAudiofile; - } - protected override ValidationResult Validate(string property) { ValidationResult validationResult; @@ -414,27 +379,6 @@ protected override ValidationResult Validate(string property) validationResult = ValidationResult.Create(ValidationStatus.NoValidation); } break; - case nameof(AudioConverterService): - if (Cuesheet.SplitPoints.Any()) - { - if (AudioConverterService == null) - { - var validationMessages = new List() - { - new("{0} has no value!", nameof(Exportprofile)) - }; - validationResult = ValidationResult.Create(ValidationStatus.Error, validationMessages); - } - else - { - validationResult = ValidationResult.Create(ValidationStatus.Success); - } - } - else - { - validationResult = ValidationResult.Create(ValidationStatus.NoValidation); - } - break; default: validationResult = ValidationResult.Create(ValidationStatus.NoValidation); break; diff --git a/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs b/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs index 456fd0f7..15a332e4 100644 --- a/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs +++ b/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs @@ -22,6 +22,7 @@ namespace AudioCuesheetEditor.Model.IO.Export { public class SplitPoint : Validateable, ITraceable { + //TODO: Add audio file name as property to be set by user private Cuesheet? cuesheet; private TimeSpan? moment; private String? artist; diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs index 122fd599..45bdad06 100644 --- a/AudioCuesheetEditor/Program.cs +++ b/AudioCuesheetEditor/Program.cs @@ -52,7 +52,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); builder.Services.AddLogging(); builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging")); diff --git a/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/de.json b/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/de.json index 8f6b5874..2709c8c3 100644 --- a/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/de.json +++ b/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/de.json @@ -7,7 +7,6 @@ "Begin": "Anfang", "End": "Ende", "Content": "Inhalt", - "ExportAudiofile": "Verarbeitete Audiodatei", "Download this file": "Diese Datei herunterladen", "Generate export files": "Exportdateien generieren", "Abort": "Abbrechen", diff --git a/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/en.json b/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/en.json index 0636febf..973e4b8a 100644 --- a/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/en.json +++ b/AudioCuesheetEditor/Resources/Localization/ModalExportdialog/en.json @@ -7,7 +7,6 @@ "Begin": "Begin", "End": "End", "Content": "Content", - "ExportAudiofile": "Split audiofile", "Download this file": "Download this file", "Generate export files": "Generate export files", "Abort": "Abort", diff --git a/AudioCuesheetEditor/Shared/MainLayout.razor b/AudioCuesheetEditor/Shared/MainLayout.razor index f2449c96..1e8fe17a 100644 --- a/AudioCuesheetEditor/Shared/MainLayout.razor +++ b/AudioCuesheetEditor/Shared/MainLayout.razor @@ -31,7 +31,6 @@ along with Foobar. If not, see @inject SessionStateContainer _sessionStateContainer @inject IBlazorDownloadFileService _blazorDownloadFileService @inject ITextLocalizer _validationMessageLocalizer -@inject IAudioConverterService _audioConverterService @@ -419,7 +418,7 @@ along with Foobar. If not, see { get { - var generator = new ExportfileGenerator(ExportType.Cuesheet, _sessionStateContainer.Cuesheet, applicationOptions: applicationOptions, audioConverterService: _audioConverterService); + var generator = new ExportfileGenerator(ExportType.Cuesheet, _sessionStateContainer.Cuesheet, applicationOptions: applicationOptions); var validationResult = generator.Validate(); if (validationResult.Status == Model.Entity.ValidationStatus.Error) { diff --git a/AudioCuesheetEditor/Shared/ModalExportdialog.razor b/AudioCuesheetEditor/Shared/ModalExportdialog.razor index 9318493f..10d8231f 100644 --- a/AudioCuesheetEditor/Shared/ModalExportdialog.razor +++ b/AudioCuesheetEditor/Shared/ModalExportdialog.razor @@ -24,7 +24,6 @@ along with Foobar. If not, see @inject SessionStateContainer _sessionStateContainer @inject IBlazorDownloadFileService _blazorDownloadFileService @inject HotKeys _hotKeys -@inject IAudioConverterService _audioConverterService @@ -54,10 +53,6 @@ along with Foobar. If not, see @_localizer[nameof(Exportfile.Begin)] @_localizer[nameof(Exportfile.End)] @_localizer[nameof(Exportfile.Content)] - @if ((exportfiles != null) && (exportfiles.Any(x => x.ExportAudiofile != null))) - { - @_localizer[nameof(Exportfile.ExportAudiofile)] - } @@ -79,19 +74,6 @@ along with Foobar. If not, see - @if (exportfile.ExportAudiofile != null) - { - - - - - - } } } @@ -128,6 +110,7 @@ along with Foobar. If not, see @code { + //TODO: Export of cuesheet doesn't work (ApplicationOptions missing in ExportfileGenerator) public event EventHandler? GenerateExportfilesClicked; [Parameter] @@ -214,15 +197,13 @@ along with Foobar. If not, see hotKeysContext = _hotKeys.CreateContext() .Add(Key.Enter, OnEnterKeyDown); - _audioConverterService.ProgressChanged += IAudioConverterService_ProgressChanged; - ExportfileGenerator = new ExportfileGenerator(ExportType, _sessionStateContainer.Cuesheet, audioConverterService: _audioConverterService); + ExportfileGenerator = new ExportfileGenerator(ExportType, _sessionStateContainer.Cuesheet); await base.OnInitializedAsync(); } public void Dispose() { - _audioConverterService.ProgressChanged -= IAudioConverterService_ProgressChanged; hotKeysContext?.Dispose(); } @@ -252,7 +233,7 @@ along with Foobar. If not, see } } - async Task GenerateExportfiles_Clicked() + Task GenerateExportfiles_Clicked() { _logger.LogDebug("GenerateExportfiles_Clicked called"); if (ExportPossible) @@ -261,12 +242,13 @@ along with Foobar. If not, see exportProgress = 0; if (ExportfileGenerator != null) { - exportfiles = await ExportfileGenerator.GenerateExportfilesAsync(); + exportfiles = ExportfileGenerator.GenerateExportfiles(); selectedStep = "displayExportResult"; prepareExportCompleted = true; } exportProgress = null; } + return Task.CompletedTask; } bool NavigationAllowed(StepNavigationContext context) diff --git a/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs b/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs index a58f4c74..79bcb516 100644 --- a/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs +++ b/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs @@ -34,7 +34,7 @@ public class ExportfileGeneratorTests { [TestMethod()] - public async Task GenerateCuesheetFilesTestAsync() + public void GenerateCuesheetFilesTest() { var testHelper = new TestHelper(); Cuesheet cuesheet = new() @@ -57,7 +57,7 @@ public async Task GenerateCuesheetFilesTestAsync() cuesheet.AddTrack(track, testHelper.ApplicationOptions); } var generator = new ExportfileGenerator(ExportType.Cuesheet, cuesheet, applicationOptions: testHelper.ApplicationOptions); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); Assert.AreEqual(Exportfile.DefaultCuesheetFilename, generatedFiles.First().Name); var content = generatedFiles.First().Content; @@ -83,7 +83,7 @@ public async Task GenerateCuesheetFilesTestAsync() File.Delete(fileName); cuesheet.CDTextfile = new CDTextfile("Testfile.cdt"); cuesheet.Cataloguenumber.Value = "0123456789123"; - generatedFiles = await generator.GenerateExportfilesAsync(); + generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); content = generatedFiles.First().Content; Assert.IsNotNull(content); @@ -96,12 +96,12 @@ public async Task GenerateCuesheetFilesTestAsync() cuesheet.CDTextfile = new CDTextfile("Testfile.cdt"); cuesheet.Cataloguenumber.Value = "Testvalue"; Assert.AreEqual(ValidationStatus.Error, generator.Validate().Status); - generatedFiles = await generator.GenerateExportfilesAsync(); + generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(0, generatedFiles.Count); } [TestMethod()] - public async Task GenerateCuesheetFilesWithPreGapAndPostGapTestAsync() + public void GenerateCuesheetFilesWithPreGapAndPostGapTest() { var testHelper = new TestHelper(); Cuesheet cuesheet = new() @@ -132,7 +132,7 @@ public async Task GenerateCuesheetFilesWithPreGapAndPostGapTestAsync() cuesheet.AddTrack(track, testHelper.ApplicationOptions); } var generator = new ExportfileGenerator(ExportType.Cuesheet, cuesheet, applicationOptions: testHelper.ApplicationOptions); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); var content = generatedFiles.First().Content; Assert.IsNotNull(content); @@ -165,7 +165,7 @@ public async Task GenerateCuesheetFilesWithPreGapAndPostGapTestAsync() } [TestMethod()] - public async Task GenerateCuesheetFilesWithTrackFlagsTestAsync() + public void GenerateCuesheetFilesWithTrackFlagsTest() { var testHelper = new TestHelper(); Cuesheet cuesheet = new() @@ -194,7 +194,7 @@ public async Task GenerateCuesheetFilesWithTrackFlagsTestAsync() cuesheet.AddTrack(track, testHelper.ApplicationOptions); } var generator = new ExportfileGenerator(ExportType.Cuesheet, cuesheet, applicationOptions: testHelper.ApplicationOptions); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); var content = generatedFiles.First().Content; Assert.IsNotNull(content); @@ -221,7 +221,7 @@ public async Task GenerateCuesheetFilesWithTrackFlagsTestAsync() } [TestMethod()] - public async Task GenerateCuesheetFilesWithIncorrectTrackPositionsTestAsync() + public void GenerateCuesheetFilesWithIncorrectTrackPositionsTest() { var testHelper = new TestHelper(); Cuesheet cuesheet = new() @@ -254,7 +254,7 @@ public async Task GenerateCuesheetFilesWithIncorrectTrackPositionsTestAsync() cuesheet.Tracks.ElementAt(3).Position = 4; cuesheet.Tracks.ElementAt(4).Position = 5; Assert.AreEqual(ValidationStatus.Success, generator.Validate().Status); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); var content = generatedFiles.First().Content; Assert.IsNotNull(content); @@ -280,7 +280,7 @@ public async Task GenerateCuesheetFilesWithIncorrectTrackPositionsTestAsync() } [TestMethod()] - public async Task GenerateCuesheetFilesWithSplitPointsTestAsync() + public void GenerateCuesheetFilesWithSplitPointsTest() { var testHelper = new TestHelper(); Cuesheet cuesheet = new() @@ -315,9 +315,9 @@ public async Task GenerateCuesheetFilesWithSplitPointsTestAsync() splitPoint.Title = "Title 3"; splitPoint.Moment = new TimeSpan(1, 30, 0); testHelper.ApplicationOptions.CuesheetFilename = "Unit test.cue"; - var generator = new ExportfileGenerator(ExportType.Cuesheet, cuesheet, applicationOptions: testHelper.ApplicationOptions, audioConverterService:testHelper.AudioConverterService); + var generator = new ExportfileGenerator(ExportType.Cuesheet, cuesheet, applicationOptions: testHelper.ApplicationOptions); Assert.AreEqual(ValidationStatus.Success, generator.Validate().Status); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(5, generatedFiles.Count); var position = 1; var counter = 1; @@ -381,9 +381,9 @@ public async Task GenerateCuesheetFilesWithSplitPointsTestAsync() position--; } } - + [TestMethod()] - public async Task GenerateExportfilesTestAsync() + public void GenerateExportfilesTest() { var testHelper = new TestHelper(); //Prepare cuesheet @@ -428,7 +428,7 @@ public async Task GenerateExportfilesTestAsync() }; Assert.AreEqual(ValidationStatus.Success, exportProfile.Validate().Status); var generator = new ExportfileGenerator(ExportType.Exportprofile, cuesheet, exportprofile: exportProfile); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); Assert.AreEqual(exportProfile.Filename, generatedFiles.First().Name); var fileContent = generatedFiles.First().Content; @@ -461,7 +461,7 @@ public async Task GenerateExportfilesTestAsync() }; Assert.AreEqual(ValidationStatus.Success, exportProfile.Validate().Status); generator.Exportprofile = exportProfile; - generatedFiles = await generator.GenerateExportfilesAsync(); + generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); Assert.AreEqual(exportProfile.Filename, generatedFiles.First().Name); fileContent = generatedFiles.First().Content; @@ -495,7 +495,7 @@ public async Task GenerateExportfilesTestAsync() }; Assert.AreEqual(ValidationStatus.Success, exportProfile.Validate().Status); generator.Exportprofile = exportProfile; - generatedFiles = await generator.GenerateExportfilesAsync(); + generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); Assert.AreEqual(exportProfile.Filename, generatedFiles.First().Name); fileContent = generatedFiles.First().Content; @@ -520,7 +520,7 @@ public async Task GenerateExportfilesTestAsync() } [TestMethod()] - public async Task GenerateExportfilesWithPregapAndPostgapTestAsync() + public void GenerateExportfilesWithPregapAndPostgapTest() { var testHelper = new TestHelper(); //Prepare cuesheet @@ -566,7 +566,7 @@ public async Task GenerateExportfilesWithPregapAndPostgapTestAsync() }; Assert.AreEqual(ValidationStatus.Success, exportProfile.Validate().Status); var generator = new ExportfileGenerator(ExportType.Exportprofile, cuesheet, exportprofile: exportProfile); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(1, generatedFiles.Count); Assert.AreEqual(exportProfile.Filename, generatedFiles.First().Name); var fileContent = generatedFiles.First().Content; @@ -586,7 +586,7 @@ public async Task GenerateExportfilesWithPregapAndPostgapTestAsync() } [TestMethod()] - public async Task GenerateExportfilesWithSplitPointsTestAsync() + public void GenerateExportfilesWithSplitPointsTest() { var testHelper = new TestHelper(); //Prepare cuesheet @@ -641,9 +641,9 @@ public async Task GenerateExportfilesWithSplitPointsTestAsync() SchemeTracks = "%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%", SchemeFooter = "Exported %Cuesheet.Title% from %Cuesheet.Artist% using AudioCuesheetEditor" }; - var generator = new ExportfileGenerator(ExportType.Exportprofile, cuesheet, exportProfile, audioConverterService: testHelper.AudioConverterService); + var generator = new ExportfileGenerator(ExportType.Exportprofile, cuesheet, exportProfile); Assert.AreEqual(ValidationStatus.Success, generator.Validate().Status); - var generatedFiles = await generator.GenerateExportfilesAsync(); + var generatedFiles = generator.GenerateExportfiles(); Assert.AreEqual(5, generatedFiles.Count); //Check split according to split points diff --git a/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs b/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs deleted file mode 100644 index 4176f28f..00000000 --- a/AudioCuesheetEditorTests/Utility/AudioConverterServiceUnitTest.cs +++ /dev/null @@ -1,33 +0,0 @@ -//This file is part of AudioCuesheetEditor. - -//AudioCuesheetEditor is free software: you can redistribute it and/or modify -//it under the terms of the GNU General Public License as published by -//the Free Software Foundation, either version 3 of the License, or -//(at your option) any later version. - -//AudioCuesheetEditor is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. - -//You should have received a copy of the GNU General Public License -//along with Foobar. If not, see -//. -using AudioCuesheetEditor.Model.IO.Audio; -using System; -using System.Threading.Tasks; - -namespace AudioCuesheetEditorTests.Utility -{ - internal class AudioConverterServiceUnitTest : IAudioConverterService - { - public event EventHandler? ProgressChanged; - - public Task SplitAudiofileAsync(Audiofile audiofile, TimeSpan from, TimeSpan? to = null) - { - ProgressChanged?.Invoke(this, 100); - // This implementation does nothing with audio processing, so we only return some fake data - return Task.FromResult(null); - } - } -} diff --git a/AudioCuesheetEditorTests/Utility/TestHelper.cs b/AudioCuesheetEditorTests/Utility/TestHelper.cs index ed78cda4..e5776f9c 100644 --- a/AudioCuesheetEditorTests/Utility/TestHelper.cs +++ b/AudioCuesheetEditorTests/Utility/TestHelper.cs @@ -31,11 +31,9 @@ public TestHelper() { LinkTracksWithPreviousOne = false }; - AudioConverterService = new AudioConverterServiceUnitTest(); } public ApplicationOptions ApplicationOptions { get; private set; } - public IAudioConverterService AudioConverterService { get; private set; } public static ILogger CreateLogger() { var serviceProvider = new ServiceCollection() From 5fc13e2378703c90baabbdbe49ca156d142ed9b1 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:35:15 +0200 Subject: [PATCH 05/11] Update ExportfileGenerator.cs --- AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs index ac3a4a5b..f4c2833b 100644 --- a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs @@ -350,7 +350,7 @@ protected override ValidationResult Validate(string property) } else { - validationResult = ValidationResult.Create(ValidationStatus.Success); + validationResult = ApplicationOptions.Validate(x => x.CuesheetFilename); } } else From 04318d6810297973d6d987265ca90543c31e87f9 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:44:01 +0200 Subject: [PATCH 06/11] Update SessionStateContainer.cs --- .../Extensions/SessionStateContainer.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/AudioCuesheetEditor/Extensions/SessionStateContainer.cs b/AudioCuesheetEditor/Extensions/SessionStateContainer.cs index 9bfb0a2c..d46385f6 100644 --- a/AudioCuesheetEditor/Extensions/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Extensions/SessionStateContainer.cs @@ -118,18 +118,6 @@ public Audiofile? ImportAudiofile } } - private void TextImportScheme_AnalysisFinished(object? sender, EventArgs eventArgs) - { - if (textImportFile != null) - { - ImportCuesheet = textImportFile.Cuesheet; - } - else - { - ImportCuesheet = null; - } - } - public ViewMode CurrentViewMode { get { return currentViewMode; } @@ -166,7 +154,17 @@ private void SetCuesheetReference(Cuesheet value) _traceChangeManager.TraceChanges(Cuesheet); CuesheetChanged?.Invoke(this, EventArgs.Empty); } - + private void TextImportScheme_AnalysisFinished(object? sender, EventArgs eventArgs) + { + if (textImportFile != null) + { + ImportCuesheet = textImportFile.Cuesheet; + } + else + { + ImportCuesheet = null; + } + } private void Cuesheet_CuesheetImported(object? sender, EventArgs e) { CuesheetChanged?.Invoke(this, EventArgs.Empty); From 98face0951e87901e5e6386faa5e5926e7517666 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:50:44 +0200 Subject: [PATCH 07/11] Fixes export dialog --- AudioCuesheetEditor/Shared/MainLayout.razor | 12 ++------ .../Shared/ModalExportdialog.razor | 30 +++++++++++-------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/AudioCuesheetEditor/Shared/MainLayout.razor b/AudioCuesheetEditor/Shared/MainLayout.razor index 1e8fe17a..05a3cf61 100644 --- a/AudioCuesheetEditor/Shared/MainLayout.razor +++ b/AudioCuesheetEditor/Shared/MainLayout.razor @@ -766,9 +766,9 @@ along with Foobar. If not, see _logger.LogInformation("SelectedExportProfileChanged with {0}", newValue); selectedExportProfileId = newValue; modalExportdialogExportprofile?.Validations?.ValidateAll().GetAwaiter().GetResult(); - if ((modalExportdialogExportprofile != null) && (modalExportdialogExportprofile.ExportfileGenerator != null)) + if (modalExportdialogExportprofile != null) { - modalExportdialogExportprofile.ExportfileGenerator.Exportprofile = SelectedExportProfile; + modalExportdialogExportprofile.SelectedExportProfile = SelectedExportProfile; modalExportdialogExportprofile.Reset(); } StateHasChanged(); @@ -797,19 +797,11 @@ along with Foobar. If not, see void ModalExportdialogExportprofile_GenerateExportfilesClicked(object? sender, EventArgs args) { Task.Run(SaveExportProfiles); - if ((modalExportdialogExportprofile != null) && (modalExportdialogExportprofile.ExportfileGenerator != null)) - { - modalExportdialogExportprofile.ExportfileGenerator.Exportprofile = SelectedExportProfile; - } } void ModalExportdialogCuesheet_GenerateExportfilesClicked(object? sender, EventArgs args) { Task.Run(SaveApplicationOptions); - if ((modalExportdialogCuesheet != null) && (modalExportdialogCuesheet.ExportfileGenerator != null)) - { - modalExportdialogCuesheet.ExportfileGenerator.ApplicationOptions = applicationOptions; - } } Task OnApplicationOptionsCuesheetFilenameChanged(string value) diff --git a/AudioCuesheetEditor/Shared/ModalExportdialog.razor b/AudioCuesheetEditor/Shared/ModalExportdialog.razor index 10d8231f..0940e47e 100644 --- a/AudioCuesheetEditor/Shared/ModalExportdialog.razor +++ b/AudioCuesheetEditor/Shared/ModalExportdialog.razor @@ -110,7 +110,6 @@ along with Foobar. If not, see @code { - //TODO: Export of cuesheet doesn't work (ApplicationOptions missing in ExportfileGenerator) public event EventHandler? GenerateExportfilesClicked; [Parameter] @@ -125,9 +124,10 @@ along with Foobar. If not, see [EditorRequired] public ExportType ExportType { get; set; } + public Exportprofile? SelectedExportProfile{ get; set; } + public Boolean IsVisible { get; private set; } public Validations? Validations { get; private set; } - public ExportfileGenerator? ExportfileGenerator { get; private set; } public Boolean LockUserInputs { get => exportProgress != null; } Modal? modalExportdialog; @@ -136,6 +136,7 @@ along with Foobar. If not, see Boolean prepareExportCompleted = false; HotKeysContext? hotKeysContext; int? exportProgress; + ApplicationOptions? applicationOptions; Boolean StepNavigationAllowed { @@ -162,7 +163,8 @@ along with Foobar. If not, see { get { - var validationResult = ExportfileGenerator?.Validate(); + var generator = new ExportfileGenerator(ExportType, _sessionStateContainer.Cuesheet, SelectedExportProfile, applicationOptions); + var validationResult = generator.Validate(); if (validationResult?.Status == Model.Entity.ValidationStatus.Error) { string? detailText = null; @@ -197,7 +199,8 @@ along with Foobar. If not, see hotKeysContext = _hotKeys.CreateContext() .Add(Key.Enter, OnEnterKeyDown); - ExportfileGenerator = new ExportfileGenerator(ExportType, _sessionStateContainer.Cuesheet); + applicationOptions = await _localStorageOptionsProvider.GetOptions(); + _localStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved; await base.OnInitializedAsync(); } @@ -205,6 +208,7 @@ along with Foobar. If not, see public void Dispose() { hotKeysContext?.Dispose(); + _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; } public async Task Show() @@ -240,12 +244,10 @@ along with Foobar. If not, see { GenerateExportfilesClicked?.Invoke(this, EventArgs.Empty); exportProgress = 0; - if (ExportfileGenerator != null) - { - exportfiles = ExportfileGenerator.GenerateExportfiles(); - selectedStep = "displayExportResult"; - prepareExportCompleted = true; - } + var generator = new ExportfileGenerator(ExportType, _sessionStateContainer.Cuesheet, SelectedExportProfile, applicationOptions); + exportfiles = generator.GenerateExportfiles(); + selectedStep = "displayExportResult"; + prepareExportCompleted = true; exportProgress = null; } return Task.CompletedTask; @@ -281,9 +283,11 @@ along with Foobar. If not, see } } - void IAudioConverterService_ProgressChanged(object? sender, int progress) + void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions options) { - exportProgress = progress; - InvokeAsync(StateHasChanged); + if (options is ApplicationOptions) + { + applicationOptions = (ApplicationOptions)options; + } } } From 33c1bfb63a03c5a48e3b8acc08cfc6da64d05392 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 3 Apr 2024 08:25:38 +0200 Subject: [PATCH 08/11] Remove headers for ffmpeg wasm --- netlify.toml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/netlify.toml b/netlify.toml index fc5ce0b8..ff1c0508 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,9 +1,4 @@ [[redirects]] from = "/*" to = "/index.html" - status = 200 -[[headers]] - for = "/*" - [headers.values] - Cross-Origin-Opener-Policy = "same-origin" - Cross-Origin-Embedder-Policy = "require-corp" \ No newline at end of file + status = 200 \ No newline at end of file From ac628a5a4b097a5de76881935c7b20f594289376 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 3 Apr 2024 08:40:45 +0200 Subject: [PATCH 09/11] Generate export files with begin and end --- .../Model/IO/Export/ExportfileGenerator.cs | 15 +++++++++++---- .../Model/IO/Export/ExportfileGeneratorTests.cs | 8 ++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs index f4c2833b..50f4d964 100644 --- a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs @@ -47,13 +47,13 @@ public ExportfileGenerator(ExportType exportType, Cuesheet cuesheet, Exportprofi public IReadOnlyCollection GenerateExportfiles() { - //TODO: Generate export files with start 00:00:00 and each end set correctly! List exportfiles = new(); if (Validate().Status != ValidationStatus.Error) { if (Cuesheet.SplitPoints.Count != 0) { TimeSpan? previousSplitPointMoment = null; + var begin = Cuesheet.Tracks.Min(x => x.Begin); var counter = 1; String? content = null; String filename = String.Empty; @@ -79,7 +79,11 @@ public IReadOnlyCollection GenerateExportfiles() } if (content != null) { - exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment, End = splitPoint.Moment }); + if (previousSplitPointMoment != null) + { + begin = previousSplitPointMoment; + } + exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = begin, End = splitPoint.Moment }); } previousSplitPointMoment = splitPoint.Moment; counter++; @@ -103,7 +107,8 @@ public IReadOnlyCollection GenerateExportfiles() } if (content != null) { - exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment }); + var end = Cuesheet.Tracks.Max(x => x.End); + exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = previousSplitPointMoment, End = end }); } } else @@ -140,7 +145,9 @@ public IReadOnlyCollection GenerateExportfiles() } if (content != null) { - exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content) }); + var begin = Cuesheet.Tracks.Min(x => x.Begin); + var end = Cuesheet.Tracks.Max(x => x.End); + exportfiles.Add(new Exportfile() { Name = filename, Content = Encoding.UTF8.GetBytes(content), Begin = begin, End = end }); } } } diff --git a/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs b/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs index 79bcb516..d1bf57d4 100644 --- a/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs +++ b/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs @@ -322,7 +322,7 @@ public void GenerateCuesheetFilesWithSplitPointsTest() var position = 1; var counter = 1; //Check split according to split points - Assert.IsNull(generatedFiles.First().Begin); + Assert.AreEqual(cuesheet.Tracks.Min(x => x.Begin), generatedFiles.First().Begin); Assert.AreEqual(new TimeSpan(0, 30, 0), generatedFiles.First().End); Assert.AreEqual(new TimeSpan(0, 30, 0), generatedFiles.ElementAt(1).Begin); Assert.AreEqual(new TimeSpan(1, 0, 0), generatedFiles.ElementAt(1).End); @@ -331,7 +331,7 @@ public void GenerateCuesheetFilesWithSplitPointsTest() Assert.AreEqual(new TimeSpan(1, 30, 0), generatedFiles.ElementAt(3).Begin); Assert.AreEqual(new TimeSpan(2, 0, 0), generatedFiles.ElementAt(3).End); Assert.AreEqual(new TimeSpan(2, 0, 0), generatedFiles.ElementAt(4).Begin); - Assert.IsNull(generatedFiles.Last().End); + Assert.AreEqual(cuesheet.Tracks.Max(x => x.End), generatedFiles.Last().End); foreach (var generatedFile in generatedFiles) { Assert.AreEqual(String.Format("Unit test({0}).cue", counter), generatedFile.Name); @@ -647,7 +647,7 @@ public void GenerateExportfilesWithSplitPointsTest() Assert.AreEqual(5, generatedFiles.Count); //Check split according to split points - Assert.IsNull(generatedFiles.First().Begin); + Assert.AreEqual(cuesheet.Tracks.Min(x => x.Begin), generatedFiles.First().Begin); Assert.AreEqual(new TimeSpan(0, 30, 0), generatedFiles.First().End); Assert.AreEqual(new TimeSpan(0, 30, 0), generatedFiles.ElementAt(1).Begin); Assert.AreEqual(new TimeSpan(1, 0, 0), generatedFiles.ElementAt(1).End); @@ -656,7 +656,7 @@ public void GenerateExportfilesWithSplitPointsTest() Assert.AreEqual(new TimeSpan(1, 30, 0), generatedFiles.ElementAt(3).Begin); Assert.AreEqual(new TimeSpan(2, 0, 0), generatedFiles.ElementAt(3).End); Assert.AreEqual(new TimeSpan(2, 0, 0), generatedFiles.ElementAt(4).Begin); - Assert.IsNull(generatedFiles.Last().End); + Assert.AreEqual(cuesheet.Tracks.Max(x => x.End), generatedFiles.Last().End); var counter = 1; var position = 1; foreach (var generatedFile in generatedFiles) From b508b96d8386a44b14ada54b64a379f8fbec9ee1 Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:21:36 +0200 Subject: [PATCH 10/11] Model and UI changes for audiofile for splitpoints --- .../Model/IO/Export/ExportfileGenerator.cs | 1 + .../Model/IO/Export/SplitPoint.cs | 23 +++++- .../Pages/EditSplitpoints.razor | 73 +++++++++++++++++++ .../Localization/EditSplitpoints/de.json | 7 +- .../Localization/EditSplitpoints/en.json | 7 +- .../Localization/ValidationMessage/de.json | 3 +- .../Localization/ValidationMessage/en.json | 3 +- 7 files changed, 112 insertions(+), 5 deletions(-) diff --git a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs index 50f4d964..12cef661 100644 --- a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs @@ -57,6 +57,7 @@ public IReadOnlyCollection GenerateExportfiles() var counter = 1; String? content = null; String filename = String.Empty; + //TODO String audioFileName = String.Empty; foreach (var splitPoint in Cuesheet.SplitPoints.OrderBy(x => x.Moment)) { diff --git a/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs b/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs index 15a332e4..78e782c7 100644 --- a/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs +++ b/AudioCuesheetEditor/Model/IO/Export/SplitPoint.cs @@ -22,11 +22,11 @@ namespace AudioCuesheetEditor.Model.IO.Export { public class SplitPoint : Validateable, ITraceable { - //TODO: Add audio file name as property to be set by user private Cuesheet? cuesheet; private TimeSpan? moment; private String? artist; private String? title; + private String? audiofileName; public event EventHandler? TraceablePropertyChanged; @@ -35,6 +35,7 @@ public SplitPoint(Cuesheet cuesheet) Cuesheet = cuesheet; artist = Cuesheet.Artist; title = Cuesheet.Title; + audiofileName = Cuesheet.Audiofile?.Name; } [JsonConstructor] @@ -91,6 +92,18 @@ public TimeSpan? Moment } } + public String? AudiofileName + { + get => audiofileName; + set + { + var previousValue = audiofileName; + audiofileName = value; + OnValidateablePropertyChanged(nameof(AudiofileName)); + OnTraceablePropertyChanged(previousValue, nameof(AudiofileName)); + } + } + public void CopyValues(SplitPoint splitPoint) { Artist = splitPoint.Artist; @@ -137,6 +150,14 @@ protected override ValidationResult Validate(string property) validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Title))); } break; + case nameof(AudiofileName): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(AudiofileName)) + { + validationMessages ??= new(); + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(AudiofileName))); + } + break; } return ValidationResult.Create(validationStatus, validationMessages); } diff --git a/AudioCuesheetEditor/Pages/EditSplitpoints.razor b/AudioCuesheetEditor/Pages/EditSplitpoints.razor index c81913fa..c551484b 100644 --- a/AudioCuesheetEditor/Pages/EditSplitpoints.razor +++ b/AudioCuesheetEditor/Pages/EditSplitpoints.razor @@ -23,6 +23,7 @@ along with Foobar. If not, see @inject DateTimeUtility _dateTimeUtility @inject ITextLocalizerService _localizationService @inject TraceChangeManager _traceChangeManager +@inject IJSRuntime _jsRuntime @if (Cuesheet != null) @@ -51,6 +52,7 @@ along with Foobar. If not, see @_localizer["Moment"] @_localizer["CD artist"] @_localizer["CD title"] + @_localizer["Audiofile name"] @@ -99,6 +101,33 @@ along with Foobar. If not, see + + + @if (String.IsNullOrEmpty(splitPoint.AudiofileName)) + { + x.MimeType))" Changed="(args) => OnSplitpointAudiofileChanged(args, splitPoint)" AutoReset="false"> + + + + + } + else + { + + + + + + + + + + + + + } + + } @@ -106,8 +135,13 @@ along with Foobar. If not, see } + + @code { Validations? validations; + ModalDialog? modalDialog; + Validation? audiofileValidation; + Dictionary fileEditAudiofileIds = new(); public Cuesheet? Cuesheet { @@ -172,6 +206,7 @@ along with Foobar. If not, see { var splitPoint = Cuesheet.AddSplitPoint(); _traceChangeManager.TraceChanges(splitPoint); + fileEditAudiofileIds.Add(splitPoint, Guid.NewGuid()); } return Task.CompletedTask; } @@ -229,4 +264,42 @@ along with Foobar. If not, see { StateHasChanged(); } + + async Task OnSplitpointAudiofileChangedCliccked(SplitPoint splitPoint) + { + splitPoint.AudiofileName = null; + StateHasChanged(); + await Task.Delay(1); + await _jsRuntime.InvokeVoidAsync("triggerClick", fileEditAudiofileIds[splitPoint]); + } + + async Task OnSplitpointAudiofileChanged(FileChangedEventArgs e, SplitPoint splitPoint) + { + if (e.Files.FirstOrDefault() != null) + { + if (Cuesheet != null) + { + var file = e.Files.First(); + if (IOUtility.CheckFileMimeTypeForAudioCodec(file) == true) + { + splitPoint.AudiofileName = file.Name; + } + else + { + if (modalDialog != null) + { + modalDialog.Title = _localizer["Error"]; + modalDialog.Text = String.Format(_localizer["The file {0} can not be used for operation: {1}. The file is invalid, please use a valid file!"], file.Name, _localizer["Audiofile"]); + modalDialog.ModalSize = ModalSize.Small; + modalDialog.Mode = ModalDialog.DialogMode.Alert; + await modalDialog.ShowModal(); + } + } + } + } + if (audiofileValidation != null) + { + await audiofileValidation.ValidateAsync(); + } + } } diff --git a/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/de.json b/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/de.json index 7a92f7c6..1ade6c3a 100644 --- a/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/de.json +++ b/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/de.json @@ -6,6 +6,11 @@ "Moment": "Zeitpunkt", "Delete split tooltip": "Löscht diesen Aufteilungspunkt", "CD artist": "CD Künstler", - "CD title": "CD Titel" + "CD title": "CD Titel", + "Audiofile name": "Audiodatei", + "Error": "Fehler", + "The file {0} can not be used for operation: {1}. The file is invalid, please use a valid file!": "Die Datei {0} kann nicht für folgende Operation genutzt werden: {1}. Die Datei ist ungültig, bitte verwenden Sie eine gültige Datei!", + "Audiofile": "Audiofile", + "Change": "Ändern" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/en.json b/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/en.json index 1642de6b..7256528d 100644 --- a/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/en.json +++ b/AudioCuesheetEditor/Resources/Localization/EditSplitpoints/en.json @@ -6,6 +6,11 @@ "Moment": "Moment", "Delete split tooltip": "Deletes this split point", "CD artist": "CD artist", - "CD title": "CD title" + "CD title": "CD title", + "Audiofile name": "Audiofile", + "Error": "Error", + "The file {0} can not be used for operation: {1}. The file is invalid, please use a valid file!": "The file {0} can not be used for operation: {1}. The file is invalid, please use a valid file!", + "Audiofile": "Audiofile", + "Change": "Change" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json index c4a91e06..afdb290e 100644 --- a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json +++ b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/de.json @@ -39,6 +39,7 @@ "Artist": "Künstler", "Title": "Titel", "Exportprofile": "Exportprofil", - "ApplicationOptions": "Applikationsoptionen" + "ApplicationOptions": "Applikationsoptionen", + "AudiofileName": "Audiodatei" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json index d08f0bd6..309d5fe4 100644 --- a/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json +++ b/AudioCuesheetEditor/Resources/Localization/ValidationMessage/en.json @@ -39,6 +39,7 @@ "Artist": "Artist", "Title": "Title", "Exportprofile": "Exportprofile", - "ApplicationOptions": "Application options" + "ApplicationOptions": "Application options", + "AudiofileName": "Audiofile" } } \ No newline at end of file From e195cb7aa3be89a863a716edbb2187afacad722d Mon Sep 17 00:00:00 2001 From: NeoCoderMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:55:17 +0200 Subject: [PATCH 11/11] use splitpoint audio file name --- .../Model/IO/Export/ExportfileGenerator.cs | 9 ++++----- .../Model/IO/Export/ExportfileGeneratorTests.cs | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs index 12cef661..ac448d0d 100644 --- a/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Model/IO/Export/ExportfileGenerator.cs @@ -57,11 +57,10 @@ public IReadOnlyCollection GenerateExportfiles() var counter = 1; String? content = null; String filename = String.Empty; - //TODO - String audioFileName = String.Empty; + String? audioFileName = null; foreach (var splitPoint in Cuesheet.SplitPoints.OrderBy(x => x.Moment)) { - audioFileName = String.Format("{0}({1}){2}", Path.GetFileNameWithoutExtension(Cuesheet.Audiofile?.Name), counter, Path.GetExtension(Cuesheet.Audiofile?.Name)); + audioFileName = splitPoint.AudiofileName; if (splitPoint.Validate().Status == ValidationStatus.Success) { switch (ExportType) @@ -155,7 +154,7 @@ public IReadOnlyCollection GenerateExportfiles() return exportfiles; } - private string WriteCuesheet(String audiofileName, TimeSpan? from = null, SplitPoint? splitPoint = null) + private string WriteCuesheet(String? audiofileName, TimeSpan? from = null, SplitPoint? splitPoint = null) { var builder = new StringBuilder(); if (Cuesheet.Cataloguenumber != null && string.IsNullOrEmpty(Cuesheet.Cataloguenumber.Value) == false && Cuesheet.Cataloguenumber.Validate().Status != ValidationStatus.Error) @@ -231,7 +230,7 @@ private string WriteCuesheet(String audiofileName, TimeSpan? from = null, SplitP return builder.ToString(); } - private String WriteExport(String audiofileName, TimeSpan? from = null, SplitPoint? splitPoint = null) + private String WriteExport(String? audiofileName, TimeSpan? from = null, SplitPoint? splitPoint = null) { var builder = new StringBuilder(); if (Exportprofile != null) diff --git a/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs b/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs index d1bf57d4..a06551f6 100644 --- a/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs +++ b/AudioCuesheetEditorTests/Model/IO/Export/ExportfileGeneratorTests.cs @@ -305,14 +305,17 @@ public void GenerateCuesheetFilesWithSplitPointsTest() var splitPoint = cuesheet.AddSplitPoint(); splitPoint.Moment = new TimeSpan(2, 0, 0); splitPoint.Title = "Last part"; + splitPoint.AudiofileName = "Last part.mp3"; splitPoint = cuesheet.AddSplitPoint(); splitPoint.Moment = new TimeSpan(0, 30, 0); + splitPoint.AudiofileName = "First part.mp3"; splitPoint = cuesheet.AddSplitPoint(); splitPoint.Moment = new TimeSpan(1, 0, 0); splitPoint.Artist = "Demo Artist Part2"; splitPoint = cuesheet.AddSplitPoint(); splitPoint.Artist = "Artist 3"; splitPoint.Title = "Title 3"; + splitPoint.AudiofileName = "Part 3.mp3"; splitPoint.Moment = new TimeSpan(1, 30, 0); testHelper.ApplicationOptions.CuesheetFilename = "Unit test.cue"; var generator = new ExportfileGenerator(ExportType.Cuesheet, cuesheet, applicationOptions: testHelper.ApplicationOptions); @@ -349,11 +352,14 @@ public void GenerateCuesheetFilesWithSplitPointsTest() { Assert.AreEqual(String.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, splitPointForThisFile.Title), fileContent.First()); Assert.AreEqual(String.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, splitPointForThisFile.Artist), fileContent[1]); + Assert.AreEqual(String.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, splitPointForThisFile.AudiofileName, cuesheet.Audiofile?.AudioFileType), fileContent[2]); } else { Assert.AreEqual(String.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, cuesheet.Title), fileContent.First()); Assert.AreEqual(String.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, cuesheet.Artist), fileContent[1]); + var cuesheetFileName = String.Format("{0}({1}){2}", Path.GetFileNameWithoutExtension(cuesheet.Audiofile?.Name), counter - 1, Path.GetExtension(cuesheet.Audiofile?.Name)); + Assert.AreEqual(String.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, cuesheetFileName, cuesheet.Audiofile?.AudioFileType), fileContent[2]); } //Check for start from position 1 and begin = 00:00:00 for (int i = 3; i < fileContent.Length; i += 4) @@ -621,23 +627,25 @@ public void GenerateExportfilesWithSplitPointsTest() cuesheet.Cataloguenumber.Value = "0123456789123"; cuesheet.CDTextfile = new CDTextfile("Testfile.cdt"); - var splitPoint = cuesheet.AddSplitPoint(); splitPoint.Moment = new TimeSpan(2, 0, 0); splitPoint.Title = "Last part"; + splitPoint.AudiofileName = "Last part.mp3"; splitPoint = cuesheet.AddSplitPoint(); splitPoint.Moment = new TimeSpan(0, 30, 0); + splitPoint.AudiofileName = "First part.mp3"; splitPoint = cuesheet.AddSplitPoint(); splitPoint.Moment = new TimeSpan(1, 0, 0); splitPoint.Artist = "Demo Artist Part2"; splitPoint = cuesheet.AddSplitPoint(); splitPoint.Artist = "Artist 3"; splitPoint.Title = "Title 3"; + splitPoint.AudiofileName = "Part 3.mp3"; splitPoint.Moment = new TimeSpan(1, 30, 0); //Test export var exportProfile = new Exportprofile { - SchemeHead = "%Cuesheet.Artist%;%Cuesheet.Title%;%Cuesheet.Cataloguenumber%;%Cuesheet.CDTextfile%", + SchemeHead = "%Cuesheet.Artist%;%Cuesheet.Title%;%Cuesheet.Audiofile%;%Cuesheet.Cataloguenumber%;%Cuesheet.CDTextfile%", SchemeTracks = "%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%", SchemeFooter = "Exported %Cuesheet.Title% from %Cuesheet.Artist% using AudioCuesheetEditor" }; @@ -674,11 +682,12 @@ public void GenerateExportfilesWithSplitPointsTest() var splitPointForThisFile = cuesheet.SplitPoints.FirstOrDefault(x => x.Moment == generatedFile.End); if (splitPointForThisFile != null) { - Assert.AreEqual(String.Format("{0};{1};0123456789123;Testfile.cdt", splitPointForThisFile.Artist, splitPointForThisFile.Title), fileContent[0]); + Assert.AreEqual(String.Format("{0};{1};{2};0123456789123;Testfile.cdt", splitPointForThisFile.Artist, splitPointForThisFile.Title, splitPointForThisFile.AudiofileName), fileContent[0]); } else { - Assert.AreEqual(String.Format("{0};{1};0123456789123;Testfile.cdt", cuesheet.Artist, cuesheet.Title), fileContent[0]); + var audiofileName = String.Format("{0}({1}){2}", Path.GetFileNameWithoutExtension(cuesheet.Audiofile?.Name), counter - 1, Path.GetExtension(cuesheet.Audiofile?.Name)); + Assert.AreEqual(String.Format("{0};{1};{2};0123456789123;Testfile.cdt", cuesheet.Artist, cuesheet.Title, audiofileName), fileContent[0]); } //Check for start from position 1 and begin = 00:00:00 for (int i = 1; i < fileContent.Length - 1; i++)