From 0249c46ca84f7d0dfb49bce5c90597e961dd6615 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 29 May 2026 11:13:38 +0200 Subject: [PATCH 001/132] initialize correctly --- .../Extensions/WebAssemblyHostExtension.cs | 6 ++++++ AudioCuesheetEditor/Program.cs | 11 ++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs b/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs index 11e24d17..6cc603bf 100644 --- a/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs +++ b/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs @@ -25,5 +25,11 @@ public async static Task SetCultureFromConfigurationAsync(this WebAssemblyHost h var localizationService = host.Services.GetRequiredService(); await localizationService.SetCultureFromConfigurationAsync(); } + + public async static Task InitializeSessionStateContainer(this WebAssemblyHost host) + { + var sessionStateContainer = host.Services.GetRequiredService(); + await sessionStateContainer.InitializeAsync(); + } } } diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs index 031766d3..9618bf0c 100644 --- a/AudioCuesheetEditor/Program.cs +++ b/AudioCuesheetEditor/Program.cs @@ -48,14 +48,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); - -builder.Services.AddScoped(x => -{ - var localStorageOptionsProvider = x.GetRequiredService(); - var sessionStateContainer = new SessionStateContainer(localStorageOptionsProvider); - _ = sessionStateContainer.InitializeAsync(); - return sessionStateContainer; -}); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -83,5 +76,5 @@ var host = builder.Build(); await host.SetCultureFromConfigurationAsync(); - +await host.InitializeSessionStateContainer(); await host.RunAsync(); \ No newline at end of file From 236ea995e0dd3769a0b003db60e406efef1b374a Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 29 May 2026 15:56:39 +0200 Subject: [PATCH 002/132] first step towards multiple files --- .../Model/AudioCuesheet/Cuesheet.cs | 11 +- .../Model/IO/Audio/Audiofile.cs | 59 ++++----- .../Model/IO/Export/Exportprofile.cs | 6 +- .../Model/IO/Import/Importprofile.cs | 4 +- AudioCuesheetEditor/Pages/Index.razor | 3 +- AudioCuesheetEditor/Program.cs | 1 + .../Services/Audio/PlaybackService.cs | 89 +++++++------ .../AudioCuesheet/AudiofileManager.cs | 77 +++++++++++ .../Services/AudioCuesheet/CuesheetManager.cs | 31 +++-- .../AudioCuesheet/IAudiofileManager.cs | 31 +++++ .../Services/IO/CuesheetExportService.cs | 12 +- .../Services/IO/ExportfileGenerator.cs | 9 +- .../Services/IO/FileInputManager.cs | 9 +- .../Services/IO/IFileInputManager.cs | 6 + .../Services/IO/ImportManager.cs | 12 +- .../Shared/Cuesheet/Audiofiles.de.resx | 120 ++++++++++++++++++ .../Shared/Cuesheet/Audiofiles.razor | 72 +++++++++++ .../Shared/Cuesheet/Audiofiles.resx | 120 ++++++++++++++++++ .../Shared/Cuesheet/CuesheetData.razor | 30 +++-- .../Shared/ViewModes/ViewModeFull.de.resx | 4 +- .../Shared/ViewModes/ViewModeFull.razor | 8 +- .../Shared/ViewModes/ViewModeFull.resx | 4 +- 22 files changed, 579 insertions(+), 139 deletions(-) create mode 100644 AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs create mode 100644 AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs create mode 100644 AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx create mode 100644 AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor create mode 100644 AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs index 501f90cf..d8696bde 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs @@ -21,6 +21,7 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet { public class Cuesheet() : Validateable, ICuesheet { + //TODO: Move tracks below audiofiles [JsonInclude] public IEnumerable Tracks { get; set; } = []; @@ -28,7 +29,7 @@ public class Cuesheet() : Validateable, ICuesheet public String? Title { get; set; } - public Audiofile? Audiofile { get; set; } + public ICollection Audiofiles { get; set; } = []; public CDTextfile? CDTextfile { get; set; } @@ -51,7 +52,7 @@ public override ValidationResult Validate(string property) if (!Tracks.Any()) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has invalid Count ({1})!", nameof(Tracks), 0)); + validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Tracks), 0)); } else { @@ -86,12 +87,12 @@ public override ValidationResult Validate(string property) } } break; - case nameof(Audiofile): + case nameof(Audiofiles): validationStatus = ValidationStatus.Success; - if (Audiofile == null) + if (Audiofiles.Count == 0) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Audiofile))); + validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Audiofiles), 0)); } break; case nameof(Artist): diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index b6d86c42..7601a716 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -17,8 +17,7 @@ namespace AudioCuesheetEditor.Model.IO.Audio { - [method: JsonConstructor] - public class Audiofile(String name) + public class Audiofile() { public static readonly AudioCodec AudioCodecWEBM = new("audio/webm", ".webm", "AudioCodec WEBM"); @@ -34,9 +33,15 @@ public class Audiofile(String name) new AudioCodec("audio/flac", ".flac", "AudioCodec FLAC") ]; - private AudioCodec? audioCodec; - private String name = name; - + private AudioCodec? _audioCodec; + private String? _name; + + [JsonConstructor] + public Audiofile(String? name) : this() + { + _name = name; + } + //TODO: Remove constructors?! public Audiofile(String name, String objectURL, AudioCodec? audioCodec, TimeSpan? duration = null) : this(name) { if (String.IsNullOrEmpty(objectURL)) @@ -48,57 +53,37 @@ public Audiofile(String name, String objectURL, AudioCodec? audioCodec, TimeSpan Duration = duration; } - public String Name + public String? Name { - get => name; + get => _name; set { - if (String.IsNullOrEmpty(value)) - { - throw new ArgumentNullException(nameof(value)); - } var extension = Path.GetExtension(value); - if (extension.Equals(audioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) + if (extension?.Equals(_audioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) { - value = $"{value}{audioCodec?.FileExtension}"; + value = $"{value}{_audioCodec?.FileExtension}"; } - name = value; + _name = value; } } [JsonIgnore] - public String? ObjectURL { get; private set; } + public String? ObjectURL { get; set; } /// /// Duration of the audio file /// - public TimeSpan? Duration { get; private set; } + public TimeSpan? Duration { get; set; } public AudioCodec? AudioCodec { - get { return audioCodec; } - private set + get { return _audioCodec; } + set { - audioCodec = value; - if ((audioCodec != null) && (Name?.EndsWith(audioCodec.FileExtension) == false)) + _audioCodec = value; + if ((_audioCodec != null) && (Name?.EndsWith(_audioCodec.FileExtension) == false)) { //Replace file ending - Name = String.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), audioCodec.FileExtension); - } - } - } - - [JsonIgnore] - public String? AudioFileType - { - get - { - String? audioFileType = null; - if (AudioCodec != null) - { - audioFileType = AudioCodec.FileExtension.Replace(".", "").ToUpper(); + Name = String.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), _audioCodec.FileExtension); } - //Try to find by file name - audioFileType ??= Path.GetExtension(Name)?.Replace(".", "").ToUpper(); - return audioFileType; } } } diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs index 1b044244..e021660a 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs @@ -59,7 +59,8 @@ static Exportprofile() SchemeCuesheetArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Artist), SchemeCharacter); SchemeCuesheetTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Title), SchemeCharacter); - SchemeCuesheetAudiofile = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Audiofile), SchemeCharacter); + //TODO + //SchemeCuesheetAudiofile = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Audiofile), SchemeCharacter); SchemeCuesheetCDTextfile = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.CDTextfile), SchemeCharacter); SchemeCuesheetCatalogueNumber = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Cataloguenumber), SchemeCharacter); @@ -67,7 +68,8 @@ static Exportprofile() { { nameof(Cuesheet.Artist), SchemeCuesheetArtist }, { nameof(Cuesheet.Title), SchemeCuesheetTitle }, - { nameof(Cuesheet.Audiofile), SchemeCuesheetAudiofile }, + //TODO + //{ nameof(Cuesheet.Audiofile), SchemeCuesheetAudiofile }, { nameof(Cuesheet.CDTextfile), SchemeCuesheetCDTextfile }, { nameof(Cuesheet.Cataloguenumber), SchemeCuesheetCatalogueNumber }, { "Date", SchemeDate }, diff --git a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs index b1f824c4..fddc98a3 100644 --- a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs @@ -27,7 +27,9 @@ public class Importprofile : Validateable static Importprofile() { - AvailableSchemeCuesheet = [nameof(Cuesheet.Artist), nameof(Cuesheet.Title), nameof(Cuesheet.Audiofile), nameof(Cuesheet.CDTextfile), nameof(Cuesheet.Cataloguenumber)]; + //TODO + //AvailableSchemeCuesheet = [nameof(Cuesheet.Artist), nameof(Cuesheet.Title), nameof(Cuesheet.Audiofile), nameof(Cuesheet.CDTextfile), nameof(Cuesheet.Cataloguenumber)]; + AvailableSchemeCuesheet = [nameof(Cuesheet.Artist), nameof(Cuesheet.Title), nameof(Cuesheet.CDTextfile), nameof(Cuesheet.Cataloguenumber)]; AvailableSchemesTrack = [nameof(Track.Artist), nameof(Track.Title), nameof(Track.Begin), nameof(Track.End), nameof(Track.Length), nameof(Track.Position), nameof(Track.Flags), nameof(Track.PreGap), nameof(Track.PostGap), nameof(ImportTrack.StartDateTime)]; } public Guid Id { get; init; } = Guid.NewGuid(); diff --git a/AudioCuesheetEditor/Pages/Index.razor b/AudioCuesheetEditor/Pages/Index.razor index 445ba103..1cfc1f6d 100644 --- a/AudioCuesheetEditor/Pages/Index.razor +++ b/AudioCuesheetEditor/Pages/Index.razor @@ -115,7 +115,8 @@ along with Foobar. If not, see } if (_sessionStateContainer.ImportAudiofile != null) { - _cuesheetManager.SetProperty(x => x.Audiofile, _sessionStateContainer.ImportAudiofile); + //TODO + // _cuesheetManager.SetProperty(x => x.Audiofile, _sessionStateContainer.ImportAudiofile); } } finally diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs index 9618bf0c..ab4b9616 100644 --- a/AudioCuesheetEditor/Program.cs +++ b/AudioCuesheetEditor/Program.cs @@ -64,6 +64,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddLogging(); // Read out configuration for loglevel diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index 68142028..af18e300 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -47,14 +47,16 @@ private set } } public Track? CurrentlyPlayingTrack => _sessionStateContainer.Cuesheet.Tracks.SingleOrDefault(x => x.Begin.HasValue == true && x.End.HasValue == true && x.Begin <= CurrentPosition && x.End > CurrentPosition); - public TimeSpan? TotalTime => _sessionStateContainer.Cuesheet.Audiofile?.Duration; + public TimeSpan? TotalTime => null; //TODO _sessionStateContainer.Cuesheet.Audiofile?.Duration; public Boolean IsPlaying { get; private set; } = false; public Boolean IsPlaybackPossible { get { - var audiofile = _sessionStateContainer.Cuesheet.Audiofile; - return String.IsNullOrEmpty(audiofile?.ObjectURL) == false && String.IsNullOrEmpty(audiofile?.AudioFileType) == false; + //TODO + //var audiofile = _sessionStateContainer.Cuesheet.Audiofile; + //return String.IsNullOrEmpty(audiofile?.ObjectURL) == false && String.IsNullOrEmpty(audiofile?.AudioFileType) == false; + return false; } } public Boolean IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; @@ -72,40 +74,41 @@ public PlaybackService(ISessionStateContainer sessionStateContainer, IHowl howl) public async Task PlayOrPauseAsync() { - //Reset if the last played audiofile is not the current one - if (_currentlyPlayingAudiofile != _sessionStateContainer.Cuesheet.Audiofile) - { - _currentPlayingSoundId = null; - } - //If the current audiofile already started, we just pause - if (_currentPlayingSoundId != null) - { - await _howl.Pause(_currentPlayingSoundId.Value); - } - else - { - if (IsPlaybackPossible) - { - string[]? sources = null; - string[]? formats = null; - if (_sessionStateContainer.Cuesheet.Audiofile?.ObjectURL != null) - { - sources = [_sessionStateContainer.Cuesheet.Audiofile.ObjectURL]; - } - if (_sessionStateContainer.Cuesheet.Audiofile?.AudioFileType != null) - { - formats = [_sessionStateContainer.Cuesheet.Audiofile.AudioFileType.ToLower()]; - } - var options = new HowlOptions - { - Sources = sources, - Formats = formats, - Html5 = true - }; - _currentPlayingSoundId = await _howl.Play(options); - _currentlyPlayingAudiofile = _sessionStateContainer.Cuesheet.Audiofile; - } - } + //TODO + ////Reset if the last played audiofile is not the current one + //if (_currentlyPlayingAudiofile != _sessionStateContainer.Cuesheet.Audiofile) + //{ + // _currentPlayingSoundId = null; + //} + ////If the current audiofile already started, we just pause + //if (_currentPlayingSoundId != null) + //{ + // await _howl.Pause(_currentPlayingSoundId.Value); + //} + //else + //{ + // if (IsPlaybackPossible) + // { + // string[]? sources = null; + // string[]? formats = null; + // if (_sessionStateContainer.Cuesheet.Audiofile?.ObjectURL != null) + // { + // sources = [_sessionStateContainer.Cuesheet.Audiofile.ObjectURL]; + // } + // if (_sessionStateContainer.Cuesheet.Audiofile?.AudioFileType != null) + // { + // formats = [_sessionStateContainer.Cuesheet.Audiofile.AudioFileType.ToLower()]; + // } + // var options = new HowlOptions + // { + // Sources = sources, + // Formats = formats, + // Html5 = true + // }; + // _currentPlayingSoundId = await _howl.Play(options); + // _currentlyPlayingAudiofile = _sessionStateContainer.Cuesheet.Audiofile; + // } + //} } public async Task PlayAsync(Track trackToPlay) @@ -199,7 +202,8 @@ private void Howl_OnStop(Howler.Blazor.Components.Events.HowlEventArgs obj) _currentPlayingSoundId = null; StopTimer(); CurrentPosition = null; - _currentlyPlayingAudiofile = _sessionStateContainer.Cuesheet.Audiofile; + //TODO + //_currentlyPlayingAudiofile = _sessionStateContainer.Cuesheet.Audiofile; } private void Howl_OnEnd(Howler.Blazor.Components.Events.HowlEventArgs obj) @@ -240,10 +244,11 @@ private async void UpdateCurrentPosition(object? state) if (_currentPlayingSoundId == null || !IsPlaying) return; } CurrentPosition = await _howl.GetCurrentTime(_currentPlayingSoundId.Value); - if (_sessionStateContainer.Cuesheet.Audiofile != _currentlyPlayingAudiofile) - { - await _howl.Stop(_currentPlayingSoundId.Value); - } + //TODO + //if (_sessionStateContainer.Cuesheet.Audiofile != _currentlyPlayingAudiofile) + //{ + // await _howl.Stop(_currentPlayingSoundId.Value); + //} } } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs new file mode 100644 index 00000000..ea2a6bb8 --- /dev/null +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -0,0 +1,77 @@ +//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 AudioCuesheetEditor.Services.IO; +using AudioCuesheetEditor.Services.UI; +using Microsoft.AspNetCore.Components.Forms; +using Microsoft.JSInterop; + +namespace AudioCuesheetEditor.Services.AudioCuesheet +{ + public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeManager traceChangeManager, IJSRuntime jsRuntime) : IAudiofileManager + { + private readonly IFileInputManager _fileInputManager = fileInputManager; + private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + private readonly IJSRuntime _jsRuntime = jsRuntime; + + /// + public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId) + { + if (browserFile == null) + { + SetProperties(audiofile, null, null, null, null); + } + else + { + var codec = _fileInputManager.GetAudioCodec(browserFile.ContentType, browserFile.Name); + var objectUrl = await _fileInputManager.GetObjectUrlAsync(fileInputId); + TimeSpan? duration = null; + if (String.IsNullOrEmpty(objectUrl) == false) + { + var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", objectUrl); + duration = TimeSpan.FromSeconds(durationSeconds); + } + SetProperties(audiofile, codec, browserFile.Name, objectUrl, duration); + } + } + + void SetProperties(Audiofile audiofile, AudioCodec? audioCodec, string? name, string? objectUrl, TimeSpan? duration) + { + _traceChangeManager.BulkEdit = true; + if (audiofile.AudioCodec != audioCodec) + { + _traceChangeManager.AddChange(new(audiofile, new(audiofile.AudioCodec, nameof(Audiofile.AudioCodec)))); + audiofile.AudioCodec = audioCodec; + } + if (audiofile.Name != name) + { + _traceChangeManager.AddChange(new(audiofile, new(audiofile.Name, nameof(Audiofile.Name)))); + audiofile.Name = name; + } + if (audiofile.ObjectURL != objectUrl) + { + _traceChangeManager.AddChange(new(audiofile, new(audiofile.ObjectURL, nameof(Audiofile.ObjectURL)))); + audiofile.ObjectURL = objectUrl; + } + if (audiofile.Duration != duration) + { + _traceChangeManager.AddChange(new(audiofile, new(audiofile.Duration, nameof(Audiofile.Duration)))); + audiofile.Duration = duration; + } + _traceChangeManager.BulkEdit = false; + } + } +} diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs index 6f45baa8..47d851ee 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs @@ -34,13 +34,14 @@ public void SetProperty(Expression> propert { _traceChangeManager.BulkEdit = true; var cuesheet = _sessionStateContainer.GetActiveCuesheet(); - var audiofile = cuesheet?.Audiofile; + //TODO + //var audiofile = cuesheet?.Audiofile; SetValue(cuesheet!, propertyExpression, value); - // If audiofile has been set, we need to calculate last track end - if (audiofile != cuesheet?.Audiofile) - { - SetLastTrackEnd(cuesheet!); - } + //// If audiofile has been set, we need to calculate last track end + //if (audiofile != cuesheet?.Audiofile) + //{ + // SetLastTrackEnd(cuesheet!); + //} _traceChangeManager.BulkEdit = false; } @@ -113,10 +114,11 @@ public void AddTrack(Track track) else { var lastTrack = GetLastTrack(cuesheet!); - if ((cuesheet?.Audiofile?.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == cuesheet.Audiofile.Duration)) - { - _trackManager.SetProperty(lastTrack, x => x.End, null); - } + //TODO + //if ((cuesheet?.Audiofile?.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == cuesheet.Audiofile.Duration)) + //{ + // _trackManager.SetProperty(lastTrack, x => x.End, null); + //} if (track.Position.HasValue == false) { _trackManager.SetProperty(track, x => x.Position, (ushort?)(lastTrack?.Position + 1)); @@ -261,10 +263,11 @@ void SetValue(Cuesheet cuesheet, Expression void SetLastTrackEnd(Cuesheet cuesheet) { var lastTrack = GetLastTrack(cuesheet); - if ((lastTrack?.End.HasValue == false) && (cuesheet.Audiofile?.Duration.HasValue == true)) - { - _trackManager.SetProperty(lastTrack, x => x.End, cuesheet.Audiofile.Duration); - } + //TODO + //if ((lastTrack?.End.HasValue == false) && (cuesheet.Audiofile?.Duration.HasValue == true)) + //{ + // _trackManager.SetProperty(lastTrack, x => x.End, cuesheet.Audiofile.Duration); + //} } static Track? GetLastTrack(Cuesheet cuesheet) diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs new file mode 100644 index 00000000..ce5da903 --- /dev/null +++ b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs @@ -0,0 +1,31 @@ +//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 Microsoft.AspNetCore.Components.Forms; + +namespace AudioCuesheetEditor.Services.AudioCuesheet +{ + public interface IAudiofileManager + { + /// + /// Set properties from a file upload + /// + /// + /// + /// + Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId); + } +} diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index 2c34ee94..766e9e7b 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -59,10 +59,11 @@ public Result GenerateExportfile(string? filename) { filename = $"{filename}{FileExtensions.Cuesheet}"; } - if (_sessionStateContainer.Cuesheet.Audiofile != null) - { - content = WriteCuesheet(_sessionStateContainer.Cuesheet.Audiofile.Name); - } + //TODO + //if (_sessionStateContainer.Cuesheet.Audiofile != null) + //{ + // content = WriteCuesheet(_sessionStateContainer.Cuesheet.Audiofile.Name); + //} return Result.Success(new Exportfile() { Name = filename!, Content = content }); } @@ -79,7 +80,8 @@ private string WriteCuesheet(string? audiofileName) } builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, _sessionStateContainer.Cuesheet.Title)); builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); - builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofileName, _sessionStateContainer.Cuesheet.Audiofile?.AudioFileType)); + //TODO + //builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofileName, _sessionStateContainer.Cuesheet.Audiofile?.AudioFileType)); IEnumerable tracks = _sessionStateContainer.Cuesheet.Tracks.OrderBy(x => x.Position); if (tracks.Any()) { diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index 4b1e3464..b2f44b54 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -49,10 +49,11 @@ public Result GenerateExportfile(Exportprofile exportprofile) return Result.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); } string? content = null; - if (_sessionStateContainer.Cuesheet.Audiofile != null) - { - content = WriteExport(exportprofile, _sessionStateContainer.Cuesheet.Audiofile.Name); - } + //TODO + //if (_sessionStateContainer.Cuesheet.Audiofile != null) + //{ + // content = WriteExport(exportprofile, _sessionStateContainer.Cuesheet.Audiofile.Name); + //} return Result.Success(new Exportfile() { Name = exportprofile.Filename, Content = content}); } diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 32836dc8..160a7701 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -21,10 +21,9 @@ namespace AudioCuesheetEditor.Services.IO { - public class FileInputManager(IJSRuntime jsRuntime, HttpClient httpClient, ILogger logger) : IFileInputManager + public class FileInputManager(IJSRuntime jsRuntime, ILogger logger) : IFileInputManager { private readonly IJSRuntime _jsRuntime = jsRuntime; - private readonly HttpClient _httpClient = httpClient; private readonly ILogger _logger = logger; public AudioCodec? GetAudioCodec(string? fileContentType, string fileName) @@ -46,6 +45,12 @@ public class FileInputManager(IJSRuntime jsRuntime, HttpClient httpClient, ILogg return foundAudioCodec; } + /// + public async Task GetObjectUrlAsync(string fileInputId) + { + return await _jsRuntime.InvokeAsync("getObjectURLFromMudFileUpload", fileInputId); + } + public bool IsValidAudiofile(string? fileContentType, string fileName) { return GetAudioCodec(fileContentType, fileName) != null; diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs index f79f88a0..e5f4ff39 100644 --- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs @@ -26,6 +26,12 @@ public interface IFileInputManager bool IsValidAudiofile(string? fileContentType, string fileName); AudioCodec? GetAudioCodec(string? fileContentType, string fileName); /// + /// Get object url from a mud file upload + /// + /// + /// + Task GetObjectUrlAsync(string fileInputId); + /// /// Checks if a file content type and name matches given parameters /// /// diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 1a17a2dc..542fa964 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -188,17 +188,19 @@ private void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) if (cuesheetToCopy is Cuesheet originCuesheet) { tracks = originCuesheet.Tracks; - target.Audiofile = originCuesheet.Audiofile; + //TODO + //target.Audiofile = originCuesheet.Audiofile; target.CDTextfile = originCuesheet.CDTextfile; target.Cataloguenumber = originCuesheet.Cataloguenumber; } if (cuesheetToCopy is ImportCuesheet importCuesheet) { tracks = importCuesheet.Tracks; - if (String.IsNullOrEmpty(importCuesheet.Audiofile) == false) - { - target.Audiofile = new Audiofile(importCuesheet.Audiofile); - } + //TODO + //if (String.IsNullOrEmpty(importCuesheet.Audiofile) == false) + //{ + // target.Audiofile = new Audiofile(importCuesheet.Audiofile); + //} if (String.IsNullOrEmpty(importCuesheet.CDTextfile) == false) { target.CDTextfile = new CDTextfile(importCuesheet.CDTextfile); diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor new file mode 100644 index 00000000..0dd95da1 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -0,0 +1,72 @@ + +@inherits BaseLocalizedComponent + +@inject IStringLocalizer _localizer +@inject ISessionStateContainer _sessionStateContainer +@inject ICuesheetManager _cuesheetManager +@inject IAudiofileManager _audiofileManager + + + + + + + @foreach (var file in _audiofiles) + { + + + @file.Name + + + @{ + var fileInputId = $"Audiofile_{Guid.NewGuid()}"; + } + x.MimeType))" /> + + + } + + +@code { + //TODO: Remove audiofile button + //TODO: Tracklist below each file + //TOOD: Better handling for fileinput?! + //TODO: Button for removing all audiofiles + + [CascadingParameter] + public ViewMode CurrentViewMode { get; set; } + + Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); + ICollection _audiofiles => _cuesheet!.Audiofiles; + + void AddButtonClicked() + { + var files = new List(_audiofiles); + files.Add(new()); + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + } + + void DeleteButtonClicked(Audiofile audiofile) + { + var files = new List(_audiofiles); + files.Remove(audiofile); + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + } +} diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor b/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor index 6de35334..ee27a922 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor @@ -36,8 +36,8 @@ along with Foobar. If not, see { case ViewMode.ImportView: case ViewMode.DetailView: - x.MimeType))" OnFileRenameClicked="AudioFileRename" FileRenameDisabled="Cuesheet.Audiofile == null" /> + @* x.MimeType))" OnFileRenameClicked="AudioFileRename" FileRenameDisabled="Cuesheet.Audiofile == null" /> *@ } @code { + //TODO: Have multiple audio file inputs for each file + //TODO: Add tracks to file public Cuesheet? Cuesheet { get @@ -118,7 +120,8 @@ along with Foobar. If not, see var fileUpload = await _fileInputManager.CreateFileUploadsAsync([browserFile], _fileInputAudiofileId); audiofile = await _fileInputManager.CreateAudiofileAsync(fileUpload.Single()); } - _cuesheetManager.SetProperty(x => x.Audiofile, audiofile); + //TODO + // _cuesheetManager.SetProperty(x => x.Audiofile, audiofile); } catch(ArgumentException ae) { @@ -137,7 +140,7 @@ along with Foobar. If not, see { return; } - var validationMessages = _validationService.Validate(Cuesheet, nameof(Cuesheet.Audiofile)); + var validationMessages = _validationService.Validate(Cuesheet, nameof(Cuesheet.Audiofiles)); if (validationMessages.Count() > 0) { _fileInputAudiofileErrorText = String.Join(Environment.NewLine, validationMessages); @@ -185,15 +188,16 @@ along with Foobar. If not, see async Task AudioFileRename() { - var newFileName = await ShowInputDialog(Cuesheet?.Audiofile?.Name); - if (String.IsNullOrEmpty(newFileName) == false) - { - var audioFile = Cuesheet?.Audiofile; - if (audioFile != null) - { - audioFile.Name = newFileName; - } - } + //TODO + // var newFileName = await ShowInputDialog(Cuesheet?.Audiofile?.Name); + // if (String.IsNullOrEmpty(newFileName) == false) + // { + // var audioFile = Cuesheet?.Audiofile; + // if (audioFile != null) + // { + // audioFile.Name = newFileName; + // } + // } } async Task ShowInputDialog(string? initialValue) diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.de.resx b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.de.resx index c482082c..12369499 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.de.resx +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.de.resx @@ -120,7 +120,7 @@ Allgemeine Informationen - - Titel + + Dateien \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor index 7f10f6e4..a0f6d3ce 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor @@ -28,12 +28,12 @@ along with Foobar. If not, see - + - @_localizer["Tracks"] + @_localizer["Files"] - + @@ -42,5 +42,5 @@ along with Foobar. If not, see @code { Boolean cuesheetDataExpanded = true; - Boolean cuesheetTracksExpanded = true; + Boolean cuesheetFilesExpanded = true; } diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.resx b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.resx index 6c53c579..d4f7b80a 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.resx +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.resx @@ -120,7 +120,7 @@ Common data - - Tracks + + Files \ No newline at end of file From 2628f1b70f30bdaa883ea8b8c20d1a248ac7517c Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 29 May 2026 16:48:22 +0200 Subject: [PATCH 003/132] add button for removing all files --- .../Shared/Cuesheet/Audiofiles.razor | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 0dd95da1..0115eef4 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -21,10 +21,21 @@ along with Foobar. If not, see @inject ISessionStateContainer _sessionStateContainer @inject ICuesheetManager _cuesheetManager @inject IAudiofileManager _audiofileManager +@inject IDialogService _dialogService - - - + + + + + + + @_localizer["Delete all files"] + + + + + + @foreach (var file in _audiofiles) @@ -48,7 +59,7 @@ along with Foobar. If not, see //TODO: Remove audiofile button //TODO: Tracklist below each file //TOOD: Better handling for fileinput?! - //TODO: Button for removing all audiofiles + //TODO: Localization [CascadingParameter] public ViewMode CurrentViewMode { get; set; } @@ -69,4 +80,19 @@ along with Foobar. If not, see files.Remove(audiofile); _cuesheetManager.SetProperty(x => x.Audiofiles, files); } + + async Task DeleteAllFilesClicked() + { + var parameters = new DialogParameters + { + { x => x.ConfirmText, _localizer["Are you sure you want to remove all files?"] }, + }; + var dialog = await _dialogService.ShowAsync(_localizer["Confirm"], parameters); + var result = await dialog.Result; + if (result?.Canceled == false) + { + var files = new List(); + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + } + } } From 1a11f37cf22f5791e448acf564a8169ab7652a02 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 29 May 2026 16:57:56 +0200 Subject: [PATCH 004/132] Update Audiofiles.razor --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 0115eef4..84c78198 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -37,10 +37,13 @@ along with Foobar. If not, see +
+
+ @foreach (var file in _audiofiles) { - + @file.Name From 8643232def7775c2295f22ba34be555242ded606 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:33:05 +0200 Subject: [PATCH 005/132] file rename --- .../AudioCuesheet/AudiofileManager.cs | 51 ++++++++++++------- .../AudioCuesheet/IAudiofileManager.cs | 9 ++++ .../Shared/Cuesheet/Audiofiles.razor | 42 +++++++++++++-- 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index ea2a6bb8..85b95a6e 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -18,6 +18,8 @@ using AudioCuesheetEditor.Services.UI; using Microsoft.AspNetCore.Components.Forms; using Microsoft.JSInterop; +using System.Linq.Expressions; +using System.Reflection; namespace AudioCuesheetEditor.Services.AudioCuesheet { @@ -30,9 +32,14 @@ public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeMa /// public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId) { + //TODO: Tests + _traceChangeManager.BulkEdit = true; if (browserFile == null) { - SetProperties(audiofile, null, null, null, null); + SetValue(audiofile, x => x.AudioCodec, null); + SetValue(audiofile, x => x.Name, null); + SetValue(audiofile, x => x.ObjectURL, null); + SetValue(audiofile, x => x.Duration, null); } else { @@ -44,34 +51,40 @@ public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserF var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", objectUrl); duration = TimeSpan.FromSeconds(durationSeconds); } - SetProperties(audiofile, codec, browserFile.Name, objectUrl, duration); + SetValue(audiofile, x => x.AudioCodec, codec); + SetValue(audiofile, x => x.Name, browserFile.Name); + SetValue(audiofile, x => x.ObjectURL, objectUrl); + SetValue(audiofile, x => x.Duration, duration); } + _traceChangeManager.BulkEdit = false; } - void SetProperties(Audiofile audiofile, AudioCodec? audioCodec, string? name, string? objectUrl, TimeSpan? duration) + public void SetProperty(Audiofile audiofile, Expression> propertyExpression, TProperty value) { - _traceChangeManager.BulkEdit = true; - if (audiofile.AudioCodec != audioCodec) - { - _traceChangeManager.AddChange(new(audiofile, new(audiofile.AudioCodec, nameof(Audiofile.AudioCodec)))); - audiofile.AudioCodec = audioCodec; - } - if (audiofile.Name != name) + //TODO: Tests + SetValue(audiofile, propertyExpression, value); + } + + void SetValue(Audiofile audiofile, Expression> propertyExpression, TProperty value) + { + if (propertyExpression.Body is not MemberExpression memberExpression) { - _traceChangeManager.AddChange(new(audiofile, new(audiofile.Name, nameof(Audiofile.Name)))); - audiofile.Name = name; + throw new ArgumentException("Expression must be a property"); } - if (audiofile.ObjectURL != objectUrl) + + if (memberExpression.Member is not PropertyInfo propertyInfo) { - _traceChangeManager.AddChange(new(audiofile, new(audiofile.ObjectURL, nameof(Audiofile.ObjectURL)))); - audiofile.ObjectURL = objectUrl; + throw new ArgumentException("Member is not a property"); } - if (audiofile.Duration != duration) + + var previousValue = (TProperty?)propertyInfo.GetValue(audiofile); + if (Equals(previousValue, value)) { - _traceChangeManager.AddChange(new(audiofile, new(audiofile.Duration, nameof(Audiofile.Duration)))); - audiofile.Duration = duration; + return; } - _traceChangeManager.BulkEdit = false; + + propertyInfo.SetValue(audiofile, value); + _traceChangeManager.AddChange(new(audiofile, new(previousValue, propertyInfo.Name))); } } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs index ce5da903..cc16d8be 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs @@ -15,6 +15,7 @@ //. using AudioCuesheetEditor.Model.IO.Audio; using Microsoft.AspNetCore.Components.Forms; +using System.Linq.Expressions; namespace AudioCuesheetEditor.Services.AudioCuesheet { @@ -27,5 +28,13 @@ public interface IAudiofileManager /// /// Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId); + /// + /// Set property for an audio file + /// + /// + /// + /// + /// + void SetProperty(Audiofile audiofile, Expression> propertyExpression, TProperty value); } } diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 84c78198..54a62ec8 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -45,20 +45,21 @@ along with Foobar. If not, see { - @file.Name - - @{ var fileInputId = $"Audiofile_{Guid.NewGuid()}"; } x.MimeType))" /> + OnFileRenameClicked="(IBrowserFile? browserFile) => FileRenameClicked(file, browserFile)" Filter="@String.Join(",", Audiofile.AudioCodecs.Select(x => x.MimeType))" + FileRenameDisabled="file.Name == null"/> + + + } -@code { + @code { //TODO: Remove audiofile button //TODO: Tracklist below each file //TOOD: Better handling for fileinput?! @@ -98,4 +99,35 @@ along with Foobar. If not, see _cuesheetManager.SetProperty(x => x.Audiofiles, files); } } + + async Task ShowInputDialog(string? initialValue) + { + var parameters = new DialogParameters + { + { x => x.Placeholder, _localizer["Enter the new file name here"] }, + { x => x.Label, _localizer["New file name"] }, + { x => x.InitialValue, initialValue } + }; + var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; + var dialog = await _dialogService.ShowAsync(_localizer["Change file name"], parameters, options); + var result = await dialog.Result; + var newFileName = result?.Data as string; + if ((result?.Canceled == false) && (String.IsNullOrEmpty(newFileName) == false)) + { + return newFileName; + } + else + { + return null; + } + } + + async Task FileRenameClicked(Audiofile audiofile, IBrowserFile? browserFile) + { + var newFileName = await ShowInputDialog(browserFile?.Name); + if (String.IsNullOrEmpty(newFileName) == false) + { + _audiofileManager.SetProperty(audiofile, x => x.Name, newFileName); + } + } } From 96f1fcdd10d643ccc0b8dc1795c1e7ee7b660633 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:55:35 +0200 Subject: [PATCH 006/132] add validation errors display --- .../Shared/Cuesheet/Audiofiles.razor | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 54a62ec8..80bf1a74 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -18,11 +18,31 @@ along with Foobar. If not, see @inherits BaseLocalizedComponent @inject IStringLocalizer _localizer +@inject IStringLocalizer _validationMessageLocalizer @inject ISessionStateContainer _sessionStateContainer @inject ICuesheetManager _cuesheetManager @inject IAudiofileManager _audiofileManager @inject IDialogService _dialogService +@switch (CurrentViewMode) +{ + case ViewMode.DetailView: + case ViewMode.ImportView: + var validationResult = _cuesheet?.Validate(nameof(Cuesheet.Audiofiles)); + if (validationResult?.Status == ValidationStatus.Error) + { + + @_localizer["Validation errors"] + @foreach (var message in validationResult.ValidationMessages) + { + @message.GetMessageLocalized(_validationMessageLocalizer) + } + +
+ } + break; +} + @@ -37,7 +57,6 @@ along with Foobar. If not, see -

@@ -49,8 +68,8 @@ along with Foobar. If not, see var fileInputId = $"Audiofile_{Guid.NewGuid()}"; } x.MimeType))" - FileRenameDisabled="file.Name == null"/> + OnFileRenameClicked="(IBrowserFile? browserFile) => FileRenameClicked(file, browserFile)" Filter="@String.Join(",", Audiofile.AudioCodecs.Select(x => x.MimeType))" + FileRenameDisabled="file.Name == null" /> @@ -59,10 +78,9 @@ along with Foobar. If not, see } - @code { +@code { //TODO: Remove audiofile button //TODO: Tracklist below each file - //TOOD: Better handling for fileinput?! //TODO: Localization [CascadingParameter] From 8f93fdc9c286f4750dd68d1bff93f3dc7bb707fd Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:57:04 +0200 Subject: [PATCH 007/132] Update Audiofiles.razor --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 80bf1a74..9fb4c9be 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -57,6 +57,7 @@ along with Foobar. If not, see +

