diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs index f5760424..88f9033d 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs @@ -28,6 +28,7 @@ public class ImportTrack : ITrack public IReadOnlyCollection Flags => flags; public TimeSpan? PreGap { get; set; } public TimeSpan? PostGap { get; set; } + public DateTime? StartDateTime { get; set; } public void SetFlags(IEnumerable flags) { this.flags.Clear(); diff --git a/AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs b/AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs index 7eab81b1..f5d3e865 100644 --- a/AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs +++ b/AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs @@ -14,6 +14,7 @@ //along with Foobar. If not, see //. using AudioCuesheetEditor.Model.AudioCuesheet; +using AudioCuesheetEditor.Model.AudioCuesheet.Import; using AudioCuesheetEditor.Model.Entity; using Blazorise.Localization; @@ -54,6 +55,7 @@ static TextImportScheme() var schemeTrackFlags = String.Format("(?'{0}.{1}'{2})", nameof(Track), nameof(Track.Flags), EnterRegularExpressionHere); var schemeTrackPreGap = String.Format("(?'{0}.{1}'{2})", nameof(Track), nameof(Track.PreGap), EnterRegularExpressionHere); var schemeTrackPostGap = String.Format("(?'{0}.{1}'{2})", nameof(Track), nameof(Track.PostGap), EnterRegularExpressionHere); + var schemeTrackStartDateTime = String.Format("(?'{0}.{1}'{2})", nameof(Track), nameof(ImportTrack.StartDateTime), EnterRegularExpressionHere); AvailableSchemesTrack = new Dictionary { @@ -65,7 +67,8 @@ static TextImportScheme() { nameof(Track.Length), schemeTrackLength }, { nameof(Track.Flags), schemeTrackFlags }, { nameof(Track.PreGap), schemeTrackPreGap }, - { nameof(Track.PostGap), schemeTrackPostGap } + { nameof(Track.PostGap), schemeTrackPostGap }, + { nameof(ImportTrack.StartDateTime), schemeTrackStartDateTime } }; } diff --git a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs index b2b58e12..79f88022 100644 --- a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs @@ -13,7 +13,6 @@ //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 AudioCuesheetEditor.Model.IO; using AudioCuesheetEditor.Model.IO.Export; diff --git a/AudioCuesheetEditor/Resources/Localization/EditImportOptions/de.json b/AudioCuesheetEditor/Resources/Localization/EditImportOptions/de.json index 393b254f..1d41f3e2 100644 --- a/AudioCuesheetEditor/Resources/Localization/EditImportOptions/de.json +++ b/AudioCuesheetEditor/Resources/Localization/EditImportOptions/de.json @@ -27,6 +27,7 @@ "Hours": "Stunden", "Minutes": "Minuten", "Seconds": "Sekunden", - "Milliseconds": "Millisekunden" + "Milliseconds": "Millisekunden", + "StartDateTime": "Startzeitpunkt" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Resources/Localization/EditImportOptions/en.json b/AudioCuesheetEditor/Resources/Localization/EditImportOptions/en.json index bd91ef70..b453cd98 100644 --- a/AudioCuesheetEditor/Resources/Localization/EditImportOptions/en.json +++ b/AudioCuesheetEditor/Resources/Localization/EditImportOptions/en.json @@ -26,6 +26,7 @@ "Hours": "Hours", "Minutes": "Minutes", "Seconds": "Seconds", - "Milliseconds": "Milliseconds" + "Milliseconds": "Milliseconds", + "StartDateTime": "Startdatetime" } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 278c4080..8eca0d48 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -167,10 +167,29 @@ private async Task CopyCuesheetAsync(Cuesheet target, ICuesheet cuesheetToCopy) if (tracks != null) { var applicationOptions = await _localStorageOptionsProvider.GetOptions(); - foreach (var importTrack in tracks) + var begin = TimeSpan.Zero; + for (int i = 0; i < tracks.Count(); i++) { + var importTrack = tracks.ElementAt(i); //We don't want to copy the cuesheet reference since we are doing a copy and want to assign the track to this object var track = new Track(importTrack, false); + if (importTrack is ImportTrack importTrackReference) + { + if (importTrackReference.StartDateTime != null) + { + if (i < tracks.Count() - 1) + { + var nextTrack = (ImportTrack)tracks.ElementAt(i + 1); + var length = nextTrack.StartDateTime - importTrackReference.StartDateTime; + track.Begin = begin; + track.End = begin + length; + if (track.End.HasValue) + { + begin = track.End.Value; + } + } + } + } target.AddTrack(track, applicationOptions); } } diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index 7d1836fd..c90ce366 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -156,6 +156,13 @@ private void SetValue(object entity, PropertyInfo property, string value) { ((Cuesheet)entity).Cataloguenumber.Value = value; } + if (property.PropertyType == typeof(DateTime?)) + { + if (DateTime.TryParse(value, out var date)) + { + property.SetValue(entity, date); + } + } } } } diff --git a/AudioCuesheetEditorTests/Extensions/SessionStateContainerTests.cs b/AudioCuesheetEditorTests/Extensions/SessionStateContainerTests.cs index c18c1854..885fe83e 100644 --- a/AudioCuesheetEditorTests/Extensions/SessionStateContainerTests.cs +++ b/AudioCuesheetEditorTests/Extensions/SessionStateContainerTests.cs @@ -1,13 +1,22 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using AudioCuesheetEditor.Extensions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AudioCuesheetEditorTests.Utility; -using AudioCuesheetEditor.Model.UI; +//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.AudioCuesheet; +using AudioCuesheetEditor.Model.UI; +using AudioCuesheetEditorTests.Utility; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace AudioCuesheetEditor.Extensions.Tests { diff --git a/AudioCuesheetEditorTests/Model/UI/TraceChangeManagerTests.cs b/AudioCuesheetEditorTests/Model/UI/TraceChangeManagerTests.cs index 254f39f7..fe31187a 100644 --- a/AudioCuesheetEditorTests/Model/UI/TraceChangeManagerTests.cs +++ b/AudioCuesheetEditorTests/Model/UI/TraceChangeManagerTests.cs @@ -1,21 +1,34 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using AudioCuesheetEditor.Model.UI; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +//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.Data.Options; +using AudioCuesheetEditor.Extensions; using AudioCuesheetEditor.Model.AudioCuesheet; -using AudioCuesheetEditorTests.Utility; -using AudioCuesheetEditor.Model.IO.Import; -using System.IO; -using AudioCuesheetEditorTests.Properties; using AudioCuesheetEditor.Model.Entity; +using AudioCuesheetEditor.Model.IO.Import; using AudioCuesheetEditor.Model.Options; using AudioCuesheetEditor.Services.IO; -using AudioCuesheetEditor.Extensions; -using AudioCuesheetEditor.Data.Options; +using AudioCuesheetEditorTests.Properties; +using AudioCuesheetEditorTests.Utility; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; namespace AudioCuesheetEditor.Model.UI.Tests { diff --git a/AudioCuesheetEditorTests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditorTests/Services/IO/ImportManagerTests.cs new file mode 100644 index 00000000..bd98e833 --- /dev/null +++ b/AudioCuesheetEditorTests/Services/IO/ImportManagerTests.cs @@ -0,0 +1,111 @@ +//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.Data.Options; +using AudioCuesheetEditor.Extensions; +using AudioCuesheetEditor.Model.IO.Import; +using AudioCuesheetEditor.Model.Options; +using AudioCuesheetEditor.Model.UI; +using AudioCuesheetEditorTests.Utility; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace AudioCuesheetEditor.Services.IO.Tests +{ + [TestClass()] + public class ImportManagerTests + { + [TestMethod()] + public async Task ImportTextAsync_TextfileWithStartDateTime_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = new List + { + "Innellea~The Golden Fort~02.08.2024 20:10:48", + "Nora En Pure~Diving with Whales (Daniel Portman Remix)~02.08.2024 20:15:21", + "WhoMadeWho & Adriatique~Miracle (RÜFÜS DU SOL Remix)~02.08.2024 20:20:42", + "Ella Wild~Poison D'araignee (Original Mix)~02.08.2024 20:28:03", + "Stil & Bense~On The Edge (Original Mix)~02.08.2024 20:32:42", + "Nebula~Clairvoyant Dreams~02.08.2024 20:39:01", + "Valentina Black~I'm a Tree (Extended Mix)~02.08.2024 20:47:08", + "Nebula~Clairvoyant Dreams~02.08.2024 20:53:20", + "Kiko & Dave Davis feat. Phoebe~Living in Space (Dub Mix)~02.08.2024 20:58:11", + "Lilly Palmer~Before Acid~02.08.2024 21:03:53", + "Sofi Tukker~Drinkee (Vintage Culture & John Summit Extended Mix)~02.08.2024 21:09:52", + "CID & Truth x Lies~Caroline (Extended Mix)~02.08.2024 21:14:09", + "Moby~Why Does My Heart Feel So Bad? (Oxia Remix)~02.08.2024 21:17:15", + "Ammo Avenue~Little Gurl (Extended Mix)~02.08.2024 21:22:46", + "James Hurr & Smokin Jo & Stealth~Beggin' For Change~02.08.2024 21:28:37", + "Kristine Blond~Love Shy (Sam Divine & CASSIMM Extended Remix)~02.08.2024 21:30:47", + "Vanilla Ace~Work On You (Original Mix)~02.08.2024 21:36:28", + "Truth X Lies~Like This~02.08.2024 21:42:05", + "Terri-Anne~Round Round~02.08.2024 21:44:07", + "Joanna Magik~Maneater~02.08.2024 21:46:32", + "Jen Payne & Kevin McKay~Feed Your Soul~02.08.2024 21:48:45", + "Kevin McKay & Eppers & Notelle~On My Own~02.08.2024 21:51:37", + "Nader Razdar & Kevin McKay~Get Ur Freak On (Kevin McKay Extended Mix)~02.08.2024 21:53:49", + "Philip Z~Yala (Extended Mix)~02.08.2024 21:59:40", + "Kyle Kinch & Kevin McKay~Hella~02.08.2024 22:05:53", + "Roze Wild~B-O-D-Y~02.08.2024 22:08:26", + "Jey Kurmis~Snoop~02.08.2024 22:11:09", + "Bootie Brown & Tame Impala & Gorillaz~New Gold (Dom Dolla Remix Extended)~02.08.2024 22:16:23", + "Eli Brown & Love Regenerator~Don't You Want Me (Original Mix)~02.08.2024 22:21:23", + "Local Singles~Voices~02.08.2024 22:25:59" + }; + + var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger()); + var sessionStateContainer = new SessionStateContainer(traceChangeManager); + var localStorageOptionsProviderMock = new Mock(); + var importOptions = new ImportOptions + { + TextImportScheme = new TextImportScheme() + { + SchemeCuesheet = null, + SchemeTracks = @"(?'Track.Artist'[a-zA-Z0-9_ .();äöü&:,'*-?:]{1,})~(?'Track.Title'[a-zA-Z0-9_ .();äöü&'*-?:Ü]{1,})~(?'Track.StartDateTime'.{1,})" + } + }; + localStorageOptionsProviderMock.Setup(x => x.GetOptions()).ReturnsAsync(importOptions); + var textImportService = new TextImportService(); + var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, textImportService, traceChangeManager); + var testHelper = new TestHelper(); + // Act + await importManager.ImportTextAsync(fileContent); + // Assert + Assert.IsNull(sessionStateContainer.Importfile?.AnalyseException); + Assert.IsNotNull(sessionStateContainer.ImportCuesheet); + Assert.AreEqual(30, sessionStateContainer.ImportCuesheet.Tracks.Count); + Assert.AreEqual("Innellea", sessionStateContainer.ImportCuesheet.Tracks.ElementAt(0).Artist); + Assert.AreEqual("The Golden Fort", sessionStateContainer.ImportCuesheet.Tracks.ElementAt(0).Title); + Assert.AreEqual(TimeSpan.Zero, sessionStateContainer.ImportCuesheet.Tracks.ElementAt(0).Begin); + Assert.AreEqual(new TimeSpan(0, 4, 33), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(0).End); + Assert.AreEqual(new TimeSpan(0, 4, 33), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(0).Length); + Assert.AreEqual("Nora En Pure", sessionStateContainer.ImportCuesheet.Tracks.ElementAt(1).Artist); + Assert.AreEqual("Diving with Whales (Daniel Portman Remix)", sessionStateContainer.ImportCuesheet.Tracks.ElementAt(1).Title); + Assert.AreEqual(new TimeSpan(0, 4, 33), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(1).Begin); + Assert.AreEqual(new TimeSpan(0, 9, 54), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(1).End); + Assert.AreEqual(new TimeSpan(0, 5, 21), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(1).Length); + Assert.AreEqual("Local Singles", sessionStateContainer.ImportCuesheet.Tracks.ElementAt(29).Artist); + Assert.AreEqual("Voices", sessionStateContainer.ImportCuesheet.Tracks.ElementAt(29).Title); + Assert.AreEqual(new TimeSpan(2, 15, 11), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(29).Begin); + Assert.IsNull(sessionStateContainer.ImportCuesheet.Tracks.ElementAt(29).End); + Assert.IsNull(sessionStateContainer.ImportCuesheet.Tracks.ElementAt(29).Length); + } + } +} \ No newline at end of file