From aaaeb96779ac32b7bccf4f7687da1de06f84b266 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:18:11 +0200 Subject: [PATCH 008/132] display error messages --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 2 +- AudioCuesheetEditor/Shared/Inputs/FileInput.razor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 9fb4c9be..8f144fad 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -70,7 +70,7 @@ along with Foobar. If not, see } x.MimeType))" - FileRenameDisabled="file.Name == null" /> + FileRenameDisabled="file.Name == null" Error="@(file.Name == null ? _validationMessageLocalizer["No file selected!"].Value : null)" /> diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor b/AudioCuesheetEditor/Shared/Inputs/FileInput.razor index 22398f4a..62c76e6d 100644 --- a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor +++ b/AudioCuesheetEditor/Shared/Inputs/FileInput.razor @@ -23,7 +23,7 @@ along with Foobar. If not, see - + From 20c461d8828ec4b9d7a0c4e20e11ca26a6a59765 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:10:34 +0200 Subject: [PATCH 009/132] Update Audiofiles.razor --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 8f144fad..a0718be5 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -83,6 +83,7 @@ along with Foobar. If not, see //TODO: Remove audiofile button //TODO: Tracklist below each file //TODO: Localization + //TODO: Move up/down buttons [CascadingParameter] public ViewMode CurrentViewMode { get; set; } From fee03ce25d83da520eb2f911da8775d73579d3f2 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 14:15:26 +0200 Subject: [PATCH 010/132] remove expanables on first layer --- .../Shared/Audio/AudioPlayer.razor | 87 ++++++++---------- .../Shared/Cuesheet/Audiofiles.razor | 32 ++----- .../Shared/Import/DisplayAnalyzedResult.razor | 37 ++++---- .../Shared/ViewModes/ViewModeFull.razor | 90 ++++++++++++++----- .../Shared/ViewModes/ViewModeRecord.razor | 41 ++++----- 5 files changed, 149 insertions(+), 138 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Audio/AudioPlayer.razor b/AudioCuesheetEditor/Shared/Audio/AudioPlayer.razor index 122d0742..feb70521 100644 --- a/AudioCuesheetEditor/Shared/Audio/AudioPlayer.razor +++ b/AudioCuesheetEditor/Shared/Audio/AudioPlayer.razor @@ -22,54 +22,45 @@ along with Foobar. If not, see @inject PlaybackService _playbackService @inject HotKeys _hotKeys - - - - @_localizer["Playback"] - - - - - @if (_playbackService.CurrentPosition.HasValue) - { - @_playbackService.CurrentPosition.Value.ToString("hh\\:mm\\:ss") - } - else - { - @String.Format("--{0}--{1}--", CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator, CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator) - } - - - @GetSliderTimeValue() - - - @if (_playbackService.TotalTime.HasValue) - { - @_playbackService.TotalTime.Value.ToString("hh\\:mm\\:ss") - } - else - { - @String.Format("--{0}--{1}--", CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator, CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator) - } - - - - - - - - - - - - - - - - - - - + + @if (_playbackService.CurrentPosition.HasValue) + { + @_playbackService.CurrentPosition.Value.ToString("hh\\:mm\\:ss") + } + else + { + @String.Format("--{0}--{1}--", CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator, CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator) + } + + + @GetSliderTimeValue() + + + @if (_playbackService.TotalTime.HasValue) + { + @_playbackService.TotalTime.Value.ToString("hh\\:mm\\:ss") + } + else + { + @String.Format("--{0}--{1}--", CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator, CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator) + } + + + + + + + + + + + + + + + + + @code { double sliderValue; diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index a0718be5..38b8d002 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -43,25 +43,8 @@ along with Foobar. If not, see break; } - - - - - - - @_localizer["Delete all files"] - - - - - - - -
-
- - @foreach (var file in _audiofiles) + @foreach (var file in Files) { @@ -85,22 +68,25 @@ along with Foobar. If not, see //TODO: Localization //TODO: Move up/down buttons + Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); + + [Parameter] + [EditorRequired] + public ICollection Files { get; set; } + [CascadingParameter] public ViewMode CurrentViewMode { get; set; } - Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); - ICollection _audiofiles => _cuesheet!.Audiofiles; - void AddButtonClicked() { - var files = new List(_audiofiles); + var files = new List(Files); files.Add(new()); _cuesheetManager.SetProperty(x => x.Audiofiles, files); } void DeleteButtonClicked(Audiofile audiofile) { - var files = new List(_audiofiles); + var files = new List(Files); files.Remove(audiofile); _cuesheetManager.SetProperty(x => x.Audiofiles, files); } diff --git a/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor index 60e287c7..7afea233 100644 --- a/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor +++ b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor @@ -36,29 +36,26 @@ along with Foobar. If not, see } else { - - - - @_localizer["Common data"] - - - - - - - - @_localizer["Tracks"] - - - - - - + + + @_localizer["Common data"] + + + + + + + + @_localizer["Tracks"] + + + + + } @code { - Boolean cuesheetDataExpanded = true, cuesheetTracksExpanded = true; - + //TODO: Display files and then tracks public String? FileContentRecognized => _sessionStateContainer.Importfile?.FileContentRecognized; string SanitizeHTML(string input) diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor index a0f6d3ce..f28137c7 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor @@ -18,29 +18,75 @@ along with Foobar. If not, see @inherits BaseLocalizedComponent @inject IStringLocalizer _localizer +@inject ISessionStateContainer _sessionStateContainer +@inject ICuesheetManager _cuesheetManager +@inject IDialogService _dialogService - - - - @_localizer["Common data"] - - - - - - - + + + @_localizer["Common data"] + + + + + + + + @_localizer["Files"] - - - - - - - - + + + + + + + + @_localizer["Delete all files"] + + + + + + + + + + + + + + + @_localizer["Playback"] + + + + + + @code { - Boolean cuesheetDataExpanded = true; - Boolean cuesheetFilesExpanded = true; -} + Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); + ICollection _audiofiles => _cuesheet != null ? _cuesheet.Audiofiles : []; + + void AddButtonClicked() + { + var files = new List(_audiofiles); + files.Add(new()); + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + } + + async Task DeleteAllFilesClicked() + { + var parameters = new DialogParameters + { + { x => x.ConfirmText, _localizer["Are you sure you want to remove all files?"] }, + }; + var dialog = await _dialogService.ShowAsync(_localizer["Confirm"], parameters); + var result = await dialog.Result; + if (result?.Canceled == false) + { + var files = new List(); + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + } + } +} \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.razor index f734e7d6..e1fdc98e 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.razor @@ -18,33 +18,24 @@ along with Foobar. If not, see @inherits BaseLocalizedComponent @inject IStringLocalizer _localizer -@inject IJSRuntime _jsRuntime -@inject ISessionStateContainer _sessionStateContainer -@inject IFileInputManager _fileInputManager

- - - - @_localizer["Tracks"] - - - - - - - - @_localizer["Common data"] - - - - - - - -@code { - Boolean cuesheetDataExpanded = false, tracksExpanded = true; -} + + + @_localizer["Tracks"] + + + + + + + + @_localizer["Common data"] + + + + + \ No newline at end of file From e088f47487d5e16be3c95ae6561cdb827610ac1f Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 14:28:24 +0200 Subject: [PATCH 011/132] Update Audiofiles.razor --- .../Shared/Cuesheet/Audiofiles.razor | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 38b8d002..5f70064c 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -77,35 +77,6 @@ along with Foobar. If not, see [CascadingParameter] public ViewMode CurrentViewMode { get; set; } - void AddButtonClicked() - { - var files = new List(Files); - files.Add(new()); - _cuesheetManager.SetProperty(x => x.Audiofiles, files); - } - - void DeleteButtonClicked(Audiofile audiofile) - { - var files = new List(Files); - files.Remove(audiofile); - _cuesheetManager.SetProperty(x => x.Audiofiles, files); - } - - async Task DeleteAllFilesClicked() - { - var parameters = new DialogParameters - { - { x => x.ConfirmText, _localizer["Are you sure you want to remove all files?"] }, - }; - var dialog = await _dialogService.ShowAsync(_localizer["Confirm"], parameters); - var result = await dialog.Result; - if (result?.Canceled == false) - { - var files = new List(); - _cuesheetManager.SetProperty(x => x.Audiofiles, files); - } - } - async Task ShowInputDialog(string? initialValue) { var parameters = new DialogParameters From 2b3cab6c47294e386762679ab1fcbf81a849b873 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 1 Jun 2026 16:03:16 +0200 Subject: [PATCH 012/132] Update ViewModeFull.razor --- AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor index f28137c7..c82a6a4f 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor @@ -56,7 +56,7 @@ along with Foobar. If not, see - @_localizer["Playback"] + @_localizer["Playback"] From 820d6f3dbd23c9fac20acc1c01066843f31e30cf Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 2 Jun 2026 16:11:22 +0200 Subject: [PATCH 013/132] final layout for audiofiles --- .../Shared/Cuesheet/Audiofiles.razor | 42 ++++-- .../Shared/Cuesheet/CuesheetData.razor | 131 +++--------------- .../Shared/Inputs/FileInput.de.resx | 3 + .../Shared/Inputs/FileInput.razor | 25 ++-- .../Shared/Inputs/FileInput.resx | 3 + .../Shared/ViewModes/ViewModeFull.razor | 34 +++-- 6 files changed, 89 insertions(+), 149 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 5f70064c..485355b4 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -48,25 +48,26 @@ along with Foobar. If not, see { - @{ - var fileInputId = $"Audiofile_{Guid.NewGuid()}"; - } - x.MimeType))" - FileRenameDisabled="file.Name == null" Error="@(file.Name == null ? _validationMessageLocalizer["No file selected!"].Value : null)" /> + + + @{ + var fileInputId = $"Audiofile_{Guid.NewGuid()}"; + } + x.MimeType))" + FileRenameDisabled="file.Name == null" Error="file.Name == null" /> + - + }
@code { - //TODO: Remove audiofile button //TODO: Tracklist below each file //TODO: Localization - //TODO: Move up/down buttons Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); @@ -77,6 +78,12 @@ along with Foobar. If not, see [CascadingParameter] public ViewMode CurrentViewMode { get; set; } + [Parameter] + public HashSet SelectedFiles { get; set; } = []; + + [Parameter] + public EventCallback> SelectedFilesChanged { get; set; } + async Task ShowInputDialog(string? initialValue) { var parameters = new DialogParameters @@ -99,12 +106,25 @@ along with Foobar. If not, see } } - async Task FileRenameClicked(Audiofile audiofile, IBrowserFile? browserFile) + async Task FileRenameClicked(Audiofile audiofile) { - var newFileName = await ShowInputDialog(browserFile?.Name); + var newFileName = await ShowInputDialog(audiofile.Name); if (String.IsNullOrEmpty(newFileName) == false) { _audiofileManager.SetProperty(audiofile, x => x.Name, newFileName); } } + + void SelectedChanged(Audiofile audiofile, Boolean selected) + { + if (selected) + { + SelectedFiles.Add(audiofile); + } + else + { + SelectedFiles.Remove(audiofile); + } + SelectedFilesChanged.InvokeAsync(SelectedFiles); + } } diff --git a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor b/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor index ee27a922..097d8ee1 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor @@ -23,24 +23,21 @@ along with Foobar. If not, see @inject IDialogService _dialogService @inject ISessionStateContainer _sessionStateContainer @inject ICuesheetManager _cuesheetManager -@inject ITrackManager _trackManager -@if (Cuesheet != null) +@if (_cuesheet != null) { - - + - @switch(CurrentViewMode) { case ViewMode.ImportView: case ViewMode.DetailView: - @* x.MimeType))" OnFileRenameClicked="AudioFileRename" FileRenameDisabled="Cuesheet.Audiofile == null" /> *@ - - + break; @@ -49,26 +46,10 @@ along with Foobar. If not, see } @code { - //TODO: Have multiple audio file inputs for each file - //TODO: Add tracks to file - public Cuesheet? Cuesheet - { - get - { - if (CurrentViewMode == ViewMode.ImportView) - { - return _sessionStateContainer.ImportCuesheet; - } - return _sessionStateContainer.Cuesheet; - } - } - [CascadingParameter] public ViewMode CurrentViewMode { get; set; } - string? _fileInputAudiofileId; - string? _fileInputAudiofileErrorText; - string? _fileInputCDTextfileErrorText; + Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); string? _catalogueNumber; MudForm? _form; MudTextField? _catalogueNumberTextField; @@ -76,10 +57,6 @@ along with Foobar. If not, see protected override void OnInitialized() { base.OnInitialized(); - if (_fileInputAudiofileId == null) - { - _fileInputAudiofileId = $"Input_Audiofile_{Guid.NewGuid()}"; - } TraceChangeManager.UndoDone += TraceChangeManager_UndoDone; TraceChangeManager.RedoDone += TraceChangeManager_RedoDone; _sessionStateContainer.CuesheetChanged += SessionStateContainer_CuesheetChanged; @@ -98,87 +75,29 @@ along with Foobar. If not, see protected override void OnParametersSet() { base.OnParametersSet(); - if (_form?.IsTouched == true) - { - SetAudiofileValidationText(); - } - _catalogueNumber = Cuesheet?.Cataloguenumber; - } - - async Task OnAudiofileSelected(IBrowserFile? browserFile) - { - if (Cuesheet == null) - { - return; - } - _fileInputAudiofileErrorText = null; - try - { - Audiofile? audiofile = null; - if (browserFile != null) - { - var fileUpload = await _fileInputManager.CreateFileUploadsAsync([browserFile], _fileInputAudiofileId); - audiofile = await _fileInputManager.CreateAudiofileAsync(fileUpload.Single()); - } - //TODO - // _cuesheetManager.SetProperty(x => x.Audiofile, audiofile); - } - catch(ArgumentException ae) - { - _fileInputAudiofileErrorText = ae.Message; - } - // Just validate the cuesheet if there is no error already - if (_fileInputAudiofileErrorText == null) - { - SetAudiofileValidationText(); - } - } - - void SetAudiofileValidationText() - { - if (Cuesheet == null) - { - return; - } - var validationMessages = _validationService.Validate(Cuesheet, nameof(Cuesheet.Audiofiles)); - if (validationMessages.Count() > 0) - { - _fileInputAudiofileErrorText = String.Join(Environment.NewLine, validationMessages); - } - else - { - _fileInputAudiofileErrorText = null; - } + _catalogueNumber = _cuesheet?.Cataloguenumber; } void OnCDTextfileSelected(IBrowserFile? browserFile) { - if (Cuesheet == null) + if (_cuesheet == null) { return; } - _fileInputCDTextfileErrorText = null; - try - { - CDTextfile? newValue = null; - if (browserFile != null) - { - newValue = _fileInputManager.CreateCDTextfile(browserFile.ContentType, browserFile.Name); - } - _cuesheetManager.SetProperty(x => x.CDTextfile, newValue); - } - catch (ArgumentException ae) + CDTextfile? newValue = null; + if (browserFile != null) { - _fileInputCDTextfileErrorText = ae.Message; + newValue = _fileInputManager.CreateCDTextfile(browserFile.ContentType, browserFile.Name); } + _cuesheetManager.SetProperty(x => x.CDTextfile, newValue); } async Task CDTextFileRename() { - var newFileName = await ShowInputDialog(Cuesheet?.CDTextfile?.Name); + var newFileName = await ShowInputDialog(_cuesheet?.CDTextfile?.Name); if (String.IsNullOrEmpty(newFileName) == false) { - var cdTextFile = Cuesheet?.CDTextfile; + var cdTextFile = _cuesheet?.CDTextfile; if (cdTextFile != null) { cdTextFile.Name = newFileName; @@ -186,20 +105,6 @@ along with Foobar. If not, see } } - async Task AudioFileRename() - { - //TODO - // var newFileName = await ShowInputDialog(Cuesheet?.Audiofile?.Name); - // if (String.IsNullOrEmpty(newFileName) == false) - // { - // var audioFile = Cuesheet?.Audiofile; - // if (audioFile != null) - // { - // audioFile.Name = newFileName; - // } - // } - } - async Task ShowInputDialog(string? initialValue) { var parameters = new DialogParameters @@ -230,13 +135,13 @@ along with Foobar. If not, see void TraceChangeManager_RedoDone(object? sender, EventArgs e) { - _catalogueNumber = Cuesheet?.Cataloguenumber; + _catalogueNumber = _cuesheet?.Cataloguenumber; _catalogueNumberTextField?.ResetAsync(); } void TraceChangeManager_UndoDone(object? sender, EventArgs e) { - _catalogueNumber = Cuesheet?.Cataloguenumber; + _catalogueNumber = _cuesheet?.Cataloguenumber; _catalogueNumberTextField?.ResetAsync(); } diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.de.resx b/AudioCuesheetEditor/Shared/Inputs/FileInput.de.resx index c53b0a37..f3c81bf2 100644 --- a/AudioCuesheetEditor/Shared/Inputs/FileInput.de.resx +++ b/AudioCuesheetEditor/Shared/Inputs/FileInput.de.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Datei entfernen + Keine Datei ausgewählt diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor b/AudioCuesheetEditor/Shared/Inputs/FileInput.razor index 62c76e6d..cde8bfb4 100644 --- a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor +++ b/AudioCuesheetEditor/Shared/Inputs/FileInput.razor @@ -23,25 +23,21 @@ along with Foobar. If not, see - + @_localizer["Search"] + - - @if (DisplayMenu) - { - - @_localizer["Rename file"] - - } + + + @_localizer["Clear file"] + + @_localizer["Rename file"] + -@if(String.IsNullOrEmpty(Error) == false) -{ - @Error -} @code { [Parameter] @@ -61,7 +57,7 @@ along with Foobar. If not, see public String Id { get; set; } = $"FileInput_{Guid.NewGuid()}"; [Parameter] - public String? Error { get; set; } + public Boolean Error { get; set; } [Parameter] public String? Filter { get; set; } @@ -69,9 +65,6 @@ along with Foobar. If not, see [Parameter] public String? FileName { get; set; } - [Parameter] - public Boolean DisplayMenu { get; set; } = true; - IBrowserFile? _selectedFile; MudFileUpload? _fileUpload; String _textFieldValue => String.IsNullOrEmpty(FileName) ? _localizer["No file selected"] : FileName; diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.resx b/AudioCuesheetEditor/Shared/Inputs/FileInput.resx index 36dacde3..fba7f8bc 100644 --- a/AudioCuesheetEditor/Shared/Inputs/FileInput.resx +++ b/AudioCuesheetEditor/Shared/Inputs/FileInput.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Clear file + No file selected diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor index c82a6a4f..1ab5c3fc 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor @@ -39,18 +39,23 @@ along with Foobar. If not, see - - - @_localizer["Delete all files"] - - - - - + + + + + + + @_localizer["Delete all files"] + + + + + + - + @@ -65,8 +70,11 @@ along with Foobar. If not, see @code { + //TODO: Move up/down buttons for files + Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); ICollection _audiofiles => _cuesheet != null ? _cuesheet.Audiofiles : []; + HashSet _selectedAudiofiles = []; void AddButtonClicked() { @@ -75,6 +83,14 @@ along with Foobar. If not, see _cuesheetManager.SetProperty(x => x.Audiofiles, files); } + void DeleteButtonClicked() + { + var files = new List(_audiofiles); + files.RemoveAll(x => _selectedAudiofiles.Contains(x)); + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + _selectedAudiofiles.Clear(); + } + async Task DeleteAllFilesClicked() { var parameters = new DialogParameters From 8d1a8b8d7507d6a85666bb53c2c30457306ae3ee Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 9 Jun 2026 09:44:05 +0200 Subject: [PATCH 014/132] set relation for track to audiofile --- .../Model/AudioCuesheet/Cuesheet.cs | 44 ---- .../Model/AudioCuesheet/Track.cs | 21 +- .../Model/IO/Audio/Audiofile.cs | 59 +++++- AudioCuesheetEditor/Model/IO/Projectfile.cs | 15 +- .../Services/Audio/PlaybackService.cs | 28 +-- .../AudioCuesheet/AudiofileManager.cs | 81 ++++++- .../Services/AudioCuesheet/CuesheetManager.cs | 197 +++++++----------- .../AudioCuesheet/IAudiofileManager.cs | 6 + .../AudioCuesheet/ICuesheetManager.cs | 5 - .../Services/AudioCuesheet/TrackManager.cs | 91 ++++---- .../Services/IO/CuesheetExportService.cs | 69 +++--- .../Services/IO/ExportfileGenerator.cs | 70 ++++--- .../Services/IO/ImportManager.cs | 11 +- .../Shared/Cuesheet/Audiofiles.razor | 3 +- .../Shared/Record/AddTrack.razor | 19 +- .../Shared/TrackList/TrackList.razor | 35 ++-- 16 files changed, 402 insertions(+), 352 deletions(-) diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs index d8696bde..8cde6731 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs @@ -21,10 +21,6 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet { public class Cuesheet() : Validateable, ICuesheet { - //TODO: Move tracks below audiofiles - [JsonInclude] - public IEnumerable Tracks { get; set; } = []; - public String? Artist { get; set; } public String? Title { get; set; } @@ -47,46 +43,6 @@ public override ValidationResult Validate(string property) List? validationMessages = null; switch (property) { - case nameof(Tracks): - validationStatus = ValidationStatus.Success; - if (!Tracks.Any()) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Tracks), 0)); - } - else - { - //Check track overlapping - var tracksWithSamePosition = Tracks - .GroupBy(x => x.Position) - .Where(grp => grp.Count() > 1); - if (tracksWithSamePosition.Any()) - { - validationMessages ??= []; - foreach (var track in tracksWithSamePosition) - { - foreach (var trackWithSamePosition in track) - { - validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : String.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : String.Empty, trackWithSamePosition.Artist ?? String.Empty, trackWithSamePosition.Title ?? String.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : String.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : String.Empty)); - } - } - } - foreach (var track in Tracks.OrderBy(x => x.Position)) - { - var tracksBetween = Tracks.Where(x => ((track.Begin >= x.Begin && track.Begin < x.End) - || (x.Begin < track.End && track.End <= x.End)) - && (x.Equals(track) == false)); - if (tracksBetween.Any()) - { - validationMessages ??= []; - foreach (var trackBetween in tracksBetween) - { - validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : String.Empty, track.Artist ?? String.Empty, track.Title ?? String.Empty, track.Begin != null ? track.Begin : String.Empty, track.End != null ? track.End : String.Empty, trackBetween.Position != null ? trackBetween.Position : String.Empty, trackBetween.Artist ?? String.Empty, trackBetween.Title ?? String.Empty, trackBetween.Begin != null ? trackBetween.Begin : String.Empty, trackBetween.End != null ? trackBetween.End : String.Empty)); - } - } - } - } - break; case nameof(Audiofiles): validationStatus = ValidationStatus.Success; if (Audiofiles.Count == 0) diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs index 1efc32ef..b03764ae 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs @@ -67,8 +67,6 @@ public TimeSpan? Length } [JsonInclude] public IEnumerable Flags { get; set; } = []; - [JsonIgnore] - public Cuesheet? Cuesheet { get; set; } /// public TimeSpan? PreGap { get; set; } /// @@ -101,15 +99,16 @@ public override ValidationResult Validate(string property) else { // Check correct track position - if (Cuesheet != null) - { - var positionTrackShouldHave = Cuesheet.Tracks.OrderBy(x => x.Begin ?? TimeSpan.MaxValue).ThenBy(x => x.Position).ToList().IndexOf(this) + 1; - if (positionTrackShouldHave != Position) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? String.Empty, Title ?? String.Empty, Begin != null ? Begin : String.Empty, End != null ? End : String.Empty, positionTrackShouldHave)); - } - } + //TODO + //if (Cuesheet != null) + //{ + // var positionTrackShouldHave = Cuesheet.Tracks.OrderBy(x => x.Begin ?? TimeSpan.MaxValue).ThenBy(x => x.Position).ToList().IndexOf(this) + 1; + // if (positionTrackShouldHave != Position) + // { + // validationMessages ??= []; + // validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? String.Empty, Title ?? String.Empty, Begin != null ? Begin : String.Empty, End != null ? End : String.Empty, positionTrackShouldHave)); + // } + //} } } break; diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index 7601a716..20cfeb95 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -13,11 +13,13 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //. +using AudioCuesheetEditor.Model.AudioCuesheet; +using AudioCuesheetEditor.Model.Entity; using System.Text.Json.Serialization; namespace AudioCuesheetEditor.Model.IO.Audio { - public class Audiofile() + public class Audiofile() : Validateable { public static readonly AudioCodec AudioCodecWEBM = new("audio/webm", ".webm", "AudioCodec WEBM"); @@ -66,8 +68,10 @@ public String? Name _name = value; } } + [JsonIgnore] public String? ObjectURL { get; set; } + /// /// Duration of the audio file /// @@ -86,5 +90,58 @@ public AudioCodec? AudioCodec } } } + + public ICollection Tracks { get; set; } = []; + + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List? validationMessages = null; + switch (property) + { + //TODO: Validate Name, Audiocodec, etc. + case nameof(Tracks): + validationStatus = ValidationStatus.Success; + if (Tracks.Count == 0) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Tracks), 0)); + } + else + { + //Check track overlapping + var tracksWithSamePosition = Tracks + .GroupBy(x => x.Position) + .Where(grp => grp.Count() > 1); + if (tracksWithSamePosition.Any()) + { + validationMessages ??= []; + foreach (var track in tracksWithSamePosition) + { + foreach (var trackWithSamePosition in track) + { + validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : String.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : String.Empty, trackWithSamePosition.Artist ?? String.Empty, trackWithSamePosition.Title ?? String.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : String.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : String.Empty)); + } + } + } + foreach (var track in Tracks.OrderBy(x => x.Position)) + { + var tracksBetween = Tracks.Where(x => ((track.Begin >= x.Begin && track.Begin < x.End) + || (x.Begin < track.End && track.End <= x.End)) + && (x.Equals(track) == false)); + if (tracksBetween.Any()) + { + validationMessages ??= []; + foreach (var trackBetween in tracksBetween) + { + validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : String.Empty, track.Artist ?? String.Empty, track.Title ?? String.Empty, track.Begin != null ? track.Begin : String.Empty, track.End != null ? track.End : String.Empty, trackBetween.Position != null ? trackBetween.Position : String.Empty, trackBetween.Artist ?? String.Empty, trackBetween.Title ?? String.Empty, trackBetween.Begin != null ? trackBetween.Begin : String.Empty, trackBetween.End != null ? trackBetween.End : String.Empty)); + } + } + } + } + break; + } + return ValidationResult.Create(validationStatus, validationMessages); + } } } diff --git a/AudioCuesheetEditor/Model/IO/Projectfile.cs b/AudioCuesheetEditor/Model/IO/Projectfile.cs index a1e187bc..13833ac4 100644 --- a/AudioCuesheetEditor/Model/IO/Projectfile.cs +++ b/AudioCuesheetEditor/Model/IO/Projectfile.cs @@ -37,13 +37,14 @@ public class Projectfile(Cuesheet cuesheet) public static Cuesheet? ImportFile(string fileContent) { var cuesheet = JsonSerializer.Deserialize(fileContent, Options); - if (cuesheet != null) - { - foreach (var track in cuesheet.Tracks) - { - track.Cuesheet = cuesheet; - } - } + //TODO + //if (cuesheet != null) + //{ + // foreach (var track in cuesheet.Tracks) + // { + // track.Cuesheet = cuesheet; + // } + //} return cuesheet; } diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index af18e300..262fd931 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -46,7 +46,7 @@ private set } } } - public Track? CurrentlyPlayingTrack => _sessionStateContainer.Cuesheet.Tracks.SingleOrDefault(x => x.Begin.HasValue == true && x.End.HasValue == true && x.Begin <= CurrentPosition && x.End > CurrentPosition); + public Track? CurrentlyPlayingTrack => null;//TODO_sessionStateContainer.Cuesheet.Tracks.SingleOrDefault(x => x.Begin.HasValue == true && x.End.HasValue == true && x.Begin <= CurrentPosition && x.End > CurrentPosition); public TimeSpan? TotalTime => null; //TODO _sessionStateContainer.Cuesheet.Audiofile?.Duration; public Boolean IsPlaying { get; private set; } = false; public Boolean IsPlaybackPossible @@ -59,8 +59,8 @@ public Boolean IsPlaybackPossible return false; } } - public Boolean IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; - public Boolean IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; + public Boolean IsPreviousPossible => (CurrentlyPlayingTrack != null); //TODO && _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; + public Boolean IsNextPossible => (CurrentlyPlayingTrack != null); //TODO && _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; public PlaybackService(ISessionStateContainer sessionStateContainer, IHowl howl) { @@ -138,11 +138,12 @@ public async Task PlayNextTrackAsync() { if (CurrentlyPlayingTrack != null) { - var trackToPlay = _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End); - if (trackToPlay != null) - { - await PlayAsync(trackToPlay); - } + //TODO + //var trackToPlay = _sessionStateContainer.Cuesheet.Tracks.FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End); + //if (trackToPlay != null) + //{ + // await PlayAsync(trackToPlay); + //} } } @@ -150,11 +151,12 @@ public async Task PlayPreviousTrackAsync() { if (CurrentlyPlayingTrack != null) { - var trackToPlay = _sessionStateContainer.Cuesheet.Tracks.LastOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin); - if (trackToPlay != null) - { - await PlayAsync(trackToPlay); - } + //TODO + //var trackToPlay = _sessionStateContainer.Cuesheet.Tracks.LastOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin); + //if (trackToPlay != null) + //{ + // await PlayAsync(trackToPlay); + //} } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index 85b95a6e..a67b9b9b 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -13,6 +13,7 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //. +using AudioCuesheetEditor.Model.AudioCuesheet; using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Services.IO; using AudioCuesheetEditor.Services.UI; @@ -23,11 +24,13 @@ namespace AudioCuesheetEditor.Services.AudioCuesheet { - public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeManager traceChangeManager, IJSRuntime jsRuntime) : IAudiofileManager + public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeManager traceChangeManager, IJSRuntime jsRuntime, ITrackManager trackManager, ISessionStateContainer sessionStateContainer) : IAudiofileManager { private readonly IFileInputManager _fileInputManager = fileInputManager; private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; private readonly IJSRuntime _jsRuntime = jsRuntime; + private readonly ITrackManager _trackManager = trackManager; + private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; /// public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId) @@ -59,12 +62,69 @@ public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserF _traceChangeManager.BulkEdit = false; } + /// public void SetProperty(Audiofile audiofile, Expression> propertyExpression, TProperty value) { //TODO: Tests SetValue(audiofile, propertyExpression, value); } + /// + public void AddTrack(Audiofile audiofile, Track track) + { + //TODO: Tests + //Calculate track properties + _traceChangeManager.BulkEdit = true; + var cuesheet = _sessionStateContainer.GetActiveCuesheet(); + if (cuesheet?.IsRecording == true) + { + _trackManager.SetProperty(track, x => x.Begin, DateTime.UtcNow - cuesheet.RecordingStart); + } + if (cuesheet?.Audiofiles.SelectMany(x => x.Tracks).Any() == false) + { + _trackManager.SetProperty(track, x => x.Position, (ushort)(1)); + if ((track.Begin.HasValue == false) || cuesheet?.IsRecording == true) + { + _trackManager.SetProperty(track, x => x.Begin, TimeSpan.Zero); + } + } + else + { + //TODO: adapt to multiple audio files + var lastTrack = GetLastTrack(cuesheet!); + //if ((cuesheet?.Audiofile?.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == cuesheet.Audiofile.Duration)) + //{ + // _trackManager.SetProperty(lastTrack, x => x.End, null); + //} + if (track.Position.HasValue == false) + { + _trackManager.SetProperty(track, x => x.Position, (ushort?)(lastTrack?.Position + 1)); + } + if (track.Begin.HasValue == false) + { + _trackManager.SetProperty(track, x => x.Begin, lastTrack?.End); + } + else + { + if (lastTrack?.End.HasValue == false) + { + _trackManager.SetProperty(lastTrack, x => x.End, track.Begin); + } + } + if (cuesheet?.IsRecording == true && lastTrack != null) + { + _trackManager.SetProperty(lastTrack, x => x.End, track.Begin); + } + } + var newValue = new List(audiofile.Tracks) + { + track + }; + SetValue(audiofile, x => x.Tracks, newValue); + SetLastTrackEnd(cuesheet!); + _traceChangeManager.BulkEdit = false; + } + void SetValue(Audiofile audiofile, Expression> propertyExpression, TProperty value) { if (propertyExpression.Body is not MemberExpression memberExpression) @@ -86,5 +146,24 @@ void SetValue(Audiofile audiofile, Expression x.End, cuesheet.Audiofile.Duration); + //} + } + + static Track? GetLastTrack(Cuesheet cuesheet) + { + return cuesheet.Audiofiles.SelectMany(x => x.Tracks) + .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) + .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) + .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .LastOrDefault(); + } } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs index 47d851ee..384e5af9 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs @@ -50,10 +50,11 @@ public Result IsRecordingPossible { get { - if (_sessionStateContainer.Cuesheet.Tracks.Any()) - { - return Result.Failure(new Error(ErrorType.NotPossible, "Cuesheet already contains tracks!")); - } + //TODO + //if (_sessionStateContainer.Cuesheet.Tracks.Any()) + //{ + // return Result.Failure(new Error(ErrorType.NotPossible, "Cuesheet already contains tracks!")); + //} return Result.Success(); } } @@ -82,101 +83,47 @@ public void StopRecording() var cuesheet = _sessionStateContainer.Cuesheet; if (cuesheet.IsRecording == true) { - var lastTrack = cuesheet.Tracks.LastOrDefault(); - if ((lastTrack != null) && cuesheet.RecordingStart.HasValue) - { - lastTrack.End = DateTime.UtcNow - cuesheet.RecordingStart.Value; - } - cuesheet.RecordingStart = null; - IsRecordingChanged?.Invoke(this, EventArgs.Empty); - } - } - - /// - public void AddTrack(Track track) - { - var cuesheet = _sessionStateContainer.GetActiveCuesheet(); - track.Cuesheet = cuesheet; - // Calculate track properties - _traceChangeManager.BulkEdit = true; - if (cuesheet?.IsRecording == true) - { - _trackManager.SetProperty(track, x => x.Begin, DateTime.UtcNow - cuesheet.RecordingStart); - } - if (cuesheet?.Tracks.Any() == false) - { - _trackManager.SetProperty(track, x => x.Position, (ushort)(1)); - if ((track.Begin.HasValue == false) || cuesheet.IsRecording) - { - _trackManager.SetProperty(track, x => x.Begin, TimeSpan.Zero); - } - } - else - { - var lastTrack = GetLastTrack(cuesheet!); //TODO - //if ((cuesheet?.Audiofile?.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == cuesheet.Audiofile.Duration)) + //var lastTrack = cuesheet.Tracks.LastOrDefault(); + //if ((lastTrack != null) && cuesheet.RecordingStart.HasValue) //{ - // _trackManager.SetProperty(lastTrack, x => x.End, null); + // lastTrack.End = DateTime.UtcNow - cuesheet.RecordingStart.Value; //} - if (track.Position.HasValue == false) - { - _trackManager.SetProperty(track, x => x.Position, (ushort?)(lastTrack?.Position + 1)); - } - if (track.Begin.HasValue == false) - { - _trackManager.SetProperty(track, x => x.Begin, lastTrack?.End); - } - else - { - if (lastTrack?.End.HasValue == false) - { - _trackManager.SetProperty(lastTrack, x => x.End, track.Begin); - } - } - if (cuesheet?.IsRecording == true && lastTrack != null) - { - _trackManager.SetProperty(lastTrack, x => x.End, track.Begin); - } + cuesheet.RecordingStart = null; + IsRecordingChanged?.Invoke(this, EventArgs.Empty); } - var newValue = new List(cuesheet!.Tracks) - { - track - }; - SetValue(cuesheet, x => x.Tracks, newValue); - SetLastTrackEnd(cuesheet); - _traceChangeManager.BulkEdit = false; } /// public void RemoveTracks(IEnumerable tracksToRemove) { var cuesheet = _sessionStateContainer.GetActiveCuesheet(); - var intersection = cuesheet!.Tracks.Intersect(tracksToRemove); - ICollection newValue = [.. cuesheet.Tracks.Except(intersection)]; - //Calculate position and begin of new tracks - ushort position = 1; - foreach (var track in newValue.OrderBy(x => x.Position)) - { - track.Position = position; - position++; - var previousTrack = _trackManager.GetPreviousLinkedTrack(track); - if (previousTrack?.End.HasValue == true) - { - track.Begin = previousTrack.End; - } - } - _traceChangeManager.BulkEdit = true; - SetValue(cuesheet, x => x.Tracks, newValue); - SetLastTrackEnd(cuesheet); - _traceChangeManager.BulkEdit = false; + //TODO + //var intersection = cuesheet!.Tracks.Intersect(tracksToRemove); + //ICollection newValue = [.. cuesheet.Tracks.Except(intersection)]; + ////Calculate position and begin of new tracks + //ushort position = 1; + //foreach (var track in newValue.OrderBy(x => x.Position)) + //{ + // track.Position = position; + // position++; + // var previousTrack = _trackManager.GetPreviousLinkedTrack(track); + // if (previousTrack?.End.HasValue == true) + // { + // track.Begin = previousTrack.End; + // } + //} + //_traceChangeManager.BulkEdit = true; + //SetValue(cuesheet, x => x.Tracks, newValue); + //SetLastTrackEnd(cuesheet); + //_traceChangeManager.BulkEdit = false; } /// public bool IsMoveTracksUpPossible(HashSet selectedTracks) => selectedTracks.Count > 0 && selectedTracks.Min(x => x.Position) >= 2; /// - public bool IsMoveTracksDownPossible(HashSet selectedTracks) => selectedTracks.Count > 0 && selectedTracks.Max(x => x.Position) < _sessionStateContainer.GetActiveCuesheet()?.Tracks.Max(x => x.Position); + public bool IsMoveTracksDownPossible(HashSet selectedTracks) => selectedTracks.Count > 0; //TODO && selectedTracks.Max(x => x.Position) < _sessionStateContainer.GetActiveCuesheet()?.Tracks.Max(x => x.Position); /// public Result MoveTracksUp(HashSet selectedTracks) @@ -187,22 +134,23 @@ public Result MoveTracksUp(HashSet selectedTracks) } _traceChangeManager.BulkEdit = true; var cuesheet = _sessionStateContainer.GetActiveCuesheet(); - foreach (var selectedTrack in selectedTracks.OrderBy(x => x.Position)) - { - var previousTrack = cuesheet?.Tracks.FirstOrDefault(x => x.Position == selectedTrack.Position - 1); - var newBegin = previousTrack?.Begin; - var newEnd = previousTrack?.End; - if (previousTrack != null) - { - _trackManager.SetProperty(previousTrack, x => x.Position, selectedTrack.Position); - _trackManager.SetProperty(previousTrack, x => x.Begin, selectedTrack.Begin); - _trackManager.SetProperty(previousTrack, x => x.End, selectedTrack.End); - } - _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position - 1)); - _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); - _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); - } - SetValue(cuesheet!, x => x.Tracks, cuesheet?.Tracks.OrderBy(x => x.Position)); + //TODO + //foreach (var selectedTrack in selectedTracks.OrderBy(x => x.Position)) + //{ + // var previousTrack = cuesheet?.Tracks.FirstOrDefault(x => x.Position == selectedTrack.Position - 1); + // var newBegin = previousTrack?.Begin; + // var newEnd = previousTrack?.End; + // if (previousTrack != null) + // { + // _trackManager.SetProperty(previousTrack, x => x.Position, selectedTrack.Position); + // _trackManager.SetProperty(previousTrack, x => x.Begin, selectedTrack.Begin); + // _trackManager.SetProperty(previousTrack, x => x.End, selectedTrack.End); + // } + // _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position - 1)); + // _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); + // _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); + //} + //SetValue(cuesheet!, x => x.Tracks, cuesheet?.Tracks.OrderBy(x => x.Position)); _traceChangeManager.BulkEdit = false; return Result.Success(); } @@ -215,25 +163,26 @@ public Result MoveTracksDown(HashSet selectedTracks) { return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks down is not possible!")); } - _traceChangeManager.BulkEdit = true; - foreach (var selectedTrack in selectedTracks.OrderByDescending(x => x.Position)) - { - var nextTrack = cuesheet?.Tracks.FirstOrDefault(x => x.Position == selectedTrack.Position + 1); - var newBegin = nextTrack?.Begin; - var newEnd = nextTrack?.End; - if (nextTrack != null) - { - _trackManager.SetProperty(nextTrack, x => x.Position, selectedTrack.Position); - _trackManager.SetProperty(nextTrack, x => x.Begin, selectedTrack.Begin); - _trackManager.SetProperty(nextTrack, x => x.End, selectedTrack.End); - } - var newPosition = (ushort?)(selectedTrack.Position + 1); - _trackManager.SetProperty(selectedTrack, x => x.Position, newPosition); - _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); - _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); - } - SetValue(cuesheet!, x => x.Tracks, cuesheet?.Tracks.OrderBy(x => x.Position)); - _traceChangeManager.BulkEdit = false; + //TODO + //_traceChangeManager.BulkEdit = true; + //foreach (var selectedTrack in selectedTracks.OrderByDescending(x => x.Position)) + //{ + // var nextTrack = cuesheet?.Tracks.FirstOrDefault(x => x.Position == selectedTrack.Position + 1); + // var newBegin = nextTrack?.Begin; + // var newEnd = nextTrack?.End; + // if (nextTrack != null) + // { + // _trackManager.SetProperty(nextTrack, x => x.Position, selectedTrack.Position); + // _trackManager.SetProperty(nextTrack, x => x.Begin, selectedTrack.Begin); + // _trackManager.SetProperty(nextTrack, x => x.End, selectedTrack.End); + // } + // var newPosition = (ushort?)(selectedTrack.Position + 1); + // _trackManager.SetProperty(selectedTrack, x => x.Position, newPosition); + // _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); + // _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); + //} + //SetValue(cuesheet!, x => x.Tracks, cuesheet?.Tracks.OrderBy(x => x.Position)); + //_traceChangeManager.BulkEdit = false; return Result.Success(); } @@ -272,11 +221,13 @@ void SetLastTrackEnd(Cuesheet cuesheet) static Track? GetLastTrack(Cuesheet cuesheet) { - return cuesheet.Tracks - .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) - .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) - .LastOrDefault(); + //TODO + return null; + //return cuesheet.Tracks + // .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) + // .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) + // .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + // .LastOrDefault(); } } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs index cc16d8be..709a064b 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs @@ -13,6 +13,7 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //. +using AudioCuesheetEditor.Model.AudioCuesheet; using AudioCuesheetEditor.Model.IO.Audio; using Microsoft.AspNetCore.Components.Forms; using System.Linq.Expressions; @@ -36,5 +37,10 @@ public interface IAudiofileManager /// /// void SetProperty(Audiofile audiofile, Expression> propertyExpression, TProperty value); + /// + /// Adds a track to the audiofile + /// + /// + void AddTrack(Audiofile audiofile, Track track); } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs index 460264ff..7af44179 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs @@ -50,11 +50,6 @@ public interface ICuesheetManager /// void StopRecording(); /// - /// Adds a track to the cuesheet - /// - /// - void AddTrack(Track track); - /// /// Remove tracks from cuesheet /// /// diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs index cbffeb9b..0849600d 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs @@ -110,62 +110,65 @@ public void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTr { return null; } - if (track.Position.HasValue && (track.Cuesheet?.Tracks.All(x => x.Position.HasValue) == true)) - { - return track.Cuesheet?.Tracks.LastOrDefault(x => x.Position == track.Position - 1 && Equals(x, track) == false); - } - if (track.Begin.HasValue) - { - return track.Cuesheet?.Tracks.OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); - } + //TODO + //if (track.Position.HasValue && (track.Cuesheet?.Tracks.All(x => x.Position.HasValue) == true)) + //{ + // return track.Cuesheet?.Tracks.LastOrDefault(x => x.Position == track.Position - 1 && Equals(x, track) == false); + //} + //if (track.Begin.HasValue) + //{ + // return track.Cuesheet?.Tracks.OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); + //} return null; } /// public Track? GetNextLinkedTrack(Track track) { - if (track.Position.HasValue && (track.Cuesheet?.Tracks.All(x => x.Position.HasValue) == true)) - { - return track.Cuesheet?.Tracks.OrderBy(x => x.Begin).FirstOrDefault(x => x.Position >= track.Position.Value + 1 && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); - } - if (track.End.HasValue) - { - return track.Cuesheet?.Tracks.OrderBy(x => x.Begin).LastOrDefault(x => x.Begin <= track.End && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); - } + //TODO + //if (track.Position.HasValue && (track.Cuesheet?.Tracks.All(x => x.Position.HasValue) == true)) + //{ + // return track.Cuesheet?.Tracks.OrderBy(x => x.Begin).FirstOrDefault(x => x.Position >= track.Position.Value + 1 && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); + //} + //if (track.End.HasValue) + //{ + // return track.Cuesheet?.Tracks.OrderBy(x => x.Begin).LastOrDefault(x => x.Begin <= track.End && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); + //} return null; } /// public void RecalculateLinkedTracksProperties(Track track) { - if (track.Cuesheet != null) - { - var previousTrack = GetPreviousLinkedTrack(track); - if (previousTrack != null) - { - if (track.Position.HasValue == false && previousTrack.Position.HasValue && (track.Position != previousTrack.Position.Value + 1)) - { - SetValue(track, x => x.Position, (ushort?)(previousTrack.Position + 1)); - } - if (previousTrack.End.HasValue && (track.Begin != previousTrack.End)) - { - SetValue(track, x => x.Begin, previousTrack.End); - } - if ((previousTrack.End.HasValue == false) && track.Begin.HasValue) - { - SetValue(previousTrack, x => x.End, track.Begin); - } - } - var nextTrack = GetNextLinkedTrack(track); - if (nextTrack != null) - { - if (track.Position.HasValue) - { - SetValue(nextTrack, x => x.Position, (ushort?)(track.Position + 1)); - } - SetValue(nextTrack, x => x.Begin, track.End); - } - } + //TODO + //if (track.Cuesheet != null) + //{ + // var previousTrack = GetPreviousLinkedTrack(track); + // if (previousTrack != null) + // { + // if (track.Position.HasValue == false && previousTrack.Position.HasValue && (track.Position != previousTrack.Position.Value + 1)) + // { + // SetValue(track, x => x.Position, (ushort?)(previousTrack.Position + 1)); + // } + // if (previousTrack.End.HasValue && (track.Begin != previousTrack.End)) + // { + // SetValue(track, x => x.Begin, previousTrack.End); + // } + // if ((previousTrack.End.HasValue == false) && track.Begin.HasValue) + // { + // SetValue(previousTrack, x => x.End, track.Begin); + // } + // } + // var nextTrack = GetNextLinkedTrack(track); + // if (nextTrack != null) + // { + // if (track.Position.HasValue) + // { + // SetValue(nextTrack, x => x.Position, (ushort?)(track.Position + 1)); + // } + // SetValue(nextTrack, x => x.Begin, track.End); + // } + //} } void SetValue(Track track, Expression> propertyExpression, TProperty value) diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index 766e9e7b..cad42f8f 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -38,7 +38,8 @@ public Result CanGenerateExportfile(string? filename) validationMessages.Add(new ValidationMessage("File extension is not '{0}'", FileExtensions.Cuesheet)); } validationMessages.AddRange(_sessionStateContainer.Cuesheet.Validate().ValidationMessages); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Tracks.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); + //TODO + //validationMessages.AddRange(_sessionStateContainer.Cuesheet.Tracks.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); if (validationMessages.Count != 0) { return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); @@ -82,39 +83,39 @@ private string WriteCuesheet(string? audiofileName) builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); //TODO //builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofileName, _sessionStateContainer.Cuesheet.Audiofile?.AudioFileType)); - IEnumerable tracks = _sessionStateContainer.Cuesheet.Tracks.OrderBy(x => x.Position); - if (tracks.Any()) - { - //Position and begin should always start from 0 even with splitpoints - int positionDifference = 1 - Convert.ToInt32(tracks.First().Position); - foreach (var track in tracks) - { - builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position + positionDifference, CuesheetConstants.CuesheetTrackAudio)); - builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); - builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); - if (track.Flags.Any()) - { - builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); - } - if (track.PreGap.HasValue) - { - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); - } - if (track.Begin.HasValue) - { - var begin = track.Begin.Value; - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); - } - else - { - throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); - } - if (track.PostGap.HasValue) - { - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); - } - } - } + //IEnumerable tracks = _sessionStateContainer.Cuesheet.Tracks.OrderBy(x => x.Position); + //if (tracks.Any()) + //{ + // //Position and begin should always start from 0 even with splitpoints + // int positionDifference = 1 - Convert.ToInt32(tracks.First().Position); + // foreach (var track in tracks) + // { + // builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position + positionDifference, CuesheetConstants.CuesheetTrackAudio)); + // builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); + // builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); + // if (track.Flags.Any()) + // { + // builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); + // } + // if (track.PreGap.HasValue) + // { + // builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); + // } + // if (track.Begin.HasValue) + // { + // var begin = track.Begin.Value; + // builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); + // } + // else + // { + // throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); + // } + // if (track.PostGap.HasValue) + // { + // builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); + // } + // } + //} return builder.ToString(); } } diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index b2f44b54..f0d2eded 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -33,7 +33,8 @@ public Result CanGenerateExportfile(Exportprofile exportprofile) List validationMessages = []; validationMessages.AddRange(exportprofile.Validate().ValidationMessages); validationMessages.AddRange(_sessionStateContainer.Cuesheet.Validate().ValidationMessages); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Tracks.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); + //TODO + //validationMessages.AddRange(_sessionStateContainer.Cuesheet.Tracks.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); if (validationMessages.Count != 0) { return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); @@ -72,39 +73,40 @@ private string WriteExport(Exportprofile exportprofile, string? audiofileName) .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); builder.AppendLine(header); - IEnumerable tracks = _sessionStateContainer.Cuesheet.Tracks.OrderBy(x => x.Position); - if (tracks.Any()) - { - //Position, Begin and End should always start from 0 even with splitpoints - int positionDifference = 1 - Convert.ToInt32(tracks.First().Position); - foreach (var track in tracks) - { - TimeSpan begin; - var end = track.End; - if (track.Begin.HasValue) - { - begin = track.Begin.Value; - } - else - { - throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); - } - var trackLine = exportprofile.SchemeTracks - .Replace(Exportprofile.SchemeTrackArtist, track.Artist) - .Replace(Exportprofile.SchemeTrackTitle, track.Title) - .Replace(Exportprofile.SchemeTrackPosition, (track.Position + positionDifference).ToString()) - .Replace(Exportprofile.SchemeTrackBegin, begin.ToString()) - .Replace(Exportprofile.SchemeTrackEnd, end.ToString()) - .Replace(Exportprofile.SchemeTrackLength, (end - begin).ToString()) - .Replace(Exportprofile.SchemeTrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))) - .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty) - .Replace(Exportprofile.SchemeTrackPostGap, track.PostGap != null ? track.PostGap.Value.ToString() : string.Empty) - .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) - .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(trackLine); - } - } + //TODO + //IEnumerable tracks = _sessionStateContainer.Cuesheet.Tracks.OrderBy(x => x.Position); + //if (tracks.Any()) + //{ + // //Position, Begin and End should always start from 0 even with splitpoints + // int positionDifference = 1 - Convert.ToInt32(tracks.First().Position); + // foreach (var track in tracks) + // { + // TimeSpan begin; + // var end = track.End; + // if (track.Begin.HasValue) + // { + // begin = track.Begin.Value; + // } + // else + // { + // throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); + // } + // var trackLine = exportprofile.SchemeTracks + // .Replace(Exportprofile.SchemeTrackArtist, track.Artist) + // .Replace(Exportprofile.SchemeTrackTitle, track.Title) + // .Replace(Exportprofile.SchemeTrackPosition, (track.Position + positionDifference).ToString()) + // .Replace(Exportprofile.SchemeTrackBegin, begin.ToString()) + // .Replace(Exportprofile.SchemeTrackEnd, end.ToString()) + // .Replace(Exportprofile.SchemeTrackLength, (end - begin).ToString()) + // .Replace(Exportprofile.SchemeTrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))) + // .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty) + // .Replace(Exportprofile.SchemeTrackPostGap, track.PostGap != null ? track.PostGap.Value.ToString() : string.Empty) + // .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) + // .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + // .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); + // builder.AppendLine(trackLine); + // } + //} var footer = exportprofile.SchemeFooter .Replace(Exportprofile.SchemeCuesheetArtist, _sessionStateContainer.Cuesheet.Artist) .Replace(Exportprofile.SchemeCuesheetTitle, _sessionStateContainer.Cuesheet.Title) diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 542fa964..3d0ec5aa 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -187,8 +187,8 @@ private void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) IEnumerable? tracks = null; if (cuesheetToCopy is Cuesheet originCuesheet) { - tracks = originCuesheet.Tracks; //TODO + //tracks = originCuesheet.Tracks; //target.Audiofile = originCuesheet.Audiofile; target.CDTextfile = originCuesheet.CDTextfile; target.Cataloguenumber = originCuesheet.Cataloguenumber; @@ -245,7 +245,8 @@ private void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) } // Copy track var track = _trackManager.Clone(importTrack); - track.Cuesheet = target; + //TODO + //track.Cuesheet = target; // Special treatment for StartDateTime of ImportTrack if (importTrack is ImportTrack importTrackReference && importTrackReference.StartDateTime != null && nextTrack is ImportTrack nextImportTrackReference) { @@ -270,7 +271,8 @@ private void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) position++; targetTracks.Add(track); } - target.Tracks = targetTracks; + //TODO + //target.Tracks = targetTracks; } else { @@ -282,7 +284,8 @@ private void ResetTracing() { if (_sessionStateContainer.ImportCuesheet != null) { - _traceChangeManager.RemoveTracedChanges([_sessionStateContainer.ImportCuesheet, .. _sessionStateContainer.ImportCuesheet.Tracks]); + //TODO + //_traceChangeManager.RemoveTracedChanges([_sessionStateContainer.ImportCuesheet, .. _sessionStateContainer.ImportCuesheet.Tracks]); } } } diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 485355b4..a790b79a 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -59,14 +59,13 @@ along with Foobar. If not, see - +
} @code { - //TODO: Tracklist below each file //TODO: Localization Cuesheet? _cuesheet => _sessionStateContainer.GetActiveCuesheet(); diff --git a/AudioCuesheetEditor/Shared/Record/AddTrack.razor b/AudioCuesheetEditor/Shared/Record/AddTrack.razor index d461b00a..e07848f5 100644 --- a/AudioCuesheetEditor/Shared/Record/AddTrack.razor +++ b/AudioCuesheetEditor/Shared/Record/AddTrack.razor @@ -132,15 +132,16 @@ along with Foobar. If not, see { if (Cuesheet.IsRecording == true) { - _cuesheetManager.AddTrack(_currentRecordingTrack); - _currentRecordingTrack = new() - { - IsLinkedToPreviousTrack = _applicationOptions!.DefaultIsLinkedToPreviousTrack - }; - if (_artistInput != null) - { - await _artistInput.FocusAsync(); - } + //TODO + // _cuesheetManager.AddTrack(_currentRecordingTrack); + // _currentRecordingTrack = new() + // { + // IsLinkedToPreviousTrack = _applicationOptions!.DefaultIsLinkedToPreviousTrack + // }; + // if (_artistInput != null) + // { + // await _artistInput.FocusAsync(); + // } } } diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor b/AudioCuesheetEditor/Shared/TrackList/TrackList.razor index ecf47026..07e4715a 100644 --- a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor +++ b/AudioCuesheetEditor/Shared/TrackList/TrackList.razor @@ -29,12 +29,13 @@ along with Foobar. If not, see @inject ITrackManager _trackManager @inject ICuesheetManager _cuesheetManager @inject ITraceChangeManager _traceChangeManager +@inject IAudiofileManager _audiofileManager @switch (CurrentViewMode) { case ViewMode.DetailView: case ViewMode.ImportView: - var validationResult = Cuesheet?.Validate(nameof(Cuesheet.Tracks)); + var validationResult = Audiofile.Validate(nameof(Audiofile.Tracks)); if (validationResult?.Status == ValidationStatus.Error) { @@ -48,7 +49,7 @@ along with Foobar. If not, see
- @@ -108,7 +109,7 @@ along with Foobar. If not, see