diff --git a/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj b/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj
index 1611da6b..5fbad912 100644
--- a/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj
+++ b/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj
@@ -16,11 +16,11 @@
-
-
+
+
-
-
+
+
@@ -41,11 +41,23 @@
PreserveNewest
PreserveNewest
+
+ PreserveNewest
+
true
PreserveNewest
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
diff --git a/AudioCuesheetEditor.End2EndTests/Pages/IndexTest.cs b/AudioCuesheetEditor.End2EndTests/Pages/IndexTest.cs
index dd2b7265..8dbe4c4f 100644
--- a/AudioCuesheetEditor.End2EndTests/Pages/IndexTest.cs
+++ b/AudioCuesheetEditor.End2EndTests/Pages/IndexTest.cs
@@ -68,6 +68,7 @@ public async Task RecordAsync()
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).FillAsync("Test Track 2 Title");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).PressAsync("Tab");
await Page.GetByRole(AriaRole.Button, new() { Name = "Add track" }).ClickAsync();
+ await Page.Locator(".mud-overlay").ClickAsync();
await Page.GetByRole(AriaRole.Button, new() { Name = "Stop recording" }).ClickAsync();
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Artist Clear" })).ToBeVisibleAsync();
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Title Clear" })).ToBeVisibleAsync();
@@ -153,5 +154,139 @@ public async Task RenameAudiofileTestAsync()
await Page.GetByRole(AriaRole.Button, new() { Name = "Ok" }).ClickAsync();
await Expect(Page.Locator("#app")).ToMatchAriaSnapshotAsync("- textbox \"Cuesheet artist\"\n- group \"Cuesheet artist\"\n- text: Cuesheet artist\n- textbox \"Cuesheet title\"\n- group \"Cuesheet title\"\n- text: Cuesheet title\n- group:\n - button \"Choose File\"\n - textbox \"Audiofile\": /Kalimba test \\d+\\.mp3/\n - group \"Audiofile\"\n - text: Audiofile\n - button \"Search\"\n - button\n - button\n- group:\n - button \"Choose File\"\n - textbox \"CD Textfile\": No file selected\n - group \"CD Textfile\"\n - text: CD Textfile\n - button \"Search\"\n - button [disabled]\n - button\n- textbox \"Cataloguenumber\"\n- group \"Cataloguenumber\"\n- text: Cataloguenumber");
}
+
+ [TestMethod]
+ public async Task ImportUndoRedoTestAsync()
+ {
+ await Page.GotoAsync("http://localhost:5132/");
+ await Page.GetByText("Import view").ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync("Textimport with Cuesheetdata.txt");
+ await Page.GetByRole(AriaRole.Textbox, new() { Name = "Scheme common data" }).FillAsync("Artist - Title - ");
+ await Page.Locator("div").Filter(new() { HasTextRegex = new Regex("^Scheme common data$") }).GetByRole(AriaRole.Button).Nth(1).ClickAsync();
+ await Page.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Cataloguenumber" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Toolbar)).ToMatchAriaSnapshotAsync("- button \"undo\" [disabled]");
+ await Expect(Page.GetByRole(AriaRole.Toolbar)).ToMatchAriaSnapshotAsync("- button \"redo\" [disabled]");
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Complete" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Button, new() { Name = "undo" })).ToMatchAriaSnapshotAsync("- button \"undo\"");
+ await Expect(Page.GetByRole(AriaRole.Toolbar)).ToMatchAriaSnapshotAsync("- button \"redo\" [disabled]");
+ await Page.GetByRole(AriaRole.Button, new() { Name = "undo" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Toolbar)).ToMatchAriaSnapshotAsync("- button \"undo\" [disabled]");
+ await Expect(Page.GetByRole(AriaRole.Button, new() { Name = "redo" })).ToMatchAriaSnapshotAsync("- button \"redo\"");
+ await Page.GetByRole(AriaRole.Button, new() { Name = "redo" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" })).ToHaveValueAsync("DJFreezeT");
+ await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" })).ToHaveValueAsync("Rabbit Hole Mix");
+ await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cataloguenumber" })).ToHaveValueAsync("01 23456 78912 3");
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Einmusik Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Missing Path (Original Mix)" })).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task ImportTestBug54Async()
+ {
+ await Page.GotoAsync("http://localhost:5132/");
+ await Page.GetByText("Import view").ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync("Textimport-Bug-#54.txt");
+ await Page.GetByText("Textfile (common data in").ClickAsync();
+ await Page.GetByText("Textfile (just track data)").ClickAsync();
+ await Expect(Page.GetByLabel("Import view")).ToMatchAriaSnapshotAsync("- table:\n - rowgroup:\n - row \"# Sort Column options Artist Sort Column options Title Sort Column options Begin Sort Column options End Sort Column options Length Sort Column options\":\n - columnheader:\n - checkbox\n - columnheader \"# Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Artist Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Title Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Begin Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"End Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Length Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - rowgroup:\n - row /Increment Decrement Adriatique Clear X\\. Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"1\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Adriatique Clear\":\n - textbox: Adriatique\n - button \"Clear\"\n - button\n - cell \"X. Clear\":\n - textbox: X.\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Third Harmony Clear Fears And Dreams \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"2\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Third Harmony Clear\":\n - textbox: Third Harmony\n - button \"Clear\"\n - button\n - cell \"Fears And Dreams (Original Mix) Clear\":\n - textbox: Fears And Dreams (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Dele Sosimi Afrobeat Orchestra Clear Too Much Information \\(Laolu Remix; Edit\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"3\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Dele Sosimi Afrobeat Orchestra Clear\":\n - textbox: Dele Sosimi Afrobeat Orchestra\n - button \"Clear\"\n - button\n - cell \"Too Much Information (Laolu Remix; Edit) Clear\":\n - textbox: Too Much Information (Laolu Remix; Edit)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Edem, Govan Clear Ankh \\(Onetwo MX Remix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"4\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Edem, Govan Clear\":\n - textbox: Edem, Govan\n - button \"Clear\"\n - button\n - cell \"Ankh (Onetwo MX Remix) Clear\":\n - textbox: Ankh (Onetwo MX Remix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Jody Wisternoff Clear For All Time \\(feat\\. Hendrik Burkhard\\) \\(Extended Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"5\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Jody Wisternoff Clear\":\n - textbox: Jody Wisternoff\n - button \"Clear\"\n - button\n - cell \"For All Time (feat. Hendrik Burkhard) (Extended Mix) Clear\":\n - textbox: For All Time (feat. Hendrik Burkhard) (Extended Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Einmusik Clear Bead \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"6\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Einmusik Clear\":\n - textbox: Einmusik\n - button \"Clear\"\n - button\n - cell \"Bead (Original Mix) Clear\":\n - textbox: Bead (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Sebastien Leger Clear La Danse du Scorpion Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"7\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Sebastien Leger Clear\":\n - textbox: Sebastien Leger\n - button \"Clear\"\n - button\n - cell \"La Danse du Scorpion Clear\":\n - textbox: La Danse du Scorpion\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Paul Thomas & Solid Stone Clear La Bombo \\(Solid Stone Remix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"8\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Paul Thomas & Solid Stone Clear\":\n - textbox: Paul Thomas & Solid Stone\n - button \"Clear\"\n - button\n - cell \"La Bombo (Solid Stone Remix) Clear\":\n - textbox: La Bombo (Solid Stone Remix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement GusGus Clear Crossfade \\(Maceo Plex Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"9\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"GusGus Clear\":\n - textbox: GusGus\n - button \"Clear\"\n - button\n - cell \"Crossfade (Maceo Plex Mix) Clear\":\n - textbox: Crossfade (Maceo Plex Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Klangkarussell Clear Time \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Klangkarussell Clear\":\n - textbox: Klangkarussell\n - button \"Clear\"\n - button\n - cell \"Time (Original Mix) Clear\":\n - textbox: Time (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Anysense & Un:said Clear Missing Path \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Anysense & Un:said Clear\":\n - textbox: Anysense & Un:said\n - button \"Clear\"\n - button\n - cell \"Missing Path (Original Mix) Clear\":\n - textbox: Missing Path (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Space Food Clear Bombay Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Space Food Clear\":\n - textbox: Space Food\n - button \"Clear\"\n - button\n - cell \"Bombay Clear\":\n - textbox: Bombay\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement SHDW & Obscure Shape Clear Wächter der Nacht \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"SHDW & Obscure Shape Clear\":\n - textbox: SHDW & Obscure Shape\n - button \"Clear\"\n - button\n - cell \"Wächter der Nacht (Original Mix) Clear\":\n - textbox: Wächter der Nacht (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement HOSH Clear Karma Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"HOSH Clear\":\n - textbox: HOSH\n - button \"Clear\"\n - button\n - cell \"Karma Clear\":\n - textbox: Karma\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Alexey Union Clear Olympia \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Alexey Union Clear\":\n - textbox: Alexey Union\n - button \"Clear\"\n - button\n - cell \"Olympia (Original Mix) Clear\":\n - textbox: Olympia (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Paul Taylor Clear Afterglow Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Paul Taylor Clear\":\n - textbox: Paul Taylor\n - button \"Clear\"\n - button\n - cell \"Afterglow Clear\":\n - textbox: Afterglow\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Philter Clear Stranger Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Philter Clear\":\n - textbox: Philter\n - button \"Clear\"\n - button\n - cell \"Stranger Clear\":\n - textbox: Stranger\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Skizologic Clear Hypersphere \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Skizologic Clear\":\n - textbox: Skizologic\n - button \"Clear\"\n - button\n - cell \"Hypersphere (Original Mix) Clear\":\n - textbox: Hypersphere (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Thomas Schumacher, Caitlin Clear All of You \\(Remix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Thomas Schumacher, Caitlin Clear\":\n - textbox: Thomas Schumacher, Caitlin\n - button \"Clear\"\n - button\n - cell \"All of You (Remix) Clear\":\n - textbox: All of You (Remix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement A\\. Skomoroh Clear White Horse Conquest \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"A. Skomoroh Clear\":\n - textbox: A. Skomoroh\n - button \"Clear\"\n - button\n - cell \"White Horse Conquest (Original Mix) Clear\":\n - textbox: White Horse Conquest (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Patrik Berg Clear Bright \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Patrik Berg Clear\":\n - textbox: Patrik Berg\n - button \"Clear\"\n - button\n - cell \"Bright (Original Mix) Clear\":\n - textbox: Bright (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Hidden Empire Clear Bengal Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Hidden Empire Clear\":\n - textbox: Hidden Empire\n - button \"Clear\"\n - button\n - cell \"Bengal Clear\":\n - textbox: Bengal\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Mario Ochoa Clear Levitate Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Mario Ochoa Clear\":\n - textbox: Mario Ochoa\n - button \"Clear\"\n - button\n - cell \"Levitate Clear\":\n - textbox: Levitate\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Raul Facio Clear Eyes Wide Shut \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Raul Facio Clear\":\n - textbox: Raul Facio\n - button \"Clear\"\n - button\n - cell \"Eyes Wide Shut (Original Mix) Clear\":\n - textbox: Eyes Wide Shut (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Soolver Clear Regular \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Soolver Clear\":\n - textbox: Soolver\n - button \"Clear\"\n - button\n - cell \"Regular (Original Mix) Clear\":\n - textbox: Regular (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Weska Clear EQ64 \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Weska Clear\":\n - textbox: Weska\n - button \"Clear\"\n - button\n - cell \"EQ64 (Original Mix) Clear\":\n - textbox: EQ64 (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Tempo Giusto Clear The Fall \\(Extended Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Tempo Giusto Clear\":\n - textbox: Tempo Giusto\n - button \"Clear\"\n - button\n - cell \"The Fall (Extended Mix) Clear\":\n - textbox: The Fall (Extended Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Vlind & Asteroid & Gary Leroy Clear Trinity \\(Extended Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Vlind & Asteroid & Gary Leroy Clear\":\n - textbox: Vlind & Asteroid & Gary Leroy\n - button \"Clear\"\n - button\n - cell \"Trinity (Extended Mix) Clear\":\n - textbox: Trinity (Extended Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Astral Legacy Clear Vaveyla \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Astral Legacy Clear\":\n - textbox: Astral Legacy\n - button \"Clear\"\n - button\n - cell \"Vaveyla (Original Mix) Clear\":\n - textbox: Vaveyla (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Gerrox Clear Chakra \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Gerrox Clear\":\n - textbox: Gerrox\n - button \"Clear\"\n - button\n - cell \"Chakra (Original Mix) Clear\":\n - textbox: Chakra (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Charlotte De Witte Clear Pattern Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Charlotte De Witte Clear\":\n - textbox: Charlotte De Witte\n - button \"Clear\"\n - button\n - cell \"Pattern Clear\":\n - textbox: Pattern\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Space Food Clear Amabey Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Space Food Clear\":\n - textbox: Space Food\n - button \"Clear\"\n - button\n - cell \"Amabey Clear\":\n - textbox: Amabey\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement ARTBAT Clear Papilion \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"ARTBAT Clear\":\n - textbox: ARTBAT\n - button \"Clear\"\n - button\n - cell \"Papilion (Original Mix) Clear\":\n - textbox: Papilion (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement PETER PAHN Clear Enjoy Infinity \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"PETER PAHN Clear\":\n - textbox: PETER PAHN\n - button \"Clear\"\n - button\n - cell \"Enjoy Infinity (Original Mix) Clear\":\n - textbox: Enjoy Infinity (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Solitek Clear Instinct \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Solitek Clear\":\n - textbox: Solitek\n - button \"Clear\"\n - button\n - cell \"Instinct (Original Mix) Clear\":\n - textbox: Instinct (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Veerus Clear Heavy Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Veerus Clear\":\n - textbox: Veerus\n - button \"Clear\"\n - button\n - cell \"Heavy Clear\":\n - textbox: Heavy\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Secret Cinema & Reinier Zonneveld Clear Pain Thing \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Secret Cinema & Reinier Zonneveld Clear\":\n - textbox: Secret Cinema & Reinier Zonneveld\n - button \"Clear\"\n - button\n - cell \"Pain Thing (Original Mix) Clear\":\n - textbox: Pain Thing (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Amelie Lens Clear Hypnotized Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Amelie Lens Clear\":\n - textbox: Amelie Lens\n - button \"Clear\"\n - button\n - cell \"Hypnotized Clear\":\n - textbox: Hypnotized\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Nikolay Kirov Clear Chasing the Sun \\(Original Mix\\) Clear \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Nikolay Kirov Clear\":\n - textbox: Nikolay Kirov\n - button \"Clear\"\n - button\n - cell \"Chasing the Sun (Original Mix) Clear\":\n - textbox: Chasing the Sun (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell:\n - textbox\n - cell:\n - textbox\n - rowgroup:\n - row");
+ }
+
+ [TestMethod]
+ public async Task ImportTestSampleInputfile2Async()
+ {
+ await Page.GotoAsync("http://localhost:5132/");
+ await Page.GetByText("Import view").ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync("Sample_Inputfile2.txt");
+ await Page.Locator("div").Filter(new() { HasTextRegex = new Regex("^Scheme common data$") }).GetByLabel("Clear").ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" })).ToBeEmptyAsync();
+ await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" })).ToBeEmptyAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Sample Title 1 Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":09:23" }).Nth(1)).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "01:15:" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Sample Artist 8 Clear" })).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task ImportTestTraktorAsync()
+ {
+ await Page.GotoAsync("http://localhost:5132/");
+ await Page.GetByText("Import view").ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync(new[] { "Traktor Export.html" });
+ await Page.GetByText("Textfile (common data in").ClickAsync();
+ await Page.GetByText("Traktor history").ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Arba Han Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":48:53" }).Nth(1)).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Acid Rain Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":48:40" }).Nth(1)).ToBeVisibleAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Complete" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Space Yoda (Snyl Remix) Clear" })).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task EditTrackModalUndoRedoTestAsync()
+ {
+ await Page.GotoAsync("http://localhost:5132/");
+ await Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "Edit selected tracks Copy" }).GetByRole(AriaRole.Button).First.ClickAsync();
+ await Page.GetByRole(AriaRole.Row, new() { Name = "Increment Decrement 00:00:" }).GetByLabel("", new() { Exact = true }).CheckAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).FillAsync("Test Track Artist 1");
+ await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).PressAsync("Tab");
+ await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).FillAsync("Test Track Title 1");
+ await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).PressAsync("Tab");
+ await Page.GetByRole(AriaRole.Textbox, new() { Name = "End" }).FillAsync("00:02:23");
+ await Page.GetByRole(AriaRole.Button, new() { Name = "channel audio (4CH)" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Serial copy management system" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "Save changes" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track Artist 1 Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track Title 1 Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":02:23" }).First).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":02:23" }).Nth(1)).ToBeVisibleAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "undo" }).ClickAsync();
+ await Expect(Page.Locator("td:nth-child(3)")).ToBeVisibleAsync();
+ await Expect(Page.Locator("td:nth-child(4)")).ToBeVisibleAsync();
+ await Expect(Page.Locator("td:nth-child(6)")).ToBeVisibleAsync();
+ await Expect(Page.Locator("td:nth-child(7)")).ToBeVisibleAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "redo" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track Artist 1 Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track Title 1 Clear" })).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":02:23" }).First).ToBeVisibleAsync();
+ await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":02:23" }).Nth(1)).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task UndoRedoTrackTableTestAsync()
+ {
+ await Page.GotoAsync("http://localhost:5132/");
+ await Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "Edit selected tracks Copy" }).GetByRole(AriaRole.Button).First.ClickAsync();
+ await Page.Locator("td:nth-child(3)").ClickAsync();
+ await Page.GetByRole(AriaRole.Row, new() { Name = "Increment Decrement 00:00:" }).GetByRole(AriaRole.Textbox).First.FillAsync("Test Artist 1");
+ await Page.Locator(".mud-overlay").ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Button, new() { Name = "undo" })).ToBeEnabledAsync();
+ await Page.Locator("td:nth-child(4)").ClickAsync();
+ await Page.GetByRole(AriaRole.Row, new() { Name = "Increment Decrement Test" }).GetByRole(AriaRole.Textbox).Nth(1).FillAsync("Test Title 1");
+ await Page.Locator(".mud-overlay").ClickAsync();
+ await Page.GetByRole(AriaRole.Heading, new() { Name = "Playback" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "undo" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "undo" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync("- cell:\n - textbox\n - button");
+ await Expect(Page.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync("- cell:\n - textbox\n - button");
+ await Page.GetByRole(AriaRole.Button, new() { Name = "redo" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "redo" }).ClickAsync();
+ await Expect(Page.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync("- cell \"Test Artist 1 Clear\":\n - textbox: Test Artist 1\n - button \"Clear\"\n - button");
+ await Expect(Page.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync("- cell \"Test Title 1 Clear\":\n - textbox: Test Title 1\n - button \"Clear\"\n - button");
+ await Page.GetByRole(AriaRole.Cell, new() { Name = "Test Title 1 Clear" }).GetByLabel("Clear").ClickAsync();
+ await Page.Locator("td:nth-child(3)").ClickAsync();
+ await Page.Locator(".mud-overlay").ClickAsync();
+ await Page.GetByRole(AriaRole.Cell, new() { Name = "Test Artist 1 Clear" }).GetByRole(AriaRole.Textbox).First.FillAsync("Mozart");
+ await Page.Locator(".mud-overlay").ClickAsync();
+ await Page.Locator("td:nth-child(4)").ClickAsync();
+ await Page.GetByRole(AriaRole.Row, new() { Name = "Increment Decrement Mozart" }).GetByRole(AriaRole.Textbox).Nth(1).FillAsync("Eine kleine Nachtmusik");
+ await Page.GetByText("Eine kleine Nachtmusik", new() { Exact = true }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "undo" }).ClickAsync();
+ await Page.GetByRole(AriaRole.Button, new() { Name = "undo" }).ClickAsync();
+ await Expect(Page.Locator("#app")).ToMatchAriaSnapshotAsync("- group:\n - button\n - button \"Edit selected tracks\" [disabled]\n - button \"Copy selected tracks\" [disabled]\n - button \"Delete selected tracks\" [disabled]\n - button \"Delete all tracks\"\n- group:\n - button [disabled]\n - button [disabled]\n- button\n- table:\n - rowgroup:\n - row \"# Sort Column options Artist Sort Column options Title Sort Column options Begin Sort Column options End Sort Column options Length Sort Column options Status\":\n - columnheader:\n - checkbox\n - columnheader \"# Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Artist Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Title Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Begin Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"End Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Length Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Status\"\n - rowgroup:\n - row /Increment Decrement Test Artist 1 Clear \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"1\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Test Artist 1 Clear\":\n - textbox: Test Artist 1\n - button \"Clear\"\n - button\n - cell:\n - textbox\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell:\n - textbox\n - cell:\n - textbox\n - cell\n - rowgroup:\n - row");
+ }
}
}
diff --git a/AudioCuesheetEditor.Tests/Sample_Inputfile2.txt b/AudioCuesheetEditor.End2EndTests/Sample_Inputfile2.txt
similarity index 100%
rename from AudioCuesheetEditor.Tests/Sample_Inputfile2.txt
rename to AudioCuesheetEditor.End2EndTests/Sample_Inputfile2.txt
diff --git a/AudioCuesheetEditor.End2EndTests/Textimport with Cuesheetdata.txt b/AudioCuesheetEditor.End2EndTests/Textimport with Cuesheetdata.txt
new file mode 100644
index 00000000..f476fd54
--- /dev/null
+++ b/AudioCuesheetEditor.End2EndTests/Textimport with Cuesheetdata.txt
@@ -0,0 +1,40 @@
+DJFreezeT - Rabbit Hole Mix - 0123456789123
+Adriatique - X. 00:05:24.250
+Third Harmony - Fears And Dreams (Original Mix) 00:10:39
+Dele Sosimi Afrobeat Orchestra - Too Much Information (Laolu Remix; Edit) 00:17:06
+Edem, Govan - Ankh (Onetwo MX Remix) 00:23:21
+Jody Wisternoff - For All Time (feat. Hendrik Burkhard) (Extended Mix) 00:29:02
+Einmusik - Bead (Original Mix) 00:34:27
+Sebastien Leger - La Danse du Scorpion 00:40:59
+Paul Thomas & Solid Stone - La Bombo (Solid Stone Remix) 00:46:19
+GusGus - Crossfade (Maceo Plex Mix) 00:52:20
+Klangkarussell - Time (Original Mix) 00:56:19
+Anysense & Un:said - Missing Path (Original Mix) 01:01:41
+Space Food - Bombay 01:06:33
+SHDW & Obscure Shape - Wächter der Nacht (Original Mix) 01:11:04
+HOSH - Karma 01:15:28
+Alexey Union - Olympia (Original Mix) 01:21:08
+Paul Taylor - Afterglow 01:25:38
+Philter - Stranger 01:31:52
+Skizologic - Hypersphere (Original Mix) 01:36:40
+Thomas Schumacher, Caitlin - All of You (Remix) 01:42:16
+A. Skomoroh - White Horse Conquest (Original Mix) 01:47:04
+Patrik Berg - Bright (Original Mix) 01:52:37
+Hidden Empire - Bengal 01:58:05
+Mario Ochoa - Levitate 02:03:00
+Raul Facio - Eyes Wide Shut (Original Mix) 02:08:21
+Soolver - Regular (Original Mix) 02:14:31
+Weska - EQ64 (Original Mix) 02:18:35
+Tempo Giusto - The Fall (Extended Mix) 02:24:12
+Vlind & Asteroid & Gary Leroy - Trinity (Extended Mix) 02:29:38
+Astral Legacy - Vaveyla (Original Mix) 02:32:52
+Gerrox - Chakra (Original Mix) 02:37:00
+Charlotte De Witte - Pattern 02:41:55
+Space Food - Amabey 02:46:55
+ARTBAT - Papilion (Original Mix) 02:51:13
+PETER PAHN - Enjoy Infinity (Original Mix) 02:56:08
+Solitek - Instinct (Original Mix) 03:00:57
+Veerus - Heavy 03:05:19
+Secret Cinema & Reinier Zonneveld - Pain Thing (Original Mix) 03:09:38
+Amelie Lens - Hypnotized 03:13:13
+Nikolay Kirov - Chasing the Sun (Original Mix)
diff --git a/AudioCuesheetEditor.End2EndTests/Textimport-Bug-#54.txt b/AudioCuesheetEditor.End2EndTests/Textimport-Bug-#54.txt
new file mode 100644
index 00000000..9cda0a9e
--- /dev/null
+++ b/AudioCuesheetEditor.End2EndTests/Textimport-Bug-#54.txt
@@ -0,0 +1,40 @@
+
+Adriatique - X. 00:05:24
+Third Harmony - Fears And Dreams (Original Mix) 00:10:39
+Dele Sosimi Afrobeat Orchestra - Too Much Information (Laolu Remix; Edit) 00:17:06
+Edem, Govan - Ankh (Onetwo MX Remix) 00:23:21
+Jody Wisternoff - For All Time (feat. Hendrik Burkhard) (Extended Mix) 00:29:02
+Einmusik - Bead (Original Mix) 00:34:27
+Sebastien Leger - La Danse du Scorpion 00:40:59
+Paul Thomas & Solid Stone - La Bombo (Solid Stone Remix) 00:46:19
+GusGus - Crossfade (Maceo Plex Mix) 00:52:20
+Klangkarussell - Time (Original Mix) 00:56:19
+Anysense & Un:said - Missing Path (Original Mix) 01:01:41
+Space Food - Bombay 01:06:33
+SHDW & Obscure Shape - Wächter der Nacht (Original Mix) 01:11:04
+HOSH - Karma 01:15:28
+Alexey Union - Olympia (Original Mix) 01:21:08
+Paul Taylor - Afterglow 01:25:38
+Philter - Stranger 01:31:52
+Skizologic - Hypersphere (Original Mix) 01:36:40
+Thomas Schumacher, Caitlin - All of You (Remix) 01:42:16
+A. Skomoroh - White Horse Conquest (Original Mix) 01:47:04
+Patrik Berg - Bright (Original Mix) 01:52:37
+Hidden Empire - Bengal 01:58:05
+Mario Ochoa - Levitate 02:03:00
+Raul Facio - Eyes Wide Shut (Original Mix) 02:08:21
+Soolver - Regular (Original Mix) 02:14:31
+Weska - EQ64 (Original Mix) 02:18:35
+Tempo Giusto - The Fall (Extended Mix) 02:24:12
+Vlind & Asteroid & Gary Leroy - Trinity (Extended Mix) 02:29:38
+Astral Legacy - Vaveyla (Original Mix) 02:32:52
+Gerrox - Chakra (Original Mix) 02:37:00
+Charlotte De Witte - Pattern 02:41:55
+Space Food - Amabey 02:46:55
+ARTBAT - Papilion (Original Mix) 02:51:13
+PETER PAHN - Enjoy Infinity (Original Mix) 02:56:08
+Solitek - Instinct (Original Mix) 03:00:57
+Veerus - Heavy 03:05:19
+Secret Cinema & Reinier Zonneveld - Pain Thing (Original Mix) 03:09:38
+Amelie Lens - Hypnotized 03:13:13
+Nikolay Kirov - Chasing the Sun (Original Mix)
diff --git a/AudioCuesheetEditor.End2EndTests/Traktor Export.html b/AudioCuesheetEditor.End2EndTests/Traktor Export.html
new file mode 100644
index 00000000..bdc497c7
--- /dev/null
+++ b/AudioCuesheetEditor.End2EndTests/Traktor Export.html
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+ Track List HISTORY
+
+
+
+
+ Track List: HISTORY
+
+
+ | Num. |
+ Artist |
+ Title |
+ Start Time |
+
+
+ | 1 |
+ Nachap |
+ Glass |
+ 2025/1/29 18:52:10 |
+
+
+ | 2 |
+ |
+ Progressive + Melodic DECK |
+ 2025/1/29 19:04:06 |
+
+
+ | 3 |
+ Nomer 21 |
+ Depersonalization |
+ 2025/1/29 19:05:41 |
+
+
+ | 4 |
+ SevenEver, Nopopstar, 2JOHN'S & Eugene Jay |
+ Showing Off |
+ 2025/1/29 19:11:24 |
+
+
+ | 5 |
+ Carlo Whale |
+ Unconscious |
+ 2025/1/29 19:16:12 |
+
+
+ | 6 |
+ Arba Han |
+ Timelaps |
+ 2025/1/29 19:21:47 |
+
+
+ | 7 |
+ Savill |
+ Energy Surrounds |
+ 2025/1/29 19:25:23 |
+
+
+ | 8 |
+ Teklix |
+ The Tribal Code |
+ 2025/1/29 19:32:40 |
+
+
+ | 9 |
+ Neuralis |
+ I'm Looking for Answers |
+ 2025/1/29 19:41:03 |
+
+
+ | 10 |
+ Nopopstar & Arsia |
+ Dirty Moves |
+ 2025/1/29 19:46:44 |
+
+
+ | 11 |
+ SevenEver, Nopopstar, 2JOHN'S & Eugene Jay |
+ Lost (Maze 28 Remix) |
+ 2025/1/29 19:52:34 |
+
+
+ | 12 |
+ SevenEver, Nopopstar, 2JOHN'S & Eugene Jay |
+ Lost (Redspace Remix) |
+ 2025/1/29 19:57:27 |
+
+
+ | 13 |
+ Gadoz |
+ 5d |
+ 2025/1/29 20:00:32 |
+
+
+ | 14 |
+ DJ Danzik |
+ Out of Space |
+ 2025/1/29 20:08:44 |
+
+
+ | 15 |
+ Enis Çoban |
+ Internet |
+ 2025/1/29 20:11:32 |
+
+
+ | 16 |
+ Cold Mind & Alex Yikker |
+ Rage |
+ 2025/1/29 20:17:24 |
+
+
+ | 17 |
+ Maze 28 |
+ Sol (JAHAYA Remix) |
+ 2025/1/29 20:23:43 |
+
+
+ | 18 |
+ Alex Grafton |
+ Hi Baby |
+ 2025/1/29 20:25:01 |
+
+
+ | 19 |
+ Che&Mos & Halo Far |
+ Daddy |
+ 2025/1/29 20:34:23 |
+
+
+ | 20 |
+ K KARDEN |
+ Acid Rain |
+ 2025/1/29 20:37:32 |
+
+
+ | 21 |
+ Dobrov & Gar1sson |
+ Analogic (Redspace Remix) |
+ 2025/1/29 20:40:50 |
+
+
+ | 22 |
+ Gazfluz |
+ Vargan |
+ 2025/1/29 20:48:50 |
+
+
+ | 23 |
+ SHKAPOV |
+ Control |
+ 2025/1/29 20:52:49 |
+
+
+ | 24 |
+ QazaQ |
+ On the Line |
+ 2025/1/29 20:58:57 |
+
+
+ | 25 |
+ Alex Schaufel |
+ Elizabeth (Larsun Hesh Remix) |
+ 2025/1/29 21:01:19 |
+
+
+ | 26 |
+ Oiro |
+ Just Business |
+ 2025/1/29 21:06:28 |
+
+
+ | 27 |
+ Molex |
+ Mind Split (Redspace Remix) |
+ 2025/1/29 21:11:32 |
+
+
+ | 28 |
+ SOLI |
+ Give Me Your Mind |
+ 2025/1/29 21:19:58 |
+
+
+ | 29 |
+ MANDU |
+ Jacky |
+ 2025/1/29 21:25:58 |
+
+
+ | 30 |
+ SOLI |
+ Spacetoon |
+ 2025/1/29 21:31:15 |
+
+
+ | 31 |
+ Sasha Fashion |
+ Moqton |
+ 2025/1/29 21:33:41 |
+
+
+ | 32 |
+ NAASA |
+ Poison |
+ 2025/1/29 21:42:28 |
+
+
+ | 33 |
+ Nopopstar, 2JOHN'S & Eugene Jay |
+ Nightlong |
+ 2025/1/29 21:48:55 |
+
+
+ | 34 |
+ Skillz jay |
+ Choir |
+ 2025/1/29 21:51:24 |
+
+
+ | 35 |
+ Kovax |
+ Controller |
+ 2025/1/29 21:57:59 |
+
+
+ | 36 |
+ Mumboi |
+ Just a Beat |
+ 2025/1/29 22:00:41 |
+
+
+ | 37 |
+ Eclept |
+ Sprut |
+ 2025/1/29 22:07:28 |
+
+
+ | 38 |
+ Rudensky |
+ Dark Escort |
+ 2025/1/29 22:12:45 |
+
+
+ | 39 |
+ Alexey Union, Kinky Sound & KOCHETOV |
+ Connected |
+ 2025/1/29 22:17:12 |
+
+
+ | 40 |
+ ANMA (MD) |
+ Space Yoda (Snyl Remix) |
+ 2025/1/29 22:24:40 |
+
+
+ | 41 |
+ Inache |
+ Andale (MONTA (TN) Remix) |
+ 2025/1/29 22:30:03 |
+
+
+
+
+
diff --git a/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj b/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj
index 4ebd0bab..59451bb3 100644
--- a/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj
+++ b/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj
@@ -7,10 +7,10 @@
-
+
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -36,13 +36,4 @@
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
-
diff --git a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs
index 7b6f0454..1849ce87 100644
--- a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs
+++ b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs
@@ -71,90 +71,6 @@ public void EmptyCuesheetTracksValidationTest()
Assert.AreEqual(ValidationStatus.Success, validationErrorTracks.Status);
}
- [TestMethod()]
- public void ImportTest()
- {
- // Arrange
- var fileContent = new List
- {
- "CuesheetArtist - CuesheetTitle c:\\tmp\\Testfile.mp3",
- "Sample Artist 1 - Sample Title 1 00:05:00",
- "Sample Artist 2 - Sample Title 2 00:09:23",
- "Sample Artist 3 - Sample Title 3 00:15:54",
- "Sample Artist 4 - Sample Title 4 00:20:13",
- "Sample Artist 5 - Sample Title 5 00:24:54",
- "Sample Artist 6 - Sample Title 6 00:31:54",
- "Sample Artist 7 - Sample Title 7 00:45:54",
- "Sample Artist 8 - Sample Title 8 01:15:54"
- };
-
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = TextImportScheme.DefaultSchemeCuesheet,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions();
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- var testHelper = new TestHelper();
- // Act
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
-
- // Assert
- Assert.IsNull(sessionStateContainer.ImportCuesheet?.CDTextfile);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(0).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(1).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(2).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(3).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(4).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(5).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(6).Validate().Status);
- Assert.AreEqual(ValidationStatus.Success, sessionStateContainer.ImportCuesheet?.Tracks.ElementAt(7).Validate().Status);
- }
-
- [TestMethod()]
- public void ImportTestCalculateEndCorrectly()
- {
- // Arrange
- var textImportMemoryStream = new MemoryStream(Resources.Textimport_Bug_54);
- using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
- var testHelper = new TestHelper();
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var localStorageOptionsProviderMock = new Mock();
- var options = new ApplicationOptions();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = null,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- options.ImportScheme = textImportScheme;
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- var timeSpanFormat = new TimeSpanFormat();
- // Act
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
- // Assert
- Assert.IsNull(sessionStateContainer.Importfile?.AnalyseException);
- Assert.IsNotNull(sessionStateContainer.ImportCuesheet);
- Assert.AreEqual(39, sessionStateContainer.ImportCuesheet.Tracks.Count);
- Assert.AreEqual(new TimeSpan(0, 5, 24), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(0).End);
- Assert.AreEqual(new TimeSpan(3, 13, 13), sessionStateContainer.ImportCuesheet.Tracks.ElementAt(38).Begin);
- }
-
[TestMethod()]
public void RecordTest()
{
@@ -426,68 +342,6 @@ public void TrackLengthChangedWithIsLinkedToPreivousTest()
Assert.AreEqual(track1.End, track2.Begin);
Assert.AreEqual(editedTrack.End, track2.Begin);
}
- [TestMethod()]
- public void ImportSamplesTest()
- {
- // Arrange
- var fileContent = File.ReadAllLines("Sample_Inputfile.txt");
- var testHelper = new TestHelper();
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = TextImportScheme.DefaultSchemeCuesheet,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions();
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- // Act
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
- // Assert
- Assert.IsNull(sessionStateContainer.Importfile?.AnalyseException);
- Assert.IsNotNull(sessionStateContainer.ImportCuesheet);
- Assert.AreEqual("CuesheetArtist", sessionStateContainer.ImportCuesheet.Artist);
- Assert.AreEqual("CuesheetTitle", sessionStateContainer.ImportCuesheet.Title);
- Assert.AreEqual(8, sessionStateContainer.ImportCuesheet.Tracks.Count);
- Assert.AreEqual(new TimeSpan(1, 15, 54), sessionStateContainer.ImportCuesheet.Tracks.Last().End);
- }
-
- [TestMethod()]
- public void ImportSamples2Test()
- {
- // Arrange
- var fileContent = File.ReadAllLines("Sample_Inputfile2.txt");
- var testHelper = new TestHelper();
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = null,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions
- {
- ImportScheme = textImportScheme
- };
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- // Act
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
- // Assert
- Assert.IsNull(sessionStateContainer.Importfile?.AnalyseException);
- Assert.IsNotNull(sessionStateContainer.ImportCuesheet);
- Assert.IsNull(sessionStateContainer.ImportCuesheet.Artist);
- Assert.IsNull(sessionStateContainer.ImportCuesheet.Title);
- Assert.AreEqual(8, sessionStateContainer.ImportCuesheet.Tracks.Count);
- Assert.AreEqual(new TimeSpan(1, 15, 54), sessionStateContainer.ImportCuesheet.Tracks.Last().End);
- }
[TestMethod()]
public void ValidateTest()
diff --git a/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs
new file mode 100644
index 00000000..b25e9756
--- /dev/null
+++ b/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs
@@ -0,0 +1,47 @@
+//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.Entity;
+using AudioCuesheetEditor.Model.IO.Import;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Linq;
+
+namespace AudioCuesheetEditor.Tests.Model.IO.Import
+{
+ [TestClass()]
+ public class ImportprofileTests
+ {
+ [TestMethod()]
+ public void Validate_WithoutPlaceholder_ReturnsInvalid()
+ {
+ // Arrange
+ var importprofile = new Importprofile()
+ {
+ SchemeCuesheet = "Test 1",
+ SchemeTracks = "Here comes next track"
+ };
+ // Act
+ var result = importprofile.Validate();
+ // Assert
+ Assert.AreEqual(ValidationStatus.Error, result.Status);
+ Assert.AreEqual(2, result.ValidationMessages.Count);
+ Assert.AreEqual("{0} contains no placeholder!", result.ValidationMessages.First().Message);
+ Assert.AreEqual(nameof(Importprofile.SchemeCuesheet), result.ValidationMessages.First().Parameter?.First().ToString());
+ Assert.AreEqual("{0} contains no placeholder!", result.ValidationMessages.Last().Message);
+ Assert.AreEqual(nameof(Importprofile.SchemeTracks), result.ValidationMessages.Last().Parameter?.First().ToString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/AudioCuesheetEditor.Tests/Model/IO/Import/TextImportSchemeTests.cs b/AudioCuesheetEditor.Tests/Model/IO/Import/TextImportSchemeTests.cs
deleted file mode 100644
index 17be72f0..00000000
--- a/AudioCuesheetEditor.Tests/Model/IO/Import/TextImportSchemeTests.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-//This file is part of AudioCuesheetEditor.
-
-//AudioCuesheetEditor is free software: you can redistribute it and/or modify
-//it under the terms of the GNU General Public License as published by
-//the Free Software Foundation, either version 3 of the License, or
-//(at your option) any later version.
-
-//AudioCuesheetEditor is distributed in the hope that it will be useful,
-//but WITHOUT ANY WARRANTY; without even the implied warranty of
-//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-//GNU General Public License for more details.
-
-//You should have received a copy of the GNU General Public License
-//along with Foobar. If not, see
-//.
-using AudioCuesheetEditor.Model.Entity;
-using AudioCuesheetEditor.Model.IO.Import;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Linq;
-
-namespace AudioCuesheetEditor.Tests.Model.IO.Import
-{
- [TestClass()]
- public class TextImportSchemeTests
- {
- [TestMethod]
- public void Validate_SchemeCuesheet_WithValidPlaceholders_ShouldReturnSuccess()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeCuesheet = "(?'Artist'.+) - (?'Title'.+)\\t+(?'Audiofile'.+)"
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeCuesheet));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Success, result.Status);
- Assert.AreEqual(0, result.ValidationMessages.Count);
- }
-
- [TestMethod]
- public void Validate_SchemeCuesheet_WithSimplePlaceholders_ShouldReturnSuccess()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeCuesheet = "Artist - Title"
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeCuesheet));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Success, result.Status);
- Assert.AreEqual(0, result.ValidationMessages.Count);
- }
-
- [TestMethod]
- public void Validate_SchemeCuesheet_WithoutPlaceholders_ShouldReturnError()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeCuesheet = "InvalidPattern"
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeCuesheet));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Error, result.Status);
- Assert.AreEqual(1, result.ValidationMessages.Count);
- var message = result.ValidationMessages.Single();
- Assert.AreEqual("{0} contains no placeholder!", message.Message);
- Assert.AreEqual(nameof(TextImportScheme.SchemeCuesheet), message.Parameter?.FirstOrDefault());
- }
-
- [TestMethod]
- public void Validate_SchemeTracks_WithValidPlaceholders_ShouldReturnSuccess()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeTracks = "(?'Artist'.+) - (?'Title'.+)(?:...\\t)(?'End'.+)"
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeTracks));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Success, result.Status);
- Assert.AreEqual(0, result.ValidationMessages.Count);
- }
-
- [TestMethod]
- public void Validate_SchemeTracks_WithSimplePlaceholders_ShouldReturnSuccess()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeTracks = "Artist - Title\tEnd"
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeTracks));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Success, result.Status);
- Assert.AreEqual(0, result.ValidationMessages.Count);
- }
-
- [TestMethod]
- public void Validate_SchemeTracks_WithoutPlaceholders_ShouldReturnError()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeTracks = "InvalidPattern"
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeTracks));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Error, result.Status);
- Assert.AreEqual(1, result.ValidationMessages.Count);
- var message = result.ValidationMessages.Single();
- Assert.AreEqual("{0} contains no placeholder!", message.Message);
- Assert.AreEqual(nameof(TextImportScheme.SchemeTracks), message.Parameter?.FirstOrDefault());
- }
-
- [TestMethod]
- public void Validate_SchemeCuesheetEmpty_ShouldReturnSuccess()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeCuesheet = string.Empty
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeCuesheet));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Success, result.Status);
- Assert.AreEqual(0, result.ValidationMessages.Count);
- }
-
- [TestMethod]
- public void Validate_SchemeTrackstEmpty_ShouldReturnSuccess()
- {
- // Arrange
- var scheme = new TextImportScheme
- {
- SchemeTracks = string.Empty
- };
-
- // Act
- var result = scheme.Validate(nameof(TextImportScheme.SchemeTracks));
-
- // Assert
- Assert.AreEqual(ValidationStatus.Success, result.Status);
- Assert.AreEqual(0, result.ValidationMessages.Count);
- }
- }
-}
diff --git a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs
index 850c6c56..847e2528 100644
--- a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs
+++ b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs
@@ -131,7 +131,7 @@ public void GenerateFile_WithSections_GeneratesOneFile()
public void ImportFile_ValidProjectfile_ShouldImportFile()
{
// Arrange
- var fileContent = Encoding.UTF8.GetBytes("{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Cataloguenumber\":\"A123\",\"Audiofile\":{\"Name\":\"AudioFile.mp3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}],\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"}}");
+ var fileContent = "{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Cataloguenumber\":\"A123\",\"Audiofile\":{\"Name\":\"AudioFile.mp3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}],\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"}}";
// Act
var cuesheet = Projectfile.ImportFile(fileContent);
// Assert
@@ -156,7 +156,7 @@ public void ImportFile_ValidProjectfile_ShouldImportFile()
public void ImportFile_ValidProjectfileWithSections_ShouldImportFile()
{
//Arrange
- var fileContent = Encoding.UTF8.GetBytes("{\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}],\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Audiofile\":{\"Name\":\"AudioFile.mp3\"},\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"},\"Cataloguenumber\":\"A123\",\"Sections\":[{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Begin\":\"00:30:00\"},{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Begin\":\"01:00:00\"}]}");
+ var fileContent = "{\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}],\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Audiofile\":{\"Name\":\"AudioFile.mp3\"},\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"},\"Cataloguenumber\":\"A123\",\"Sections\":[{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Begin\":\"00:30:00\"},{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Begin\":\"01:00:00\"}]}";
// Act
var cuesheet = Projectfile.ImportFile(fileContent);
// Assert
diff --git a/AudioCuesheetEditor.Tests/Properties/Resources.Designer.cs b/AudioCuesheetEditor.Tests/Properties/Resources.Designer.cs
index 20d2a794..c8637f77 100644
--- a/AudioCuesheetEditor.Tests/Properties/Resources.Designer.cs
+++ b/AudioCuesheetEditor.Tests/Properties/Resources.Designer.cs
@@ -90,6 +90,16 @@ internal static byte[] Playlist_Bug_57 {
}
}
+ ///
+ /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
+ ///
+ internal static byte[] Sample_Inputfile {
+ get {
+ object obj = ResourceManager.GetObject("Sample_Inputfile", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
///
/// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
///
@@ -125,7 +135,17 @@ internal static byte[] Textimport_Bug_54 {
///
internal static byte[] Textimport_with_Cuesheetdata {
get {
- object obj = ResourceManager.GetObject("Textimport_with_Cuesheetdata", resourceCulture);
+ object obj = ResourceManager.GetObject("Textimport with Cuesheetdata", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
+ ///
+ internal static byte[] Traktor_Export {
+ get {
+ object obj = ResourceManager.GetObject("Traktor Export", resourceCulture);
return ((byte[])(obj));
}
}
diff --git a/AudioCuesheetEditor.Tests/Properties/Resources.resx b/AudioCuesheetEditor.Tests/Properties/Resources.resx
index 243026f0..0370cfee 100644
--- a/AudioCuesheetEditor.Tests/Properties/Resources.resx
+++ b/AudioCuesheetEditor.Tests/Properties/Resources.resx
@@ -136,7 +136,13 @@
..\Resources\Textimport_Bug_#233.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
+ ..\Resources\Traktor Export.html;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
..\Resources\Textimport with Cuesheetdata.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\Resources\Sample_Inputfile.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
\ No newline at end of file
diff --git a/AudioCuesheetEditor.Tests/Sample_Inputfile.txt b/AudioCuesheetEditor.Tests/Resources/Sample_Inputfile.txt
similarity index 100%
rename from AudioCuesheetEditor.Tests/Sample_Inputfile.txt
rename to AudioCuesheetEditor.Tests/Resources/Sample_Inputfile.txt
diff --git a/AudioCuesheetEditor.Tests/Resources/Textimport with Cuesheetdata.txt b/AudioCuesheetEditor.Tests/Resources/Textimport with Cuesheetdata.txt
index 754820c5..f476fd54 100644
--- a/AudioCuesheetEditor.Tests/Resources/Textimport with Cuesheetdata.txt
+++ b/AudioCuesheetEditor.Tests/Resources/Textimport with Cuesheetdata.txt
@@ -37,4 +37,4 @@ Solitek - Instinct (Original Mix) 03:00:57
Veerus - Heavy 03:05:19
Secret Cinema & Reinier Zonneveld - Pain Thing (Original Mix) 03:09:38
Amelie Lens - Hypnotized 03:13:13
-Nikolay Kirov - Chasing the Sun (Original Mix)
+Nikolay Kirov - Chasing the Sun (Original Mix)
diff --git a/AudioCuesheetEditor.Tests/Resources/Traktor Export.html b/AudioCuesheetEditor.Tests/Resources/Traktor Export.html
new file mode 100644
index 00000000..bdc497c7
--- /dev/null
+++ b/AudioCuesheetEditor.Tests/Resources/Traktor Export.html
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+ Track List HISTORY
+
+
+
+
+ Track List: HISTORY
+
+
+ | Num. |
+ Artist |
+ Title |
+ Start Time |
+
+
+ | 1 |
+ Nachap |
+ Glass |
+ 2025/1/29 18:52:10 |
+
+
+ | 2 |
+ |
+ Progressive + Melodic DECK |
+ 2025/1/29 19:04:06 |
+
+
+ | 3 |
+ Nomer 21 |
+ Depersonalization |
+ 2025/1/29 19:05:41 |
+
+
+ | 4 |
+ SevenEver, Nopopstar, 2JOHN'S & Eugene Jay |
+ Showing Off |
+ 2025/1/29 19:11:24 |
+
+
+ | 5 |
+ Carlo Whale |
+ Unconscious |
+ 2025/1/29 19:16:12 |
+
+
+ | 6 |
+ Arba Han |
+ Timelaps |
+ 2025/1/29 19:21:47 |
+
+
+ | 7 |
+ Savill |
+ Energy Surrounds |
+ 2025/1/29 19:25:23 |
+
+
+ | 8 |
+ Teklix |
+ The Tribal Code |
+ 2025/1/29 19:32:40 |
+
+
+ | 9 |
+ Neuralis |
+ I'm Looking for Answers |
+ 2025/1/29 19:41:03 |
+
+
+ | 10 |
+ Nopopstar & Arsia |
+ Dirty Moves |
+ 2025/1/29 19:46:44 |
+
+
+ | 11 |
+ SevenEver, Nopopstar, 2JOHN'S & Eugene Jay |
+ Lost (Maze 28 Remix) |
+ 2025/1/29 19:52:34 |
+
+
+ | 12 |
+ SevenEver, Nopopstar, 2JOHN'S & Eugene Jay |
+ Lost (Redspace Remix) |
+ 2025/1/29 19:57:27 |
+
+
+ | 13 |
+ Gadoz |
+ 5d |
+ 2025/1/29 20:00:32 |
+
+
+ | 14 |
+ DJ Danzik |
+ Out of Space |
+ 2025/1/29 20:08:44 |
+
+
+ | 15 |
+ Enis Çoban |
+ Internet |
+ 2025/1/29 20:11:32 |
+
+
+ | 16 |
+ Cold Mind & Alex Yikker |
+ Rage |
+ 2025/1/29 20:17:24 |
+
+
+ | 17 |
+ Maze 28 |
+ Sol (JAHAYA Remix) |
+ 2025/1/29 20:23:43 |
+
+
+ | 18 |
+ Alex Grafton |
+ Hi Baby |
+ 2025/1/29 20:25:01 |
+
+
+ | 19 |
+ Che&Mos & Halo Far |
+ Daddy |
+ 2025/1/29 20:34:23 |
+
+
+ | 20 |
+ K KARDEN |
+ Acid Rain |
+ 2025/1/29 20:37:32 |
+
+
+ | 21 |
+ Dobrov & Gar1sson |
+ Analogic (Redspace Remix) |
+ 2025/1/29 20:40:50 |
+
+
+ | 22 |
+ Gazfluz |
+ Vargan |
+ 2025/1/29 20:48:50 |
+
+
+ | 23 |
+ SHKAPOV |
+ Control |
+ 2025/1/29 20:52:49 |
+
+
+ | 24 |
+ QazaQ |
+ On the Line |
+ 2025/1/29 20:58:57 |
+
+
+ | 25 |
+ Alex Schaufel |
+ Elizabeth (Larsun Hesh Remix) |
+ 2025/1/29 21:01:19 |
+
+
+ | 26 |
+ Oiro |
+ Just Business |
+ 2025/1/29 21:06:28 |
+
+
+ | 27 |
+ Molex |
+ Mind Split (Redspace Remix) |
+ 2025/1/29 21:11:32 |
+
+
+ | 28 |
+ SOLI |
+ Give Me Your Mind |
+ 2025/1/29 21:19:58 |
+
+
+ | 29 |
+ MANDU |
+ Jacky |
+ 2025/1/29 21:25:58 |
+
+
+ | 30 |
+ SOLI |
+ Spacetoon |
+ 2025/1/29 21:31:15 |
+
+
+ | 31 |
+ Sasha Fashion |
+ Moqton |
+ 2025/1/29 21:33:41 |
+
+
+ | 32 |
+ NAASA |
+ Poison |
+ 2025/1/29 21:42:28 |
+
+
+ | 33 |
+ Nopopstar, 2JOHN'S & Eugene Jay |
+ Nightlong |
+ 2025/1/29 21:48:55 |
+
+
+ | 34 |
+ Skillz jay |
+ Choir |
+ 2025/1/29 21:51:24 |
+
+
+ | 35 |
+ Kovax |
+ Controller |
+ 2025/1/29 21:57:59 |
+
+
+ | 36 |
+ Mumboi |
+ Just a Beat |
+ 2025/1/29 22:00:41 |
+
+
+ | 37 |
+ Eclept |
+ Sprut |
+ 2025/1/29 22:07:28 |
+
+
+ | 38 |
+ Rudensky |
+ Dark Escort |
+ 2025/1/29 22:12:45 |
+
+
+ | 39 |
+ Alexey Union, Kinky Sound & KOCHETOV |
+ Connected |
+ 2025/1/29 22:17:12 |
+
+
+ | 40 |
+ ANMA (MD) |
+ Space Yoda (Snyl Remix) |
+ 2025/1/29 22:24:40 |
+
+
+ | 41 |
+ Inache |
+ Andale (MONTA (TN) Remix) |
+ 2025/1/29 22:30:03 |
+
+
+
+
+
diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs
index 2b373da0..03f2ae32 100644
--- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs
+++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs
@@ -18,7 +18,6 @@
using AudioCuesheetEditor.Tests.Properties;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -31,46 +30,43 @@ public class CuesheetImportServiceTests
public void Analyse_WithSampleCuesheet_CreatesValidCuesheet()
{
// Arrange
- var fileContent = new List
- {
- "PERFORMER \"Sample CD Artist\"",
- "TITLE \"Sample CD Title\"",
- "FILE \"AC DC - TNT.mp3\" MP3",
- "CDTEXTFILE \"Testfile.cdt\"",
- "CATALOG 0123456789012",
- "TRACK 01 AUDIO",
- " PERFORMER \"Sample Artist 1\"",
- " TITLE \"Sample Title 1\"",
- " INDEX 01 00:00:00",
- "TRACK 02 AUDIO",
- " PERFORMER \"Sample Artist 2\"",
- " TITLE \"Sample Title 2\"",
- " INDEX 01 05:00:00",
- "TRACK 03 AUDIO",
- " PERFORMER \"Sample Artist 3\"",
- " TITLE \"Sample Title 3\"",
- " INDEX 01 09:23:00",
- "TRACK 04 AUDIO",
- " PERFORMER \"Sample Artist 4\"",
- " TITLE \"Sample Title 4\"",
- " INDEX 01 15:54:00",
- "TRACK 05 AUDIO",
- " PERFORMER \"Sample Artist 5\"",
- " TITLE \"Sample Title 5\"",
- " INDEX 01 20:13:00",
- "TRACK 06 AUDIO",
- " PERFORMER \"Sample Artist 6\"",
- " TITLE \"Sample Title 6\"",
- " INDEX 01 24:54:00",
- "TRACK 07 AUDIO",
- " PERFORMER \"Sample Artist 7\"",
- " TITLE \"Sample Title 7\"",
- " INDEX 01 31:54:00",
- "TRACK 08 AUDIO",
- " PERFORMER \"Sample Artist 8\"",
- " TITLE \"Sample Title 8\"",
- " INDEX 01 45:51:00"
- };
+ var fileContent = @"PERFORMER ""Sample CD Artist""
+TITLE ""Sample CD Title""
+FILE ""AC DC - TNT.mp3"" MP3
+CDTEXTFILE ""Testfile.cdt""
+CATALOG 0123456789012
+TRACK 01 AUDIO
+ PERFORMER ""Sample Artist 1""
+ TITLE ""Sample Title 1""
+ INDEX 01 00:00:00
+TRACK 02 AUDIO
+ PERFORMER ""Sample Artist 2""
+ TITLE ""Sample Title 2""
+ INDEX 01 05:00:00
+TRACK 03 AUDIO
+ PERFORMER ""Sample Artist 3""
+ TITLE ""Sample Title 3""
+ INDEX 01 09:23:00
+TRACK 04 AUDIO
+ PERFORMER ""Sample Artist 4""
+ TITLE ""Sample Title 4""
+ INDEX 01 15:54:00
+TRACK 05 AUDIO
+ PERFORMER ""Sample Artist 5""
+ TITLE ""Sample Title 5""
+ INDEX 01 20:13:00
+TRACK 06 AUDIO
+ PERFORMER ""Sample Artist 6""
+ TITLE ""Sample Title 6""
+ INDEX 01 24:54:00
+TRACK 07 AUDIO
+ PERFORMER ""Sample Artist 7""
+ TITLE ""Sample Title 7""
+ INDEX 01 31:54:00
+TRACK 08 AUDIO
+ PERFORMER ""Sample Artist 8""
+ TITLE ""Sample Title 8""
+ INDEX 01 45:51:00";
// Act
var importFile = CuesheetImportService.Analyse(fileContent);
// Assert
@@ -78,15 +74,17 @@ public void Analyse_WithSampleCuesheet_CreatesValidCuesheet()
Assert.IsNull(importFile.AnalyseException);
Assert.IsNotNull(importFile.AnalysedCuesheet);
Assert.AreEqual(8, importFile.AnalysedCuesheet.Tracks.Count);
- Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample CD Artist\""), importFile.FileContentRecognized?.ElementAt(0));
- Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample CD Title\""), importFile.FileContentRecognized?.ElementAt(1));
- Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "FILE \"AC DC - TNT.mp3\" MP3"), importFile.FileContentRecognized?.ElementAt(2));
- Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CDTEXTFILE \"Testfile.cdt\""), importFile.FileContentRecognized?.ElementAt(3));
- Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CATALOG 0123456789012"), importFile.FileContentRecognized?.ElementAt(4));
- Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TRACK 01 AUDIO"), importFile.FileContentRecognized?.ElementAt(5));
- Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample Artist 1\"")), importFile.FileContentRecognized?.ElementAt(6));
- Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample Title 1\"")), importFile.FileContentRecognized?.ElementAt(7));
- Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "INDEX 01 00:00:00")), importFile.FileContentRecognized?.ElementAt(8));
+ Assert.IsNotNull(importFile.FileContentRecognized);
+ var lines = importFile.FileContentRecognized.Split(Environment.NewLine);
+ Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample CD Artist\""), lines.ElementAt(0));
+ Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample CD Title\""), lines.ElementAt(1));
+ Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "FILE \"AC DC - TNT.mp3\" MP3"), lines.ElementAt(2));
+ Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CDTEXTFILE \"Testfile.cdt\""), lines.ElementAt(3));
+ Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CATALOG 0123456789012"), lines.ElementAt(4));
+ Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TRACK 01 AUDIO"), lines.ElementAt(5));
+ Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample Artist 1\"")), lines.ElementAt(6));
+ Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample Title 1\"")), lines.ElementAt(7));
+ Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "INDEX 01 00:00:00")), lines.ElementAt(8));
}
[TestMethod()]
@@ -95,12 +93,7 @@ public void Analyse_WithCuesheetBug30_CreatesValidCuesheet()
//Arrange
var textImportMemoryStream = new MemoryStream(Resources.Playlist_Bug_30);
using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
+ var fileContent = reader.ReadToEnd();
//Act
var importFile = CuesheetImportService.Analyse(fileContent);
//Assert
@@ -114,12 +107,7 @@ public void Analyse_WithCuesheetBug57_CreatesValidCuesheet()
//Arrange
var textImportMemoryStream = new MemoryStream(Resources.Playlist_Bug_57);
using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
+ var fileContent = reader.ReadToEnd();
//Act
var importFile = CuesheetImportService.Analyse(fileContent);
//Assert
@@ -135,12 +123,7 @@ public void Analyse_WithCuesheetBug36_CreatesValidCuesheet()
//Arrange
var textImportMemoryStream = new MemoryStream(Resources.Playlist__36_Frames);
using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
+ var fileContent = reader.ReadToEnd();
//Act
var importFile = CuesheetImportService.Analyse(fileContent);
//Assert
@@ -154,57 +137,56 @@ public void Analyse_WithCuesheetBug36_CreatesValidCuesheet()
public void Analyse_WithCDTextFileCatalogueNumberAndPreAndPostGap_CreatesValidCuesheet()
{
// Arrange
- var fileContent = new List
- {
- "PERFORMER \"Sample CD Artist\"",
- "TITLE \"Sample CD Title\"",
- "FILE \"AC DC - TNT.mp3\" MP3",
- "CDTEXTFILE \"Testfile.cdt\"",
- "CATALOG 0123456789012",
- "TRACK 01 AUDIO",
- " PERFORMER \"Sample Artist 1\"",
- " TITLE \"Sample Title 1\"",
- " FLAGS 4CH DCP PRE SCMS",
- " INDEX 01 00:00:00",
- "TRACK 02 AUDIO",
- " PERFORMER \"Sample Artist 2\"",
- " TITLE \"Sample Title 2\"",
- " FLAGS DCP PRE",
- " INDEX 01 05:00:00",
- "TRACK 03 AUDIO",
- " PERFORMER \"Sample Artist 3\"",
- " TITLE \"Sample Title 3\"",
- " INDEX 01 09:23:00",
- "TRACK 04 AUDIO",
- " PERFORMER \"Sample Artist 4\"",
- " TITLE \"Sample Title 4\"",
- " INDEX 01 15:54:00",
- "TRACK 05 AUDIO",
- " PERFORMER \"Sample Artist 5\"",
- " TITLE \"Sample Title 5\"",
- " INDEX 01 20:13:00",
- " POSTGAP 00:02:00",
- "TRACK 06 AUDIO",
- " PERFORMER \"Sample Artist 6\"",
- " TITLE \"Sample Title 6\"",
- " INDEX 01 24:54:00",
- "TRACK 07 AUDIO",
- " PERFORMER \"Sample Artist 7\"",
- " TITLE \"Sample Title 7\"",
- " PREGAP 00:04:00",
- " INDEX 01 31:54:00",
- "TRACK 08 AUDIO",
- " PERFORMER \"Sample Artist 8\"",
- " TITLE \"Sample Title 8\"",
- " INDEX 01 45:51:00"
- };
+ var fileContent = @"PERFORMER ""Sample CD Artist""
+TITLE ""Sample CD Title""
+FILE ""AC DC - TNT.mp3"" MP3
+CDTEXTFILE ""Testfile.cdt""
+CATALOG 0123456789012
+TRACK 01 AUDIO
+ PERFORMER ""Sample Artist 1""
+ TITLE ""Sample Title 1""
+ FLAGS 4CH DCP PRE SCMS
+ INDEX 01 00:00:00
+TRACK 02 AUDIO
+ PERFORMER ""Sample Artist 2""
+ TITLE ""Sample Title 2""
+ FLAGS DCP PRE
+ INDEX 01 05:00:00
+TRACK 03 AUDIO
+ PERFORMER ""Sample Artist 3""
+ TITLE ""Sample Title 3""
+ INDEX 01 09:23:00
+TRACK 04 AUDIO
+ PERFORMER ""Sample Artist 4""
+ TITLE ""Sample Title 4""
+ INDEX 01 15:54:00
+TRACK 05 AUDIO
+ PERFORMER ""Sample Artist 5""
+ TITLE ""Sample Title 5""
+ INDEX 01 20:13:00
+ POSTGAP 00:02:00
+TRACK 06 AUDIO
+ PERFORMER ""Sample Artist 6""
+ TITLE ""Sample Title 6""
+ INDEX 01 24:54:00
+TRACK 07 AUDIO
+ PERFORMER ""Sample Artist 7""
+ TITLE ""Sample Title 7""
+ PREGAP 00:04:00
+ INDEX 01 31:54:00
+TRACK 08 AUDIO
+ PERFORMER ""Sample Artist 8""
+ TITLE ""Sample Title 8""
+ INDEX 01 45:51:00";
// Act
var importFile = CuesheetImportService.Analyse(fileContent);
// Assert
Assert.IsNull(importFile.AnalyseException);
Assert.IsNotNull(importFile.AnalysedCuesheet);
- Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "FLAGS 4CH DCP PRE SCMS")), importFile.FileContentRecognized?.ElementAt(8));
- Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PREGAP 00:04:00")), importFile.FileContentRecognized?.ElementAt(35));
+ Assert.IsNotNull(importFile.FileContentRecognized);
+ var lines = importFile.FileContentRecognized.Split(Environment.NewLine);
+ Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "FLAGS 4CH DCP PRE SCMS")), lines.ElementAt(8));
+ Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PREGAP 00:04:00")), lines.ElementAt(35));
Assert.AreEqual(8, importFile.AnalysedCuesheet.Tracks.Count);
Assert.IsNotNull(importFile.AnalysedCuesheet.CDTextfile);
Assert.AreEqual(4, importFile.AnalysedCuesheet.Tracks.ElementAt(0).Flags.Count());
diff --git a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs
index 2b293be9..f78b881c 100644
--- a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs
+++ b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.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.IO.Audio;
using AudioCuesheetEditor.Services.IO;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.Extensions.Logging;
@@ -37,7 +38,7 @@ public void CheckFileMimeType_ReturnsTrue_WhenContentTypeDoesNotMatchButExtensio
var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
// Act
- var result = manager.CheckFileMimeType(file, "audio/mpeg", ".mp3");
+ var result = manager.CheckFileMimeType(file, "audio/mpeg", [".mp3"]);
// Assert
Assert.IsTrue(result);
@@ -54,7 +55,7 @@ public void CheckFileMimeType_ReturnsTrue_WhenContentTypeDoesMatchButNotExtensio
var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
// Act
- var result = manager.CheckFileMimeType(file, "audio/mpeg", ".mp3");
+ var result = manager.CheckFileMimeType(file, "audio/mpeg", [".mp3", ".txt"]);
// Assert
Assert.IsTrue(result);
@@ -71,7 +72,7 @@ public void CheckFileMimeType_ReturnsFalse_WhenExtensionDoesNotMatchAndContentTy
var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
// Act
- var result = manager.CheckFileMimeType(file, "audio/flac", ".mp3");
+ var result = manager.CheckFileMimeType(file, "audio/flac", [".mp3"]);
// Assert
Assert.IsFalse(result);
@@ -88,12 +89,150 @@ public void CheckFileMimeType_ReturnsTrue_WhenContentTypeAndExtensionMatch()
var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
// Act
- var result = manager.CheckFileMimeType(file, "audio/wave", ".wav");
+ var result = manager.CheckFileMimeType(file, "audio/wave", [".wav"]);
// Assert
Assert.IsTrue(result);
}
+ [TestMethod()]
+ public void CheckFileMimeType_ReturnsTrue_WhenContentMainTypeMatch()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("history.txt", "text/plain");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.CheckFileMimeType(file, "text/*", [".txt", ".text"]);
+
+ // Assert
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod()]
+ public void IsValidAudiofile_ReturnsTrue_WithValidAudiocodec()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.wav", "audio/wav");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.IsValidAudiofile(file);
+
+ // Assert
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod()]
+ public void IsValidAudiofile_ReturnsFalse_WithInvalidAudiocodecAndExtension()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.mock", "just a fantasy");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.IsValidAudiofile(file);
+
+ // Assert
+ Assert.IsFalse(result);
+ }
+
+ [TestMethod()]
+ public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeMatches()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.wbem", "audio/webm");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.GetAudioCodec(file);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.AreEqual(Audiofile.AudioCodecWEBM, result);
+ }
+
+ [TestMethod()]
+ public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeAndFileExtensionMatches()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.webm", "audio/webm");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.GetAudioCodec(file);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.AreEqual(Audiofile.AudioCodecWEBM, result);
+ }
+
+ [TestMethod()]
+ public void GetAudioCodec_ReturnsNull_WhenContentTypeAndFileExtensionNotMatch()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.acx", "fantasy stuff");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.GetAudioCodec(file);
+
+ // Assert
+ Assert.IsNull(result);
+ }
+
+ [TestMethod()]
+ public void IsValidForImportView_ReturnsTrue_WhenFileIsHtml()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.html", "text/html");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.IsValidForImportView(file);
+
+ // Assert
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod()]
+ public void IsValidForImportView_ReturnsFalse_WhenFileIsBinary()
+ {
+ // Arrange
+ var jsRuntimeMock = new Mock();
+ var httpClientMock = new Mock();
+ var loggerMock = new Mock>();
+ var file = CreateBrowserFile("test.dat", "application/octet-stream");
+ var manager = new FileInputManager(jsRuntimeMock.Object, httpClientMock.Object, loggerMock.Object);
+
+ // Act
+ var result = manager.IsValidForImportView(file);
+
+ // Assert
+ Assert.IsFalse(result);
+ }
+
private static IBrowserFile CreateBrowserFile(string name, string contentType)
{
var fileMock = new Mock();
diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs
index 08b24803..36671194 100644
--- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs
+++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs
@@ -14,18 +14,24 @@
//along with Foobar. If not, see
//.
-using AudioCuesheetEditor.Data.Options;
+using AudioCuesheetEditor.Model.AudioCuesheet;
+using AudioCuesheetEditor.Model.AudioCuesheet.Import;
+using AudioCuesheetEditor.Model.IO;
using AudioCuesheetEditor.Model.IO.Import;
-using AudioCuesheetEditor.Model.Options;
-using AudioCuesheetEditor.Model.Utility;
using AudioCuesheetEditor.Services.IO;
using AudioCuesheetEditor.Services.UI;
using AudioCuesheetEditor.Tests.Utility;
+using Microsoft.AspNetCore.Components.Forms;
+using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
namespace AudioCuesheetEditor.Tests.Services.IO
{
@@ -33,78 +39,181 @@ namespace AudioCuesheetEditor.Tests.Services.IO
public class ImportManagerTests
{
[TestMethod()]
- public void ImportTextAsync_TextfileWithStartDateTime_CreatesValidCuesheet()
+ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet()
{
// Arrange
- var fileContent = new List
+ var fileContent = "This is just a test";
+ var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
+ var sessionStateContainer = new SessionStateContainer(traceChangeManager);
+ var fileInputManagerMock = new Mock();
+ var textImportServiceMock = new Mock();
+ var importCuesheet = new ImportCuesheet()
+ {
+ Artist = "Test Cuesheet Artist",
+ Title = "Test Cuesheet Title",
+ Audiofile = "Test Cuesheet Audiofile",
+ Cataloguenumber = "Test Cuesheet Cataloguenumber",
+ CDTextfile = "Test Cuesheet CDTextfile"
+ };
+ importCuesheet.Tracks.Add(new()
+ {
+ Artist = "Test Track Artist 1",
+ Title = "Test Track Title 1",
+ Begin = new TimeSpan(0, 3, 20),
+ End = new TimeSpan(0, 7, 43),
+ Flags = [Flag.DCP],
+ Position = 1,
+ PreGap = new TimeSpan(0, 0, 2),
+ PostGap = new TimeSpan(0, 0, 4)
+ });
+ var importfile = new Importfile()
+ {
+ FileContent = fileContent,
+ FileType = ImportFileType.Textfile,
+ AnalysedCuesheet = importCuesheet
+ };
+ textImportServiceMock.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importfile);
+ var loggerMock = new Mock>();
+ var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
+ var testHelper = new TestHelper();
+ sessionStateContainer.Importfile = new Importfile()
{
- "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"
+ FileContent = "This is just a test",
+ FileType = ImportFileType.Textfile
};
+ // Act
+ await importManager.AnalyseImportfile();
+ // Assert
+ Assert.AreEqual(importfile, sessionStateContainer.Importfile);
+ Assert.IsNotNull(sessionStateContainer.ImportCuesheet);
+ Assert.AreEqual(importCuesheet.Artist, sessionStateContainer.ImportCuesheet.Artist);
+ Assert.AreEqual(importCuesheet.Title, sessionStateContainer.ImportCuesheet.Title);
+ Assert.IsNotNull(sessionStateContainer.ImportCuesheet.Audiofile);
+ Assert.AreEqual(importCuesheet.Audiofile, sessionStateContainer.ImportCuesheet.Audiofile.Name);
+ Assert.AreEqual(importCuesheet.Cataloguenumber, sessionStateContainer.ImportCuesheet.Cataloguenumber);
+ Assert.IsNotNull(sessionStateContainer.ImportCuesheet.CDTextfile);
+ Assert.AreEqual(importCuesheet.CDTextfile, sessionStateContainer.ImportCuesheet.CDTextfile.Name);
+ Assert.AreEqual(importCuesheet.Tracks.First().Artist, sessionStateContainer.ImportCuesheet.Tracks.First().Artist);
+ Assert.AreEqual(importCuesheet.Tracks.First().Title, sessionStateContainer.ImportCuesheet.Tracks.First().Title);
+ Assert.AreEqual(importCuesheet.Tracks.First().Begin, sessionStateContainer.ImportCuesheet.Tracks.First().Begin);
+ Assert.AreEqual(importCuesheet.Tracks.First().End, sessionStateContainer.ImportCuesheet.Tracks.First().End);
+ CollectionAssert.AreEquivalent(importCuesheet.Tracks.First().Flags.ToList(), sessionStateContainer.ImportCuesheet.Tracks.First().Flags.ToList());
+ Assert.AreEqual(importCuesheet.Tracks.First().Position, sessionStateContainer.ImportCuesheet.Tracks.First().Position);
+ Assert.AreEqual(importCuesheet.Tracks.First().PreGap, sessionStateContainer.ImportCuesheet.Tracks.First().PreGap);
+ Assert.AreEqual(importCuesheet.Tracks.First().PostGap, sessionStateContainer.ImportCuesheet.Tracks.First().PostGap);
+ }
+ [TestMethod()]
+ public async Task AnalyseImportfile_WithoutAnalysedCuesheet_DoesNothing()
+ {
+ // Arrange
+ var fileContent = "This is just a test";
var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
+ var fileInputManagerMock = new Mock();
+ var textImportServiceMock = new Mock();
+ var importfile = new Importfile()
{
- SchemeCuesheet = null,
- SchemeTracks = @"(?'Artist'[a-zA-Z0-9_ .();äöü&:,'*-?:]{1,})~(?'Title'[a-zA-Z0-9_ .();äöü&'*-?:Ü]{1,})~(?'StartDateTime'.{1,})"
+ FileContent = fileContent,
+ FileType = ImportFileType.Textfile,
};
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions();
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
+ textImportServiceMock.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importfile);
+ var loggerMock = new Mock>();
+ var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
var testHelper = new TestHelper();
+ sessionStateContainer.Importfile = importfile;
// Act
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
+ await importManager.AnalyseImportfile();
// 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);
+ Assert.AreEqual(importfile, sessionStateContainer.Importfile);
+ Assert.IsNull(sessionStateContainer.ImportCuesheet);
+ }
+
+ [TestMethod]
+ public async Task ImportFilesAsync_ProjectFile_ImportsCorrectly()
+ {
+ // Arrange
+ var fileContent = "This is the content";
+ var file = CreateBrowserFileMock("test.projectfile", fileContent);
+ var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
+ var sessionStateContainer = new SessionStateContainer(traceChangeManager);
+ var fileInputManagerMock = new Mock();
+ var textImportServiceMock = new Mock();
+ fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Projectfile, It.IsAny>())).Returns(true);
+ fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false);
+ fileInputManagerMock.Setup(f => f.IsValidForImportView(file)).Returns(false);
+
+ var loggerMock = new Mock>();
+ var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
+ // Act
+ await importManager.ImportFilesAsync([file]);
+
+ // Assert
+ Assert.IsNotNull(sessionStateContainer.Importfile);
+ Assert.AreEqual(fileContent, sessionStateContainer.Importfile.FileContent);
+ Assert.AreEqual(fileContent, sessionStateContainer.Importfile.FileContentRecognized);
+ Assert.AreEqual(ImportFileType.ProjectFile, sessionStateContainer.Importfile.FileType);
+ }
+
+ [TestMethod]
+ public async Task ImportFilesAsync_CuesheetFile_ImportsCorrectly()
+ {
+ // Arrange
+ var fileContent = "Cuesheet file content";
+ var file = CreateBrowserFileMock("test.cue", fileContent);
+ var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
+ var sessionStateContainer = new SessionStateContainer(traceChangeManager);
+ var fileInputManagerMock = new Mock();
+ var textImportServiceMock = new Mock();
+ fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false);
+ fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(true);
+ fileInputManagerMock.Setup(f => f.IsValidForImportView(file)).Returns(false);
+
+ var loggerMock = new Mock>();
+ var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
+ // Act
+ await importManager.ImportFilesAsync([file]);
+
+ // Assert
+ Assert.IsNotNull(sessionStateContainer.Importfile);
+ Assert.AreEqual(fileContent, sessionStateContainer.Importfile.FileContent);
+ Assert.AreEqual(fileContent, sessionStateContainer.Importfile.FileContentRecognized);
+ Assert.AreEqual(ImportFileType.Cuesheet, sessionStateContainer.Importfile.FileType);
+ }
+
+ [TestMethod]
+ public async Task ImportFilesAsync_TextFile_ImportsCorrectly()
+ {
+ // Arrange
+ var fileContent = "TextFileContent";
+ var file = CreateBrowserFileMock("test.txt", fileContent);
+ var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
+ var sessionStateContainer = new SessionStateContainer(traceChangeManager);
+ var fileInputManagerMock = new Mock();
+ var textImportServiceMock = new Mock();
+ fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false);
+ fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false);
+ fileInputManagerMock.Setup(f => f.IsValidForImportView(file)).Returns(true);
+
+ var loggerMock = new Mock>();
+ var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
+ // Act
+ await importManager.ImportFilesAsync([file]);
+
+ // Assert
+ Assert.IsNotNull(sessionStateContainer.Importfile);
+ Assert.AreEqual(fileContent, sessionStateContainer.Importfile.FileContent);
+ Assert.AreEqual(fileContent, sessionStateContainer.Importfile.FileContentRecognized);
+ Assert.AreEqual(ImportFileType.Textfile, sessionStateContainer.Importfile.FileType);
+ }
+
+ private static IBrowserFile CreateBrowserFileMock(string name, string content = "TestContent")
+ {
+ var fileMock = new Mock();
+ fileMock.Setup(f => f.Name).Returns(name);
+ fileMock.Setup(f => f.OpenReadStream(It.IsAny(), It.IsAny()))
+ .Returns(new MemoryStream(Encoding.UTF8.GetBytes(content)));
+ return fileMock.Object;
}
}
}
\ No newline at end of file
diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs
index e95cfd6c..a59f9a35 100644
--- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs
+++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs
@@ -13,45 +13,49 @@
//You should have received a copy of the GNU General Public License
//along with Foobar. If not, see
//.
+using AudioCuesheetEditor.Data.Options;
using AudioCuesheetEditor.Model.AudioCuesheet;
+using AudioCuesheetEditor.Model.AudioCuesheet.Import;
using AudioCuesheetEditor.Model.IO.Import;
+using AudioCuesheetEditor.Model.Options;
using AudioCuesheetEditor.Model.Utility;
using AudioCuesheetEditor.Services.IO;
using AudioCuesheetEditor.Tests.Properties;
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.Tests.Services.IO
{
[TestClass()]
public class TextImportServiceTests
{
+
[TestMethod()]
- public void Analyse_SampleCuesheet_CreatesValidCuesheet()
+ public async Task AnalyseAsync_SampleCuesheet_CreatesValidCuesheetAsync()
{
// Arrange
- var fileContent = new List
+ var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3
+Sample Artist 1 - Sample Title 1 00:05:00
+Sample Artist 2 - Sample Title 2 00:09:23
+Sample Artist 3 - Sample Title 3 00:15:54
+Sample Artist 4 - Sample Title 4 00:20:13
+Sample Artist 5 - Sample Title 5 00:24:54
+Sample Artist 6 - Sample Title 6 00:31:54
+Sample Artist 7 - Sample Title 7 00:45:54
+Sample Artist 8 - Sample Title 8 01:15:54";
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- "CuesheetArtist - CuesheetTitle c:\\tmp\\Testfile.mp3",
- "Sample Artist 1 - Sample Title 1 00:05:00",
- "Sample Artist 2 - Sample Title 2 00:09:23",
- "Sample Artist 3 - Sample Title 3 00:15:54",
- "Sample Artist 4 - Sample Title 4 00:20:13",
- "Sample Artist 5 - Sample Title 5 00:24:54",
- "Sample Artist 6 - Sample Title 6 00:31:54",
- "Sample Artist 7 - Sample Title 7 00:45:54",
- "Sample Artist 8 - Sample Title 8 01:15:54"
- };
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = TextImportScheme.DefaultSchemeCuesheet,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
+ SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -65,55 +69,65 @@ public void Analyse_SampleCuesheet_CreatesValidCuesheet()
}
[TestMethod()]
- public void Analyse_InvalidSchemeTracks_CreatesAnalyseException()
+ public async Task AnalyseAsync_InvalidSchemeTracks_CreatesAnalyseExceptionAsync()
{
// Arrange
- var fileContent = new List
- {
- "CuesheetArtist|CuesheetTitle c:\\tmp\\TestTextFile.cdt",
- "1|Sample Artist 1 - Sample Title 1 00:05:00",
- "2|Sample Artist 2 - Sample Title 2 00:09:23",
- "3|Sample Artist 3 - Sample Title 3 00:15:54",
- "4|Sample Artist 4 - Sample Title 4 00:20:13",
- "5|Sample Artist 5 - Sample Title 5 00:24:54",
- "6|Sample Artist 6 - Sample Title 6 00:31:54",
- "7|Sample Artist 7 - Sample Title 7 00:45:54",
- "8|Sample Artist 8 - Sample Title 8 01:15:54"
- };
- var textImportScheme = new TextImportScheme()
+ var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt
+1|Sample Artist 1 - Sample Title 1 00:05:00
+2|Sample Artist 2 - Sample Title 2 00:09:23
+3|Sample Artist 3 - Sample Title 3 00:15:54
+4|Sample Artist 4 - Sample Title 4 00:20:13
+5|Sample Artist 5 - Sample Title 5 00:24:54
+6|Sample Artist 6 - Sample Title 6 00:31:54
+7|Sample Artist 7 - Sample Title 7 00:45:54
+8|Sample Artist 8 - Sample Title 8 01:15:54";
+ var profile = new Importprofile()
{
+ UseRegularExpression = true,
SchemeCuesheet = @"(?'Cuesheet.Artist'\A.*)[|](?'Cuesheet.Title'\w{1,})\t{1,}(?'Cuesheet.CDTextfile'.{1,})",
SchemeTracks = @"(?'Track.Position'.{1,})|(?'Track.Artist'.{1,}) - (?'Track.Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Track.End'.{1,})"
};
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNotNull(importfile.AnalyseException);
}
[TestMethod()]
- public void Analyse_InputfileWithExtraSeperator_CreatesValidCuesheet()
+ public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetAsync()
{
// Arrange
- var fileContent = new List
+ var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt
+1|Sample Artist 1 - Sample Title 1 00:05:00
+2|Sample Artist 2 - Sample Title 2 00:09:23
+3|Sample Artist 3 - Sample Title 3 00:15:54
+4|Sample Artist 4 - Sample Title 4 00:20:13
+5|Sample Artist 5 - Sample Title 5 00:24:54
+6|Sample Artist 6 - Sample Title 6 00:31:54
+7|Sample Artist 7 - Sample Title 7 00:45:54
+8|Sample Artist 8 - Sample Title 8 01:15:54";
+ var profile = new Importprofile()
{
- "CuesheetArtist|CuesheetTitle c:\\tmp\\TestTextFile.cdt",
- "1|Sample Artist 1 - Sample Title 1 00:05:00",
- "2|Sample Artist 2 - Sample Title 2 00:09:23",
- "3|Sample Artist 3 - Sample Title 3 00:15:54",
- "4|Sample Artist 4 - Sample Title 4 00:20:13",
- "5|Sample Artist 5 - Sample Title 5 00:24:54",
- "6|Sample Artist 6 - Sample Title 6 00:31:54",
- "7|Sample Artist 7 - Sample Title 7 00:45:54",
- "8|Sample Artist 8 - Sample Title 8 01:15:54"
+ UseRegularExpression = true,
+ SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[^\r\n]+)",
+ SchemeTracks = @"(?'Position'\d{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})"
};
- var textImportScheme = new TextImportScheme()
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'.{1,})",
- SchemeTracks = @"(?'Position'\d{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})"
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -126,30 +140,34 @@ public void Analyse_InputfileWithExtraSeperator_CreatesValidCuesheet()
Assert.AreEqual("Sample Title 1", importfile.AnalysedCuesheet.Tracks.ElementAt(0).Title);
Assert.AreEqual(new TimeSpan(0, 5, 0), importfile.AnalysedCuesheet.Tracks.ElementAt(0).End);
}
-
+
[TestMethod()]
- public void Analyse_InputfileWithSimplifiedScheme_CreatesValidCuesheet()
+ public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCuesheetAsync()
{
- // Arrange
- var fileContent = new List
- {
- "CuesheetArtist|CuesheetTitle c:\\tmp\\TestTextFile.cdt",
- "1|Sample Artist 1 - Sample Title 1 00:05:00",
- "2|Sample Artist 2 - Sample Title 2 00:09:23",
- "3|Sample Artist 3 - Sample Title 3 00:15:54",
- "4|Sample Artist 4 - Sample Title 4 00:20:13",
- "5|Sample Artist 5 - Sample Title 5 00:24:54",
- "6|Sample Artist 6 - Sample Title 6 00:31:54",
- "7|Sample Artist 7 - Sample Title 7 00:45:54",
- "8|Sample Artist 8 - Sample Title 8 01:15:54"
- };
- var textImportScheme = new TextImportScheme()
+ var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt
+1|Sample Artist 1 - Sample Title 1 00:05:00
+2|Sample Artist 2 - Sample Title 2 00:09:23
+3|Sample Artist 3 - Sample Title 3 00:15:54
+4|Sample Artist 4 - Sample Title 4 00:20:13
+5|Sample Artist 5 - Sample Title 5 00:24:54
+6|Sample Artist 6 - Sample Title 6 00:31:54
+7|Sample Artist 7 - Sample Title 7 00:45:54
+8|Sample Artist 8 - Sample Title 8 01:15:54";
+ var profile = new Importprofile()
{
+ UseRegularExpression = false,
SchemeCuesheet = @"Artist|Title CDTextfile",
SchemeTracks = @"Position|Artist - Title End"
};
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -164,71 +182,83 @@ public void Analyse_InputfileWithSimplifiedScheme_CreatesValidCuesheet()
}
[TestMethod()]
- public void Analyse_InvalidScheme_CreatesAnalyseException()
+ public async Task AnalyseAsync_InvalidScheme_CreatesAnalyseExceptionAsync()
{
// Arrange
- var fileContent = new List
- {
- "CuesheetArtist|CuesheetTitle c:\\tmp\\TestTextFile.cdt A83412346734",
- "1|Sample Artist 1 - Sample Title 1 00:05:00",
- "2|Sample Artist 2 - Sample Title 2 00:09:23",
- "3|Sample Artist 3 - Sample Title 3 00:15:54",
- "4|Sample Artist 4 - Sample Title 4 00:20:13",
- "5|Sample Artist 5 - Sample Title 5 00:24:54",
- "6|Sample Artist 6 - Sample Title 6 00:31:54",
- "7|Sample Artist 7 - Sample Title 7 00:45:54",
- "8|Sample Artist 8 - Sample Title 8 01:15:54",
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty
- };
- var textImportScheme = new TextImportScheme()
+ var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt A83412346734
+1|Sample Artist 1 - Sample Title 1 00:05:00
+2|Sample Artist 2 - Sample Title 2 00:09:23
+3|Sample Artist 3 - Sample Title 3 00:15:54
+4|Sample Artist 4 - Sample Title 4 00:20:13
+5|Sample Artist 5 - Sample Title 5 00:24:54
+6|Sample Artist 6 - Sample Title 6 00:31:54
+7|Sample Artist 7 - Sample Title 7 00:45:54
+8|Sample Artist 8 - Sample Title 8 01:15:54
+
+
+
+
+
+
+
+
+";
+ var profile = new Importprofile()
{
+ UseRegularExpression = true,
SchemeCuesheet = @"(?'Cuesheet.Artist'\A.*)[|](?'Cuesheet.Title'\w{1,})\t{1,}(?'Cuesheet.CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cuesheet.Cataloguenumber'.{1,})",
SchemeTracks = @"(?'Track.Position'.{1,})|(?'Track.Artist'.{1,}) - (?'Track.Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Track.End'.{1,})"
};
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNotNull(importfile.AnalyseException);
}
[TestMethod()]
- public void Analyse_CuesheetWithTextfileAndCatalogueNumber_CreatesValidCuesheet()
+ public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesValidCuesheetAsync()
{
// Arrange
- var fileContent = new List
- {
- "CuesheetArtist|CuesheetTitle c:\\tmp\\TestTextFile.cdt A83412346734",
- "1|Sample Artist 1 - Sample Title 1 00:05:00",
- "2|Sample Artist 2 - Sample Title 2 00:09:23",
- "3|Sample Artist 3 - Sample Title 3 00:15:54",
- "4|Sample Artist 4 - Sample Title 4 00:20:13",
- "5|Sample Artist 5 - Sample Title 5 00:24:54",
- "6|Sample Artist 6 - Sample Title 6 00:31:54",
- "7|Sample Artist 7 - Sample Title 7 00:45:54",
- "8|Sample Artist 8 - Sample Title 8 01:15:54",
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty,
- string.Empty
- };
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cataloguenumber'.{1,})",
+ var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt A83412346734
+1|Sample Artist 1 - Sample Title 1 00:05:00
+2|Sample Artist 2 - Sample Title 2 00:09:23
+3|Sample Artist 3 - Sample Title 3 00:15:54
+4|Sample Artist 4 - Sample Title 4 00:20:13
+5|Sample Artist 5 - Sample Title 5 00:24:54
+6|Sample Artist 6 - Sample Title 6 00:31:54
+7|Sample Artist 7 - Sample Title 7 00:45:54
+8|Sample Artist 8 - Sample Title 8 01:15:54
+
+
+
+
+
+
+
+
+";
+ var profile = new Importprofile()
+ {
+ UseRegularExpression = true,
+ SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cataloguenumber'[^\r\n]+)",
SchemeTracks = @"(?'Position'.{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})"
};
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -244,28 +274,31 @@ public void Analyse_CuesheetWithTextfileAndCatalogueNumber_CreatesValidCuesheet(
}
[TestMethod()]
- public void Analyse_CuesheeTracksOnly_CreatesValidCuesheet()
+ public async Task AnalyseAsync_CuesheeTracksOnly_CreatesValidCuesheetAsync()
{
// Arrange
- var fileContent = new List
+ var fileContent = @"Sample Artist 1 - Sample Title 1 00:05:00
+Sample Artist 2 - Sample Title 2 00:09:23
+Sample Artist 3 - Sample Title 3 00:15:54
+Sample Artist 4 - Sample Title 4 00:20:13
+Sample Artist 5 - Sample Title 5 00:24:54
+Sample Artist 6 - Sample Title 6 00:31:54
+Sample Artist 7 - Sample Title 7 00:45:54
+Sample Artist 8 - Sample Title 8 01:15:54
+Sample Artist 9 - Sample Title 9 ";
+ var profile = new Importprofile()
{
- "Sample Artist 1 - Sample Title 1 00:05:00",
- "Sample Artist 2 - Sample Title 2 00:09:23",
- "Sample Artist 3 - Sample Title 3 00:15:54",
- "Sample Artist 4 - Sample Title 4 00:20:13",
- "Sample Artist 5 - Sample Title 5 00:24:54",
- "Sample Artist 6 - Sample Title 6 00:31:54",
- "Sample Artist 7 - Sample Title 7 00:45:54",
- "Sample Artist 8 - Sample Title 8 01:15:54",
- "Sample Artist 9 - Sample Title 9"
+ SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}"
};
- var textImportScheme = new TextImportScheme()
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = null,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -276,25 +309,26 @@ public void Analyse_CuesheeTracksOnly_CreatesValidCuesheet()
}
[TestMethod()]
- public void Analyse_CuesheetBug213_CreatesValidCuesheet()
+ public async Task AnalyseAsync_CuesheetBug213_CreatesValidCuesheetAsync()
{
// Arrange
var textImportMemoryStream = new MemoryStream(Resources.Textimport_Bug_213);
using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
+ var fileContent = reader.ReadToEnd();
+ var profile = new Importprofile()
{
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
- var timeSpanFormat = new TimeSpanFormat() { Scheme = "Minutes:Seconds" };
- var textImportScheme = new TextImportScheme()
+ SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}",
+ TimeSpanFormat = new() { Scheme = $"{nameof(TimeSpanFormat.Minutes)}:{nameof(TimeSpanFormat.Seconds)}" }
+ };
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = null,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent, timeSpanFormat);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -303,27 +337,31 @@ public void Analyse_CuesheetBug213_CreatesValidCuesheet()
}
[TestMethod()]
- public void Analyse_CuesheetWithFlags_CreatesValidCuesheet()
+ public async Task AnalyseAsync_CuesheetWithFlags_CreatesValidCuesheetAsync()
{
// Arrange
- var fileContent = new List
+ var fileContent = @"Sample Artist 1 - Sample Title 1 00:05:00 DCP
+Sample Artist 2 - Sample Title 2 00:09:23
+Sample Artist 3 - Sample Title 3 00:15:54 PRE, DCP
+Sample Artist 4 - Sample Title 4 00:20:13 4CH
+Sample Artist 5 - Sample Title 5 00:24:54
+Sample Artist 6 - Sample Title 6 00:31:54 PRE DCP 4CH
+Sample Artist 7 - Sample Title 7 00:45:54
+Sample Artist 8 - Sample Title 8 01:15:54 PRE DCP 4CH SCMS";
+ var profile = new Importprofile()
{
- "Sample Artist 1 - Sample Title 1 00:05:00 DCP",
- "Sample Artist 2 - Sample Title 2 00:09:23",
- "Sample Artist 3 - Sample Title 3 00:15:54 PRE, DCP",
- "Sample Artist 4 - Sample Title 4 00:20:13 4CH",
- "Sample Artist 5 - Sample Title 5 00:24:54",
- "Sample Artist 6 - Sample Title 6 00:31:54 PRE DCP 4CH",
- "Sample Artist 7 - Sample Title 7 00:45:54",
- "Sample Artist 8 - Sample Title 8 01:15:54 PRE DCP 4CH SCMS"
+ UseRegularExpression = true,
+ SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]+) - (?'Title'[a-zA-Z0-9_ .();äöü]+)[\t ]+(?'End'[0-9]{2}:[0-9]{2}:[0-9]{2})(?:[\t ]+(?'Flags'[A-Za-z0-9 ,]+))?(?=[\t ]*(?:\r?\n|$))"
};
- var textImportScheme = new TextImportScheme()
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = null,
- SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Title'[a-zA-Z0-9_ .();äöü]{1,})\t{1,}(?'End'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'Flags'[a-zA-Z 0-9,]{1,})"
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -342,27 +380,31 @@ public void Analyse_CuesheetWithFlags_CreatesValidCuesheet()
}
[TestMethod()]
- public void Analyse_CuesheetWithPreGapAndPostGap_CreatesValidCuesheet()
+ public async Task AnalyseAsync_CuesheetWithPreGapAndPostGap_CreatesValidCuesheetAsync()
{
// Arrange
- var fileContent = new List
+ var fileContent = @"Sample Artist 1 - Sample Title 1 00:00:02 00:05:00 00:00:00
+Sample Artist 2 - Sample Title 2 00:00:04 00:09:23 00:00:00
+Sample Artist 3 - Sample Title 3 00:00:00 00:15:54 00:00:02
+Sample Artist 4 - Sample Title 4 00:00:00 00:20:13 00:00:03
+Sample Artist 5 - Sample Title 5 00:00:00 00:24:54 00:00:04
+Sample Artist 6 - Sample Title 6 00:00:00 00:31:54 00:00:01
+Sample Artist 7 - Sample Title 7 00:00:00 00:45:54 00:00:00
+Sample Artist 8 - Sample Title 8 00:00:02 01:15:54 00:00:00";
+ var profile = new Importprofile()
{
- "Sample Artist 1 - Sample Title 1 00:00:02 00:05:00 00:00:00",
- "Sample Artist 2 - Sample Title 2 00:00:04 00:09:23 00:00:00",
- "Sample Artist 3 - Sample Title 3 00:00:00 00:15:54 00:00:02",
- "Sample Artist 4 - Sample Title 4 00:00:00 00:20:13 00:00:03",
- "Sample Artist 5 - Sample Title 5 00:00:00 00:24:54 00:00:04",
- "Sample Artist 6 - Sample Title 6 00:00:00 00:31:54 00:00:01",
- "Sample Artist 7 - Sample Title 7 00:00:00 00:45:54 00:00:00",
- "Sample Artist 8 - Sample Title 8 00:00:02 01:15:54 00:00:00"
+ UseRegularExpression = true,
+ SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Title'[a-zA-Z0-9_ .();äöü]{1,})\t{1,}(?'PreGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'End'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'PostGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})"
};
- var textImportScheme = new TextImportScheme()
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = null,
- SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Title'[a-zA-Z0-9_ .();äöü]{1,})\t{1,}(?'PreGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'End'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'PostGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})"
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -386,73 +428,76 @@ public void Analyse_CuesheetWithPreGapAndPostGap_CreatesValidCuesheet()
}
[TestMethod()]
- public void Analyse_SchemeCuesheetOnly_CreatesFileContentRecognizedOnlyForCuesheet()
+ public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOnlyForCuesheetAsync()
{
// Arrange
- var fileContent = new List
+ var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3
+Sample Artist 1 - Sample Title 1 00:05:00
+Sample Artist 2 - Sample Title 2 00:09:23
+Sample Artist 3 - Sample Title 3 00:15:54
+Sample Artist 4 - Sample Title 4 00:20:13
+Sample Artist 5 - Sample Title 5 00:24:54
+Sample Artist 6 - Sample Title 6 00:31:54
+Sample Artist 7 - Sample Title 7 00:45:54
+Sample Artist 8 - Sample Title 8 01:15:54";
+ var profile = new Importprofile()
{
- "CuesheetArtist - CuesheetTitle c:\\tmp\\Testfile.mp3",
- "Sample Artist 1 - Sample Title 1 00:05:00",
- "Sample Artist 2 - Sample Title 2 00:09:23",
- "Sample Artist 3 - Sample Title 3 00:15:54",
- "Sample Artist 4 - Sample Title 4 00:20:13",
- "Sample Artist 5 - Sample Title 5 00:24:54",
- "Sample Artist 6 - Sample Title 6 00:31:54",
- "Sample Artist 7 - Sample Title 7 00:45:54",
- "Sample Artist 8 - Sample Title 8 01:15:54"
+ SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}\t{nameof(ImportCuesheet.Audiofile)}"
};
- var textImportScheme = new TextImportScheme()
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = TextImportScheme.DefaultSchemeCuesheet,
- SchemeTracks = null
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
Assert.IsNotNull(importfile.FileContentRecognized);
+ var lines = importfile.FileContentRecognized.Split(Environment.NewLine);
Assert.AreEqual(string.Format("{0} - {1} {2}",
string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"),
string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle"),
- string.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\tmp\\Testfile.mp3")), importfile.FileContentRecognized.First());
+ string.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\tmp\\Testfile.mp3")), lines.First());
Assert.AreEqual("CuesheetArtist", importfile.AnalysedCuesheet.Artist);
Assert.AreEqual("CuesheetTitle", importfile.AnalysedCuesheet.Title);
Assert.AreEqual("c:\\tmp\\Testfile.mp3", importfile.AnalysedCuesheet.Audiofile);
Assert.AreEqual(0, importfile.AnalysedCuesheet.Tracks.Count);
- Assert.AreEqual("Sample Artist 1 - Sample Title 1 00:05:00", importfile.FileContentRecognized.ElementAt(1));
- Assert.AreEqual("Sample Artist 2 - Sample Title 2 00:09:23", importfile.FileContentRecognized.ElementAt(2));
- Assert.AreEqual("Sample Artist 3 - Sample Title 3 00:15:54", importfile.FileContentRecognized.ElementAt(3));
- Assert.AreEqual("Sample Artist 4 - Sample Title 4 00:20:13", importfile.FileContentRecognized.ElementAt(4));
- Assert.AreEqual("Sample Artist 5 - Sample Title 5 00:24:54", importfile.FileContentRecognized.ElementAt(5));
- Assert.AreEqual("Sample Artist 6 - Sample Title 6 00:31:54", importfile.FileContentRecognized.ElementAt(6));
- Assert.AreEqual("Sample Artist 7 - Sample Title 7 00:45:54", importfile.FileContentRecognized.ElementAt(7));
- Assert.AreEqual("Sample Artist 8 - Sample Title 8 01:15:54", importfile.FileContentRecognized.ElementAt(8));
+ Assert.AreEqual("Sample Artist 1 - Sample Title 1 00:05:00", lines.ElementAt(1));
+ Assert.AreEqual("Sample Artist 2 - Sample Title 2 00:09:23", lines.ElementAt(2));
+ Assert.AreEqual("Sample Artist 3 - Sample Title 3 00:15:54", lines.ElementAt(3));
+ Assert.AreEqual("Sample Artist 4 - Sample Title 4 00:20:13", lines.ElementAt(4));
+ Assert.AreEqual("Sample Artist 5 - Sample Title 5 00:24:54", lines.ElementAt(5));
+ Assert.AreEqual("Sample Artist 6 - Sample Title 6 00:31:54", lines.ElementAt(6));
+ Assert.AreEqual("Sample Artist 7 - Sample Title 7 00:45:54", lines.ElementAt(7));
+ Assert.AreEqual("Sample Artist 8 - Sample Title 8 01:15:54", lines.ElementAt(8));
}
[TestMethod()]
- public void Analyse_CuesheetWithoutTracks_CreatesValidFileContentRecognized()
+ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentRecognizedAsync()
{
// Arrange
- var fileContent = new List
- {
- "CuesheetArtist - CuesheetTitle c:\\tmp\\Testfile.mp3",
- "Sample Artist 1 - Sample Title 1 00:05:00",
- "Sample Artist 2 - Sample Title 2 00:09:23",
- "Sample Artist 3 - Sample Title 3 00:15:54",
- "Sample Artist 4 - Sample Title 4 00:20:13",
- "Sample Artist 5 - Sample Title 5 00:24:54",
- "Sample Artist 6 - Sample Title 6 00:31:54",
- "Sample Artist 7 - Sample Title 7 00:45:54",
- "Sample Artist 8 - Sample Title 8 01:15:54"
- };
- var textImportScheme = new TextImportScheme()
+ var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3
+Sample Artist 1 - Sample Title 1 00:05:00
+Sample Artist 2 - Sample Title 2 00:09:23
+Sample Artist 3 - Sample Title 3 00:15:54
+Sample Artist 4 - Sample Title 4 00:20:13
+Sample Artist 5 - Sample Title 5 00:24:54
+Sample Artist 6 - Sample Title 6 00:31:54
+Sample Artist 7 - Sample Title 7 00:45:54
+Sample Artist 8 - Sample Title 8 01:15:54";
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = TextImportScheme.DefaultSchemeCuesheet,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
+ SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
@@ -461,39 +506,225 @@ public void Analyse_CuesheetWithoutTracks_CreatesValidFileContentRecognized()
Assert.AreEqual("Sample Artist 1", importfile.AnalysedCuesheet.Tracks.ElementAt(0).Artist);
Assert.AreEqual("Sample Title 1", importfile.AnalysedCuesheet.Tracks.ElementAt(0).Title);
Assert.AreEqual(new TimeSpan(0, 5, 0), importfile.AnalysedCuesheet.Tracks.ElementAt(0).End);
+ var lines = importfile.FileContentRecognized.Split(Environment.NewLine);
Assert.AreEqual(string.Format("{0} - {1} {2}",
string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"),
string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Title 8"),
- string.Format(CuesheetConstants.RecognizedMarkHTML, "01:15:54")), importfile.FileContentRecognized.Last());
+ string.Format(CuesheetConstants.RecognizedMarkHTML, "01:15:54")), lines.Last());
}
[TestMethod()]
- public void Analyse_TextfileBug233_CreatesValidFileContentRecognized()
+ public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedAsync()
{
// Arrange
- var textImportMemoryStream = new MemoryStream(Resources.Textimport_Bug__233);
- using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
+ var profile = new Importprofile()
{
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
- var textImportScheme = new TextImportScheme()
+ SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}"
+ };
+ var textImportMemoryStream = new MemoryStream(Resources.Textimport_Bug__233);
+ using var reader = new StreamReader(textImportMemoryStream);
+ var fileContent = reader.ReadToEnd();
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
{
- SchemeCuesheet = null,
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
+ SelectedImportProfile = profile
};
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
// Act
- var importfile = TextImportService.Analyse(textImportScheme, fileContent);
+ var importfile = await service.AnalyseAsync(fileContent);
// Assert
Assert.IsNull(importfile.AnalyseException);
Assert.IsNotNull(importfile.AnalysedCuesheet);
Assert.IsNotNull(importfile.FileContentRecognized);
+ var lines = importfile.FileContentRecognized.Split(Environment.NewLine);
Assert.AreEqual(string.Format("{0} - {1}\t\t\t\t\t\t\t\t{2}",
string.Format(CuesheetConstants.RecognizedMarkHTML, "Age Of Love"),
string.Format(CuesheetConstants.RecognizedMarkHTML, "The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)"),
- string.Format(CuesheetConstants.RecognizedMarkHTML, "04:29:28")), importfile.FileContentRecognized.ElementAt(53));
+ string.Format(CuesheetConstants.RecognizedMarkHTML, "04:29:28")), lines.ElementAt(53));
+ }
+
+ [TestMethod()]
+ public async Task AnalyseAsync_WithRegularExpression_ReturnsCuesheetAsync()
+ {
+ // Arrange
+ var profile = new Importprofile()
+ {
+ UseRegularExpression = true,
+ SchemeTracks = "\\s*| \\d+ | \\s*(?.*?) | \\s*(?.*?) | \\s*(?.*?) | \\s*
"
+ };
+ var textImportMemoryStream = new MemoryStream(Resources.Traktor_Export);
+ var reader = new StreamReader(textImportMemoryStream);
+ var fileContent = reader.ReadToEnd();
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
+ // Act
+ var importfile = await service.AnalyseAsync(fileContent);
+ // Assert
+ Assert.AreEqual(fileContent, importfile.FileContent);
+ Assert.IsNull(importfile.AnalyseException);
+ Assert.IsNotNull(importfile.AnalysedCuesheet);
+ Assert.IsNull(importfile.AnalysedCuesheet.Artist);
+ Assert.IsNull(importfile.AnalysedCuesheet.Title);
+ Assert.AreEqual(41, importfile.AnalysedCuesheet.Tracks.Count);
+ Assert.AreEqual("Nachap", importfile.AnalysedCuesheet.Tracks.First().Artist);
+ Assert.AreEqual("Glass", importfile.AnalysedCuesheet.Tracks.First().Title);
+ Assert.AreEqual(new DateTime(2025, 1, 29, 18, 52, 10), importfile.AnalysedCuesheet.Tracks.First().StartDateTime);
+ Assert.AreEqual("Inache", importfile.AnalysedCuesheet.Tracks.Last().Artist);
+ Assert.AreEqual("Andale (MONTA (TN) Remix)", importfile.AnalysedCuesheet.Tracks.Last().Title);
+ Assert.AreEqual(new DateTime(2025, 1, 29, 22, 30, 3), importfile.AnalysedCuesheet.Tracks.Last().StartDateTime);
+ Assert.IsNotNull(importfile.FileContentRecognized);
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sasha Fashion")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "2025/1/29 21:48:55")));
+ }
+
+ [TestMethod()]
+ public async Task AnalyseAsync_WithoutRegularExpression_ReturnsCuesheetAsync()
+ {
+ // Arrange
+ var profile = new Importprofile()
+ {
+ UseRegularExpression = false,
+ SchemeCuesheet = "Artist - Title - Cataloguenumber",
+ SchemeTracks = "Artist - Title\tBegin"
+ };
+ var textImportMemoryStream = new MemoryStream(Resources.Textimport_with_Cuesheetdata);
+ var reader = new StreamReader(textImportMemoryStream);
+ var fileContent = reader.ReadToEnd();
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
+ // Act
+ var importfile = await service.AnalyseAsync(fileContent);
+ // Assert
+ Assert.IsNull(importfile.AnalyseException);
+ Assert.IsNotNull(importfile.AnalysedCuesheet);
+ Assert.AreEqual("DJFreezeT", importfile.AnalysedCuesheet.Artist);
+ Assert.AreEqual("Rabbit Hole Mix", importfile.AnalysedCuesheet.Title);
+ Assert.AreEqual("0123456789123", importfile.AnalysedCuesheet.Cataloguenumber);
+ Assert.AreEqual("Adriatique", importfile.AnalysedCuesheet.Tracks.First().Artist);
+ Assert.AreEqual("X.", importfile.AnalysedCuesheet.Tracks.First().Title);
+ Assert.AreEqual(new TimeSpan(0, 0, 5, 24, 250), importfile.AnalysedCuesheet.Tracks.First().Begin);
+ Assert.AreEqual("Nikolay Kirov", importfile.AnalysedCuesheet.Tracks.Last().Artist);
+ Assert.AreEqual("Chasing the Sun (Original Mix)", importfile.AnalysedCuesheet.Tracks.Last().Title);
+ Assert.IsNull(importfile.AnalysedCuesheet.Tracks.Last().Begin);
+ Assert.IsNotNull(importfile.FileContentRecognized);
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "DJFreezeT")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Rabbit Hole Mix")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "0123456789123")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Nikolay Kirov")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Chasing the Sun (Original Mix)")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "SHDW & Obscure Shape")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Wächter der Nacht (Original Mix)")));
+ }
+
+ [TestMethod()]
+ public async Task AnalyseAsync_TextfileWithStartDateTime_CreatesValidCuesheetAsync()
+ {
+ // Arrange
+ var fileContent = $@"Innellea~The Golden Fort~{new DateTime(2024, 8, 14, 20, 10, 48)}
+Nora En Pure~Diving with Whales (Daniel Portman Remix)~{new DateTime(2024, 8, 14, 20, 15, 21)}
+WhoMadeWho & Adriatique~Miracle (RÜFÜS DU SOL Remix)~{new DateTime(2024, 8, 14, 20, 20, 42)}
+Ella Wild~Poison D'araignee (Original Mix)~{new DateTime(2024, 8, 14, 20, 28, 03)}
+Stil & Bense~On The Edge (Original Mix)~{new DateTime(2024, 8, 14, 20, 32, 42)}
+Nebula~Clairvoyant Dreams~{new DateTime(2024, 8, 14, 20, 39, 1)}
+Valentina Black~I'm a Tree (Extended Mix)~{new DateTime(2024, 8, 14, 20, 47, 08)}
+Nebula~Clairvoyant Dreams~{new DateTime(2024, 8, 14, 20, 53, 20)}
+Kiko & Dave Davis feat. Phoebe~Living in Space (Dub Mix)~{new DateTime(2024, 8, 14, 20, 58, 11)}
+Lilly Palmer~Before Acid~{new DateTime(2024, 8, 14, 21, 03, 53)}
+Sofi Tukker~Drinkee (Vintage Culture & John Summit Extended Mix)~{new DateTime(2024, 8, 14, 21, 09, 52)}
+CID & Truth x Lies~Caroline (Extended Mix)~{new DateTime(2024, 8, 14, 21, 14, 09)}
+Moby~Why Does My Heart Feel So Bad? (Oxia Remix)~{new DateTime(2024, 8, 14, 21, 17, 15)}
+Ammo Avenue~Little Gurl (Extended Mix)~{new DateTime(2024, 8, 14, 21, 22, 46)}
+James Hurr & Smokin Jo & Stealth~Beggin' For Change~{new DateTime(2024, 8, 14, 21, 28, 37)}
+Kristine Blond~Love Shy (Sam Divine & CASSIMM Extended Remix)~{new DateTime(2024, 8, 14, 21, 30, 47)}
+Vanilla Ace~Work On You (Original Mix)~{new DateTime(2024, 8, 14, 21, 36, 28)}
+Truth X Lies~Like This~{new DateTime(2024, 8, 14, 21, 42, 05)}
+Terri-Anne~Round Round~{new DateTime(2024, 8, 14, 21, 44, 07)}
+Joanna Magik~Maneater~{new DateTime(2024, 8, 14, 21, 46, 32)}
+Jen Payne & Kevin McKay~Feed Your Soul~1{new DateTime(2024, 8, 14, 21, 48, 45)}
+Kevin McKay & Eppers & Notelle~On My Own~{new DateTime(2024, 8, 14, 21, 51, 37)}
+Nader Razdar & Kevin McKay~Get Ur Freak On (Kevin McKay Extended Mix)~{new DateTime(2024, 8, 14, 21, 53, 49)}
+Philip Z~Yala (Extended Mix)~{new DateTime(2024, 8, 14, 21, 59, 40)}
+Kyle Kinch & Kevin McKay~Hella~{new DateTime(2024, 8, 14, 22, 05, 53)}
+Roze Wild~B-O-D-Y~{new DateTime(2024, 8, 14, 22, 08, 26)}
+Jey Kurmis~Snoop~{new DateTime(2024, 8, 14, 22, 11, 09)}
+Bootie Brown & Tame Impala & Gorillaz~New Gold (Dom Dolla Remix Extended)~{new DateTime(2024, 8, 14, 22, 16, 23)}
+Eli Brown & Love Regenerator~Don't You Want Me (Original Mix)~{new DateTime(2024, 8, 14, 22, 21, 23)}
+Local Singles~Voices~{new DateTime(2024, 8, 14, 22, 25, 59)}";
+
+ var profile = new Importprofile()
+ {
+ UseRegularExpression = false,
+ SchemeTracks = $"{nameof(ImportTrack.Artist)}~{nameof(ImportTrack.Title)}~{nameof(ImportTrack.StartDateTime)}"
+ };
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
+ // Act
+ var importfile = await service.AnalyseAsync(fileContent);
+ // Assert
+ Assert.IsNull(importfile.AnalyseException);
+ Assert.IsNotNull(importfile.AnalysedCuesheet);
+ Assert.AreEqual(30, importfile.AnalysedCuesheet.Tracks.Count);
+ Assert.AreEqual("Innellea", importfile.AnalysedCuesheet.Tracks.ElementAt(0).Artist);
+ Assert.AreEqual("The Golden Fort", importfile.AnalysedCuesheet.Tracks.ElementAt(0).Title);
+ Assert.AreEqual(new DateTime(2024, 8, 14, 20, 10, 48), importfile.AnalysedCuesheet.Tracks.ElementAt(0).StartDateTime);
+ Assert.AreEqual("Nora En Pure", importfile.AnalysedCuesheet.Tracks.ElementAt(1).Artist);
+ Assert.AreEqual("Diving with Whales (Daniel Portman Remix)", importfile.AnalysedCuesheet.Tracks.ElementAt(1).Title);
+ Assert.AreEqual(new DateTime(2024, 8, 14, 20, 15, 21), importfile.AnalysedCuesheet.Tracks.ElementAt(1).StartDateTime);
+ Assert.AreEqual("Local Singles", importfile.AnalysedCuesheet.Tracks.ElementAt(29).Artist);
+ Assert.AreEqual("Voices", importfile.AnalysedCuesheet.Tracks.ElementAt(29).Title);
+ Assert.AreEqual(new DateTime(2024, 8, 14, 22, 25, 59), importfile.AnalysedCuesheet.Tracks.ElementAt(29).StartDateTime);
+ }
+
+ [TestMethod()]
+ public async Task AnalyseAsync_WithCommonDataMatchingMultipleLines_SetsCommonDataOnceAsync()
+ {
+ // Arrange
+ var profile = new Importprofile()
+ {
+ UseRegularExpression = false,
+ SchemeCuesheet = "Artist - Title\tAudiofile",
+ SchemeTracks = "Artist - Title\tBegin"
+ };
+ var textImportMemoryStream = new MemoryStream(Resources.Sample_Inputfile);
+ var reader = new StreamReader(textImportMemoryStream);
+ var fileContent = reader.ReadToEnd();
+ var localStorageOptionsProviderMock = new Mock();
+ var options = new ImportOptions
+ {
+ SelectedImportProfile = profile
+ };
+ localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
+ var service = new TextImportService(localStorageOptionsProviderMock.Object);
+ // Act
+ var importfile = await service.AnalyseAsync(fileContent);
+ // Assert
+ Assert.IsNull(importfile.AnalyseException);
+ Assert.IsNotNull(importfile.AnalysedCuesheet);
+ Assert.AreEqual("CuesheetArtist", importfile.AnalysedCuesheet.Artist);
+ Assert.AreEqual("CuesheetTitle", importfile.AnalysedCuesheet.Title);
+ Assert.AreEqual("c:\\AudioFile.mp3", importfile.AnalysedCuesheet.Audiofile);
+ Assert.AreEqual(8, importfile.AnalysedCuesheet.Tracks.Count);
+ Assert.IsNotNull(importfile.FileContentRecognized);
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\AudioFile.mp3")));
+ Assert.IsTrue(importfile.FileContentRecognized.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8")));
}
}
}
\ No newline at end of file
diff --git a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs
index 76c4e24b..155ed70c 100644
--- a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs
+++ b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs
@@ -13,21 +13,13 @@
//You should have received a copy of the GNU General Public License
//along with Foobar. If not, see
//.
-using AudioCuesheetEditor.Data.Options;
using AudioCuesheetEditor.Model.AudioCuesheet;
using AudioCuesheetEditor.Model.Entity;
-using AudioCuesheetEditor.Model.IO.Import;
-using AudioCuesheetEditor.Model.Options;
-using AudioCuesheetEditor.Model.Utility;
-using AudioCuesheetEditor.Services.IO;
using AudioCuesheetEditor.Services.UI;
-using AudioCuesheetEditor.Tests.Properties;
using AudioCuesheetEditor.Tests.Utility;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
namespace AudioCuesheetEditor.Tests.Services.UI
@@ -164,115 +156,6 @@ public void TrackListTest()
Assert.IsFalse(manager.CanRedo);
}
- [TestMethod()]
- public void Import_ValidTextfile_IsUndoable()
- {
- // Arrange
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var textImportMemoryStream = new MemoryStream(Resources.Textimport_with_Cuesheetdata);
- using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = "(?'Artist'\\A.*) - (?'Title'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Cataloguenumber'.{1,})",
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions();
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- // Act
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
- // Assert
- Assert.IsFalse(traceChangeManager.CanUndo);
- Assert.IsFalse(traceChangeManager.CanRedo);
- Assert.IsNotNull(sessionStateContainer.ImportCuesheet);
- Assert.AreEqual("DJFreezeT", sessionStateContainer.ImportCuesheet.Artist);
- Assert.AreEqual("0123456789123", sessionStateContainer.ImportCuesheet.Cataloguenumber);
- Assert.AreNotEqual(0, sessionStateContainer.ImportCuesheet.Tracks.Count);
- }
-
- [TestMethod()]
- public void UndoImport_ValidTextfile_ResetsToEmptyCuesheet()
- {
- // Arrange
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var textImportMemoryStream = new MemoryStream(Resources.Textimport_with_Cuesheetdata);
- using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = "(?'Artist'\\A.*) - (?'Title'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Cataloguenumber'.{1,})",
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions();
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
- importManager.ImportCuesheet();
- // Act
- traceChangeManager.Undo();
- // Assert
- Assert.AreEqual(0, sessionStateContainer.Cuesheet.Tracks.Count);
- Assert.IsTrue(string.IsNullOrEmpty(sessionStateContainer.Cuesheet.Artist));
- Assert.IsTrue(string.IsNullOrEmpty(sessionStateContainer.Cuesheet.Cataloguenumber));
- Assert.IsFalse(traceChangeManager.CanUndo);
- Assert.IsTrue(traceChangeManager.CanRedo);
- }
-
- [TestMethod()]
- public void UndoAndRedoImport_ValidTextfile_ResetsTextfileValues()
- {
- // Arrange
- var testhelper = new TestHelper();
- var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger());
- var sessionStateContainer = new SessionStateContainer(traceChangeManager);
- var textImportMemoryStream = new MemoryStream(Resources.Textimport_with_Cuesheetdata);
- using var reader = new StreamReader(textImportMemoryStream);
- List lines = [];
- while (reader.EndOfStream == false)
- {
- lines.Add(reader.ReadLine());
- }
- var fileContent = lines.AsReadOnly();
- var localStorageOptionsProviderMock = new Mock();
- var textImportScheme = new TextImportScheme()
- {
- SchemeCuesheet = "(?'Artist'\\A.*) - (?'Title'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Cataloguenumber'.{1,})",
- SchemeTracks = TextImportScheme.DefaultSchemeTracks
- };
- var timeSpanFormat = new TimeSpanFormat();
- var options = new ApplicationOptions();
- localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options);
- var fileInputManagerMock = new Mock();
- var importManager = new ImportManager(sessionStateContainer, localStorageOptionsProviderMock.Object, traceChangeManager, fileInputManagerMock.Object);
- importManager.ImportText(fileContent, textImportScheme, timeSpanFormat);
- traceChangeManager.Undo();
- // Act
- traceChangeManager.Redo();
- // Assert
- Assert.AreEqual("DJFreezeT", sessionStateContainer.ImportCuesheet?.Artist);
- Assert.AreEqual("0123456789123", sessionStateContainer.ImportCuesheet?.Cataloguenumber);
- Assert.AreEqual(39, sessionStateContainer.ImportCuesheet?.Tracks.Count);
- }
-
[TestMethod()]
public void RemoveTracksTest()
{
diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj
index 826022e8..9e25d5a0 100644
--- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj
+++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj
@@ -7,7 +7,7 @@
enable
https://github.com/NeoCoderMatrix86/AudioCuesheetEditor
3.0
- 9.2.0
+ 10.0.0
false
true
true
@@ -20,17 +20,18 @@
+
-
-
+
+
-
-
-
-
+
+
+
+
-
+
diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs
index 2994ab3d..f0121747 100644
--- a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs
+++ b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs
@@ -31,6 +31,7 @@ public class CuesheetConstants
public static readonly String Tab = "\t";
public static readonly String CuesheetCDTextfile = "CDTEXTFILE";
public static readonly String CuesheetCatalogueNumber = "CATALOG";
- public static readonly String RecognizedMarkHTML = "{0}";
+ public static readonly String MarkHTMLStart = "";
+ public static readonly String RecognizedMarkHTML = MarkHTMLStart + "{0}" + "";
}
}
diff --git a/AudioCuesheetEditor/Model/IO/FileExtensions.cs b/AudioCuesheetEditor/Model/IO/FileExtensions.cs
index 439bf6df..980f574d 100644
--- a/AudioCuesheetEditor/Model/IO/FileExtensions.cs
+++ b/AudioCuesheetEditor/Model/IO/FileExtensions.cs
@@ -21,5 +21,6 @@ public class FileExtensions
public const string Projectfile = ".ace";
public const string Cuesheet = ".cue";
public const string CDTextfile = ".cdt";
+ public const string HTML = ".html";
}
}
diff --git a/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs b/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs
index 1dc3c20d..37483831 100644
--- a/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs
+++ b/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs
@@ -17,9 +17,9 @@ namespace AudioCuesheetEditor.Model.IO
{
public static class FileMimeTypes
{
- public const string Text = "text/plain";
+ public const string TextPlain = "text/plain";
public const string Projectfile = "application/x-ace";
public const string Cuesheet = "application/x-cue";
- public const string CDTextfile = "text/*";
+ public const string Text = "text/*";
}
}
diff --git a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs
index b99d07b0..a10f1d99 100644
--- a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs
+++ b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs
@@ -21,15 +21,15 @@ namespace AudioCuesheetEditor.Model.IO.Import
public interface IImportfile
{
///
- /// File content (each element is a file line)
+ /// File content
///
- IEnumerable? FileContent { get; set; }
+ String? FileContent { get; set; }
///
/// File content with marking which passages has been reconized by scheme
///
- IEnumerable? FileContentRecognized { get; set; }
+ String? FileContentRecognized { get; set; }
///
- /// Exception that has been thrown while readinng out the file
+ /// Exception that has been thrown while reading out the file
///
Exception? AnalyseException { get; set; }
///
diff --git a/AudioCuesheetEditor/Model/IO/Import/Importfile.cs b/AudioCuesheetEditor/Model/IO/Import/Importfile.cs
index 033e1989..c0726e8e 100644
--- a/AudioCuesheetEditor/Model/IO/Import/Importfile.cs
+++ b/AudioCuesheetEditor/Model/IO/Import/Importfile.cs
@@ -20,14 +20,14 @@ namespace AudioCuesheetEditor.Model.IO.Import
{
public class Importfile : IImportfile
{
- ///
- public IEnumerable? FileContent { get; set; }
- ///
- public IEnumerable? FileContentRecognized { get; set; }
///
public Exception? AnalyseException { get; set; }
///
public ImportCuesheet? AnalysedCuesheet { get; set; }
public ImportFileType FileType { get; set; }
+ ///
+ public string? FileContentRecognized { get; set; }
+ ///
+ public string? FileContent { get; set; }
}
}
diff --git a/AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs
similarity index 76%
rename from AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs
rename to AudioCuesheetEditor/Model/IO/Import/Importprofile.cs
index e63c3fce..b1f824c4 100644
--- a/AudioCuesheetEditor/Model/IO/Import/TextImportScheme.cs
+++ b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs
@@ -16,55 +16,26 @@
using AudioCuesheetEditor.Model.AudioCuesheet;
using AudioCuesheetEditor.Model.AudioCuesheet.Import;
using AudioCuesheetEditor.Model.Entity;
+using AudioCuesheetEditor.Model.Utility;
namespace AudioCuesheetEditor.Model.IO.Import
{
- public class TextImportScheme : Validateable
+ public class Importprofile : Validateable
{
public static readonly IEnumerable AvailableSchemeCuesheet;
public static readonly IEnumerable AvailableSchemesTrack;
- static TextImportScheme()
+ static Importprofile()
{
AvailableSchemeCuesheet = [nameof(Cuesheet.Artist), nameof(Cuesheet.Title), nameof(Cuesheet.Audiofile), 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 static readonly String DefaultSchemeCuesheet = @"(?'Artist'\w*) - (?'Title'\w*)\t{1,}(?'Audiofile'.*)";
- public static readonly String DefaultSchemeTracks = @"(?'Artist'.+?) - (?'Title'.+?)\s*\t+(?'End'.+)";
-
- public static readonly TextImportScheme DefaultTextImportScheme = new()
- {
- SchemeCuesheet = DefaultSchemeCuesheet,
- SchemeTracks = DefaultSchemeTracks
- };
-
- private string? schemeTracks;
- private string? schemeCuesheet;
-
- public event EventHandler? SchemeChanged;
-
- public String? SchemeTracks
- {
- get { return schemeTracks; }
- set
- {
- schemeTracks = value;
- SchemeChanged?.Invoke(this, nameof(SchemeTracks));
- OnValidateablePropertyChanged();
- }
- }
-
- public String? SchemeCuesheet
- {
- get { return schemeCuesheet; }
- set
- {
- schemeCuesheet = value;
- SchemeChanged?.Invoke(this, nameof(SchemeCuesheet));
- OnValidateablePropertyChanged();
- }
- }
+ public Guid Id { get; init; } = Guid.NewGuid();
+ public String? Name { get; set; }
+ public Boolean UseRegularExpression { get; set; }
+ public String? SchemeCuesheet { get; set; }
+ public String? SchemeTracks { get; set; }
+ public TimeSpanFormat? TimeSpanFormat { get; set; }
public override ValidationResult Validate(string property)
{
ValidationStatus validationStatus = ValidationStatus.NoValidation;
diff --git a/AudioCuesheetEditor/Model/IO/Projectfile.cs b/AudioCuesheetEditor/Model/IO/Projectfile.cs
index 075cd7ec..c54dace0 100644
--- a/AudioCuesheetEditor/Model/IO/Projectfile.cs
+++ b/AudioCuesheetEditor/Model/IO/Projectfile.cs
@@ -37,10 +37,9 @@ public class Projectfile(Cuesheet cuesheet)
}
};
- public static Cuesheet? ImportFile(byte[] fileContent)
+ public static Cuesheet? ImportFile(string fileContent)
{
- var json = Encoding.UTF8.GetString(fileContent);
- return JsonSerializer.Deserialize(json, Options);
+ return JsonSerializer.Deserialize(fileContent, Options);
}
public Cuesheet Cuesheet { get; private set; } = cuesheet;
diff --git a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs
index 97af692a..6773e70c 100644
--- a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs
+++ b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs
@@ -13,10 +13,6 @@
//You should have received a copy of the GNU General Public License
//along with Foobar. If not, see
//.
-using AudioCuesheetEditor.Model.Entity;
-using AudioCuesheetEditor.Model.IO;
-using AudioCuesheetEditor.Model.IO.Export;
-using AudioCuesheetEditor.Model.IO.Import;
using AudioCuesheetEditor.Model.Utility;
using AudioCuesheetEditor.Services.UI;
using System.Globalization;
@@ -24,33 +20,9 @@
namespace AudioCuesheetEditor.Model.Options
{
- public enum ViewMode
- {
- DetailView = 0,
- RecordView = 1,
- ImportView = 2
- }
- public class ApplicationOptions : Validateable, IOptions
+ public class ApplicationOptions : IOptions
{
public const LogLevel DefaultLogLevel = LogLevel.Information;
- private string? projectFilename = Projectfile.DefaultFilename;
- private string? cuesheetFilename = Exportfile.DefaultCuesheetFilename;
- public String? CuesheetFilename
- {
- get => cuesheetFilename;
- set
- {
- if (String.IsNullOrEmpty(value) == false)
- {
- var extension = Path.GetExtension(value);
- if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false)
- {
- value = $"{value}{FileExtensions.Cuesheet}";
- }
- }
- cuesheetFilename = value;
- }
- }
public String? CultureName { get; set; } = LocalizationService.DefaultCulture;
[JsonIgnore]
public CultureInfo Culture
@@ -67,102 +39,10 @@ public CultureInfo Culture
}
}
}
- [JsonIgnore]
- public ViewMode ActiveTab { get; set; }
- public String? ActiveTabName
- {
- get => Enum.GetName(ActiveTab);
- set
- {
- if (value != null)
- {
- ActiveTab = Enum.Parse(value);
- }
- else
- {
- throw new ArgumentNullException(nameof(value));
- }
- }
- }
- public String? ProjectFilename
- {
- get => projectFilename;
- set
- {
- if (String.IsNullOrEmpty(value) == false)
- {
- var extension = Path.GetExtension(value);
- if (extension?.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false)
- {
- value = $"{value}{FileExtensions.Projectfile}";
- }
- }
- projectFilename = value;
- }
- }
public TimeSpanFormat? TimeSpanFormat { get; set; }
- public Boolean LinkTracks { get; set; } = true;
- public TextImportScheme ImportScheme { get; set; } = TextImportScheme.DefaultTextImportScheme;
- public TimeSpanFormat ImportTimeSpanFormat { get; set; } = new();
- public uint RecordCountdownTimer { get; set; } = 5;
+ public Boolean DefaultIsLinkedToPreviousTrack { get; set; } = true;
public Boolean FixedTracksTableHeader { get; set; } = false;
public String? DisplayTimeSpanFormat { get; set; }
public LogLevel MinimumLogLevel { get; set; } = DefaultLogLevel;
-
- public override ValidationResult Validate(string property)
- {
- ValidationStatus validationStatus = ValidationStatus.NoValidation;
- List? validationMessages = null;
- switch (property)
- {
- case nameof(CuesheetFilename):
- validationStatus = ValidationStatus.Success;
- if (string.IsNullOrEmpty(CuesheetFilename))
- {
- validationMessages ??= [];
- validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(CuesheetFilename)));
- }
- else
- {
- var extension = Path.GetExtension(CuesheetFilename);
- if (extension.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false)
- {
- validationMessages ??= [];
- validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(CuesheetFilename), FileExtensions.Cuesheet));
- }
- var filenameWithoutExtension = Path.GetFileNameWithoutExtension(CuesheetFilename);
- if (string.IsNullOrEmpty(filenameWithoutExtension))
- {
- validationMessages ??= [];
- validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(CuesheetFilename)));
- }
- }
- break;
- case nameof(ProjectFilename):
- validationStatus = ValidationStatus.Success;
- if (String.IsNullOrEmpty(ProjectFilename))
- {
- validationMessages ??= [];
- validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(ProjectFilename)));
- }
- else
- {
- var extension = Path.GetExtension(ProjectFilename);
- if (extension.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false)
- {
- validationMessages ??= [];
- validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(ProjectFilename), FileExtensions.Projectfile));
- }
- var filename = Path.GetFileNameWithoutExtension(ProjectFilename);
- if (String.IsNullOrEmpty(filename))
- {
- validationMessages ??= [];
- validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(ProjectFilename)));
- }
- }
- break;
- }
- return ValidationResult.Create(validationStatus, validationMessages);
- }
}
}
diff --git a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs
new file mode 100644
index 00000000..b74e136c
--- /dev/null
+++ b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs
@@ -0,0 +1,114 @@
+//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.Entity;
+using AudioCuesheetEditor.Model.IO;
+using AudioCuesheetEditor.Model.IO.Export;
+
+namespace AudioCuesheetEditor.Model.Options
+{
+ public class DownloadOptions : Validateable, IOptions
+ {
+ private string? projectFilename = Projectfile.DefaultFilename;
+ private string? cuesheetFilename = Exportfile.DefaultCuesheetFilename;
+ public String? CuesheetFilename
+ {
+ get => cuesheetFilename;
+ set
+ {
+ if (String.IsNullOrEmpty(value) == false)
+ {
+ var extension = Path.GetExtension(value);
+ if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false)
+ {
+ value = $"{value}{FileExtensions.Cuesheet}";
+ }
+ }
+ cuesheetFilename = value;
+ }
+ }
+ public String? ProjectFilename
+ {
+ get => projectFilename;
+ set
+ {
+ if (String.IsNullOrEmpty(value) == false)
+ {
+ var extension = Path.GetExtension(value);
+ if (extension?.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false)
+ {
+ value = $"{value}{FileExtensions.Projectfile}";
+ }
+ }
+ projectFilename = value;
+ }
+ }
+ public override ValidationResult Validate(string property)
+ {
+ ValidationStatus validationStatus = ValidationStatus.NoValidation;
+ List? validationMessages = null;
+ switch (property)
+ {
+ case nameof(CuesheetFilename):
+ validationStatus = ValidationStatus.Success;
+ if (string.IsNullOrEmpty(CuesheetFilename))
+ {
+ validationMessages ??= [];
+ validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(CuesheetFilename)));
+ }
+ else
+ {
+ var extension = Path.GetExtension(CuesheetFilename);
+ if (extension.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false)
+ {
+ validationMessages ??= [];
+ validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(CuesheetFilename), FileExtensions.Cuesheet));
+ }
+ var filenameWithoutExtension = Path.GetFileNameWithoutExtension(CuesheetFilename);
+ if (string.IsNullOrEmpty(filenameWithoutExtension))
+ {
+ validationMessages ??= [];
+ validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(CuesheetFilename)));
+ }
+ }
+ break;
+ case nameof(ProjectFilename):
+ validationStatus = ValidationStatus.Success;
+ if (String.IsNullOrEmpty(ProjectFilename))
+ {
+ validationMessages ??= [];
+ validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(ProjectFilename)));
+ }
+ else
+ {
+ var extension = Path.GetExtension(ProjectFilename);
+ if (extension.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false)
+ {
+ validationMessages ??= [];
+ validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(ProjectFilename), FileExtensions.Projectfile));
+ }
+ var filename = Path.GetFileNameWithoutExtension(ProjectFilename);
+ if (String.IsNullOrEmpty(filename))
+ {
+ validationMessages ??= [];
+ validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(ProjectFilename)));
+ }
+ }
+ break;
+ }
+ return ValidationResult.Create(validationStatus, validationMessages);
+ }
+ }
+}
diff --git a/AudioCuesheetEditor/Model/Options/ExportOptions.cs b/AudioCuesheetEditor/Model/Options/ExportOptions.cs
index eb36939b..dfa267a2 100644
--- a/AudioCuesheetEditor/Model/Options/ExportOptions.cs
+++ b/AudioCuesheetEditor/Model/Options/ExportOptions.cs
@@ -67,7 +67,17 @@ public ExportOptions(ICollection exportProfiles, Guid? selectedPr
public Exportprofile? SelectedExportProfile
{
get => SelectedProfileId.HasValue ? ExportProfiles.FirstOrDefault(x => x.Id == SelectedProfileId) : null;
- set => SelectedProfileId = value?.Id;
+ set
+ {
+ if (ExportProfiles.Any(x => x.Id == value?.Id) == false)
+ {
+ if (value != null)
+ {
+ ExportProfiles.Add(value);
+ }
+ }
+ SelectedProfileId = value?.Id;
+ }
}
public Guid? SelectedProfileId { get; private set; }
}
diff --git a/AudioCuesheetEditor/Model/Options/ImportOptions.cs b/AudioCuesheetEditor/Model/Options/ImportOptions.cs
new file mode 100644
index 00000000..0b186b9f
--- /dev/null
+++ b/AudioCuesheetEditor/Model/Options/ImportOptions.cs
@@ -0,0 +1,75 @@
+//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.Import;
+using AudioCuesheetEditor.Model.IO.Import;
+using System.Text.Json.Serialization;
+
+namespace AudioCuesheetEditor.Model.Options
+{
+ public class ImportOptions : IOptions
+ {
+ public static readonly Importprofile DefaultSelectedImportprofile = new()
+ {
+ Name = "Textfile (common data in first line)",
+ UseRegularExpression = false,
+ SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}\t{nameof(ImportCuesheet.Audiofile)}",
+ SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}"
+ };
+
+ public static readonly ICollection DefaultImportprofiles =
+ [
+ DefaultSelectedImportprofile,
+ new()
+ {
+ Name = "Textfile (just track data)",
+ UseRegularExpression = false,
+ SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}"
+ },
+ new()
+ {
+ Name = "Textfile (track data seperated by ~)",
+ UseRegularExpression = false,
+ SchemeTracks = $"{nameof(ImportTrack.Artist)}~{nameof(ImportTrack.Title)}~{nameof(ImportTrack.StartDateTime)}"
+ },
+ new()
+ {
+ Name = "Traktor history",
+ UseRegularExpression = true,
+ SchemeTracks = @$"\s*| (?<{nameof(ImportTrack.Position)}>\d+) | \s*(?<{nameof(ImportTrack.Artist)}>.*?) | \s*(?<{nameof(ImportTrack.Title)}>.*?) | \s*(?<{nameof(ImportTrack.StartDateTime)}>.*?) | \s*
"
+ }
+ ];
+
+ [JsonInclude]
+ public Guid? SelectedImportProfileId { get; private set; } = DefaultSelectedImportprofile.Id;
+ public ICollection ImportProfiles { get; set; } = DefaultImportprofiles;
+ [JsonIgnore]
+ public Importprofile? SelectedImportProfile
+ {
+ get => SelectedImportProfileId.HasValue ? ImportProfiles.FirstOrDefault(x => x.Id == SelectedImportProfileId) : null;
+ set
+ {
+ if (ImportProfiles.Any(x => x.Id == value?.Id) == false)
+ {
+ if (value != null)
+ {
+ ImportProfiles.Add(value);
+ }
+ }
+ SelectedImportProfileId = value?.Id;
+ }
+ }
+ }
+}
diff --git a/AudioCuesheetEditor/Model/Options/RecordOptions.cs b/AudioCuesheetEditor/Model/Options/RecordOptions.cs
new file mode 100644
index 00000000..ab47a448
--- /dev/null
+++ b/AudioCuesheetEditor/Model/Options/RecordOptions.cs
@@ -0,0 +1,22 @@
+//This file is part of AudioCuesheetEditor.
+
+//AudioCuesheetEditor is free software: you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//AudioCuesheetEditor is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+
+//You should have received a copy of the GNU General Public License
+//along with Foobar. If not, see
+//.
+namespace AudioCuesheetEditor.Model.Options
+{
+ public class RecordOptions : IOptions
+ {
+ public uint RecordCountdownTimer { get; set; } = 5;
+ }
+}
diff --git a/AudioCuesheetEditor/Model/Options/ViewOptions.cs b/AudioCuesheetEditor/Model/Options/ViewOptions.cs
new file mode 100644
index 00000000..3c1389e4
--- /dev/null
+++ b/AudioCuesheetEditor/Model/Options/ViewOptions.cs
@@ -0,0 +1,46 @@
+//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 System.Text.Json.Serialization;
+
+namespace AudioCuesheetEditor.Model.Options
+{
+ public enum ViewMode
+ {
+ DetailView = 0,
+ RecordView = 1,
+ ImportView = 2
+ }
+ public class ViewOptions : IOptions
+ {
+ [JsonIgnore]
+ public ViewMode ActiveTab { get; set; }
+ public String? ActiveTabName
+ {
+ get => Enum.GetName(ActiveTab);
+ set
+ {
+ if (value != null)
+ {
+ ActiveTab = Enum.Parse(value);
+ }
+ else
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+ }
+ }
+ }
+}
diff --git a/AudioCuesheetEditor/Pages/Index.razor b/AudioCuesheetEditor/Pages/Index.razor
index c60b59d9..aaa79b27 100644
--- a/AudioCuesheetEditor/Pages/Index.razor
+++ b/AudioCuesheetEditor/Pages/Index.razor
@@ -20,36 +20,33 @@ along with Foobar. If not, see
@inherits BaseLocalizedComponent
-@inject ISessionStateContainer _sessionStateContainer
@inject IStringLocalizer _localizer
+@inject ILocalStorageOptionsProvider _localStorageOptionsProvider
-
-
+
+
-
-
-
+
-
-
-
+
-
-
-
+
-
-
+
+
@code{
+ ViewOptions? options;
+ ViewMode currentViewmode = ViewMode.DetailView;
+
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
- _sessionStateContainer.ImportCuesheetChanged += SessionStateContainer_ImportCuesheetChanged;
- _sessionStateContainer.CuesheetChanged += SessionStateContainer_CuesheetChanged;
- StateHasChanged();
+ options = await _localStorageOptionsProvider.GetOptionsAsync();
+ currentViewmode = options.ActiveTab;
+ _localStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved;
}
protected override void Dispose(bool disposing)
@@ -57,34 +54,23 @@ along with Foobar. If not, see
base.Dispose(disposing);
if (disposing)
{
- _sessionStateContainer.ImportCuesheetChanged -= SessionStateContainer_ImportCuesheetChanged;
- _sessionStateContainer.CuesheetChanged -= SessionStateContainer_CuesheetChanged;
+ _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved;
}
}
async Task ActiveTabIndexChanged(int tabIndex)
{
- var activeViewMode = (ViewMode)tabIndex;
- await LocalStorageOptionsProvider.SaveOptionsValueAsync(x => x.ActiveTab, activeViewMode);
- }
-
- void SessionStateContainer_CuesheetChanged(object? sender, EventArgs args)
- {
- StateHasChanged();
- }
-
- void SessionStateContainer_ImportCuesheetChanged(object? sender, EventArgs args)
- {
- StateHasChanged();
+ currentViewmode = (ViewMode)tabIndex;
+ await LocalStorageOptionsProvider.SaveOptionsValueAsync(x => x.ActiveTab, currentViewmode);
}
- ViewMode GetViewMode()
+ void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions option)
{
- ViewMode viewMode = ViewMode.DetailView;
- if (ApplicationOptions != null)
+ if (option is ViewOptions viewOptions)
{
- viewMode = ApplicationOptions.ActiveTab;
+ options = viewOptions;
+ currentViewmode = options.ActiveTab;
+ StateHasChanged();
}
- return viewMode;
}
}
\ No newline at end of file
diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs
index a6a022fe..8d470618 100644
--- a/AudioCuesheetEditor/Program.cs
+++ b/AudioCuesheetEditor/Program.cs
@@ -27,10 +27,8 @@
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using MudBlazor.Services;
-using System.ComponentModel.Design;
using System.Globalization;
using System.Reflection;
-using System.Reflection.Emit;
using Toolbelt.Blazor.Extensions.DependencyInjection;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
@@ -52,7 +50,7 @@
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
-builder.Services.AddScoped();
+builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
@@ -60,7 +58,7 @@
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
-builder.Services.AddScoped();
+builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
diff --git a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs
index 47ad4494..9f6af21d 100644
--- a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs
+++ b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs
@@ -16,16 +16,18 @@
using AudioCuesheetEditor.Model.AudioCuesheet;
using AudioCuesheetEditor.Model.AudioCuesheet.Import;
using AudioCuesheetEditor.Model.IO.Import;
+using System.Text;
using System.Text.RegularExpressions;
namespace AudioCuesheetEditor.Services.IO
{
public class CuesheetImportService
{
- public static IImportfile Analyse(IEnumerable fileContent)
+ public static IImportfile Analyse(string fileContent)
{
Importfile importfile = new()
{
+ FileContent = fileContent,
FileType = ImportFileType.Cuesheet
};
try
@@ -55,11 +57,9 @@ public static IImportfile Analyse(IEnumerable fileContent)
var regexCDTextfile = new Regex("^" + CuesheetConstants.CuesheetCDTextfile + " \"(?'" + cuesheetCDTextfileGroupName + "'.{0,})\"");
var regexCatalogueNumber = new Regex("^" + CuesheetConstants.CuesheetCatalogueNumber + " (?'" + cuesheetCatalogueNumberGroupName + "'.{0,})");
ImportTrack? track = null;
- List lines = [];
- List? recognizedLines = [];
- foreach (var line in fileContent)
+ StringBuilder recognizedContent = new();
+ foreach (var line in fileContent.Split(Environment.NewLine))
{
- lines.Add(line);
String? recognizedLine = line;
if (String.IsNullOrEmpty(line) == false)
{
@@ -277,10 +277,9 @@ public static IImportfile Analyse(IEnumerable fileContent)
}
}
}
- recognizedLines.Add(recognizedLine);
+ recognizedContent.AppendLine(recognizedLine);
}
- importfile.FileContent = lines.AsReadOnly();
- importfile.FileContentRecognized = recognizedLines.AsReadOnly();
+ importfile.FileContentRecognized = recognizedContent.ToString().TrimEnd(Environment.NewLine.ToCharArray());
}
catch (Exception ex)
{
diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs
index d3ef5d12..96129e13 100644
--- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs
+++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs
@@ -27,7 +27,7 @@ public class FileInputManager(IJSRuntime jsRuntime, HttpClient httpClient, ILogg
private readonly HttpClient _httpClient = httpClient;
private readonly ILogger _logger = logger;
- public static AudioCodec? GetAudioCodec(IBrowserFile browserFile)
+ public AudioCodec? GetAudioCodec(IBrowserFile browserFile)
{
AudioCodec? foundAudioCodec = null;
var extension = Path.GetExtension(browserFile.Name);
@@ -37,7 +37,7 @@ public class FileInputManager(IJSRuntime jsRuntime, HttpClient httpClient, ILogg
{
foundAudioCodec = audioCodecsFound.FirstOrDefault();
}
- else
+ if (foundAudioCodec == null)
{
// Second search with mime type or file extension
audioCodecsFound = Audiofile.AudioCodecs.Where(x => x.MimeType.Equals(browserFile.ContentType, StringComparison.OrdinalIgnoreCase) || x.FileExtension.Equals(extension, StringComparison.OrdinalIgnoreCase));
@@ -46,21 +46,35 @@ public class FileInputManager(IJSRuntime jsRuntime, HttpClient httpClient, ILogg
return foundAudioCodec;
}
- public Boolean CheckFileMimeType(IBrowserFile file, String mimeType, String fileExtension)
+ public bool IsValidAudiofile(IBrowserFile browserFile)
{
- _logger.LogDebug("CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtension: '{FileExtension}'", file.Name, file.ContentType, mimeType, fileExtension);
+ var codec = GetAudioCodec(browserFile);
+ return codec != null;
+ }
+
+ public Boolean CheckFileMimeType(IBrowserFile file, String mimeType, IEnumerable fileExtensions)
+ {
+ _logger.LogDebug("CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtensions: '{fileExtensions}'", file.Name, file.ContentType, mimeType, fileExtensions);
Boolean fileMimeTypeMatches = false;
- if ((file != null) && (String.IsNullOrEmpty(mimeType) == false) && (String.IsNullOrEmpty(fileExtension) == false))
+ if ((file != null) && (String.IsNullOrEmpty(mimeType) == false))
{
if (String.IsNullOrEmpty(file.ContentType) == false)
{
- fileMimeTypeMatches = file.ContentType.Equals(mimeType, StringComparison.CurrentCultureIgnoreCase);
+ if (mimeType.EndsWith("/*"))
+ {
+ var mainType = mimeType.Substring(0, mimeType.Length - 1);
+ fileMimeTypeMatches = file.ContentType.StartsWith(mainType, StringComparison.CurrentCultureIgnoreCase);
+ }
+ else
+ {
+ fileMimeTypeMatches = file.ContentType.Equals(mimeType, StringComparison.CurrentCultureIgnoreCase);
+ }
}
- if (fileMimeTypeMatches == false)
+ if ((fileMimeTypeMatches == false) && (fileExtensions.Any()))
{
//Try to find by file extension
var extension = Path.GetExtension(file.Name);
- fileMimeTypeMatches = extension.Equals(fileExtension, StringComparison.CurrentCultureIgnoreCase);
+ fileMimeTypeMatches = fileExtensions.Any(x => x.Equals(extension, StringComparison.CurrentCultureIgnoreCase));
}
}
return fileMimeTypeMatches;
@@ -101,7 +115,7 @@ public Boolean CheckFileMimeType(IBrowserFile file, String mimeType, String file
CDTextfile? cdTextfile = null;
if (browserFile != null)
{
- if (CheckFileMimeType(browserFile, FileMimeTypes.CDTextfile, FileExtensions.CDTextfile))
+ if (CheckFileMimeType(browserFile, FileMimeTypes.Text, [FileExtensions.CDTextfile]))
{
cdTextfile = new CDTextfile(browserFile.Name);
}
@@ -112,5 +126,11 @@ public Boolean CheckFileMimeType(IBrowserFile file, String mimeType, String file
}
return cdTextfile;
}
+
+ ///
+ public bool IsValidForImportView(IBrowserFile browserFile)
+ {
+ return CheckFileMimeType(browserFile, FileMimeTypes.Text, [FileExtensions.Text, FileExtensions.HTML]);
+ }
}
}
diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs
index 7a7326c8..6bf15fef 100644
--- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs
+++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs
@@ -22,8 +22,16 @@ namespace AudioCuesheetEditor.Services.IO
{
public interface IFileInputManager
{
- bool CheckFileMimeType(IBrowserFile file, string mimeType, string fileExtension);
+ bool IsValidAudiofile(IBrowserFile browserFile);
+ AudioCodec? GetAudioCodec(IBrowserFile browserFile);
+ bool CheckFileMimeType(IBrowserFile file, string mimeType, IEnumerable fileExtensions);
Task CreateAudiofileAsync(string? fileInputId, IBrowserFile? browserFile, Action>? afterContentStreamLoaded = null);
CDTextfile? CreateCDTextfile(IBrowserFile? browserFile);
+ ///
+ /// Checks if the file can be used for the import view
+ ///
+ ///
+ ///
+ bool IsValidForImportView(IBrowserFile browserFile);
}
}
\ No newline at end of file
diff --git a/AudioCuesheetEditor/Services/IO/ITextImportService.cs b/AudioCuesheetEditor/Services/IO/ITextImportService.cs
new file mode 100644
index 00000000..3f4f31a6
--- /dev/null
+++ b/AudioCuesheetEditor/Services/IO/ITextImportService.cs
@@ -0,0 +1,25 @@
+//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.Import;
+
+namespace AudioCuesheetEditor.Services.IO
+{
+ public interface ITextImportService
+ {
+ Task AnalyseAsync(string fileContent);
+ }
+}
\ No newline at end of file
diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs
index eef38039..bedeb330 100644
--- a/AudioCuesheetEditor/Services/IO/ImportManager.cs
+++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs
@@ -13,16 +13,14 @@
//You should have received a copy of the GNU General Public License
//along with Foobar. If not, see
//.
-using AudioCuesheetEditor.Data.Options;
using AudioCuesheetEditor.Model.AudioCuesheet;
using AudioCuesheetEditor.Model.AudioCuesheet.Import;
using AudioCuesheetEditor.Model.IO;
using AudioCuesheetEditor.Model.IO.Audio;
using AudioCuesheetEditor.Model.IO.Import;
-using AudioCuesheetEditor.Model.Options;
-using AudioCuesheetEditor.Model.Utility;
using AudioCuesheetEditor.Services.UI;
using Microsoft.AspNetCore.Components.Forms;
+using System.Diagnostics;
namespace AudioCuesheetEditor.Services.IO
{
@@ -34,73 +32,105 @@ public enum ImportFileType
Textfile,
Audiofile
}
- public class ImportManager(ISessionStateContainer sessionStateContainer, ILocalStorageOptionsProvider localStorageOptionsProvider, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager)
+ public class ImportManager(ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager, ITextImportService textImportService, ILogger logger)
{
+ private readonly ILogger _logger = logger;
private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer;
- private readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider;
private readonly ITraceChangeManager _traceChangeManager = traceChangeManager;
private readonly IFileInputManager _fileInputManager = fileInputManager;
+ private readonly ITextImportService _textImportService = textImportService;
- public async Task> ImportFilesAsync(IEnumerable files)
+ public async Task ImportFilesAsync(IEnumerable files)
{
- Dictionary importFileTypes = [];
+ var stopwatch = Stopwatch.StartNew();
foreach (var file in files)
{
- if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Projectfile, FileExtensions.Projectfile))
+ if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]))
{
- //TODO: can not be undone
var fileContent = await ReadFileContentAsync(file);
- var cuesheet = Projectfile.ImportFile(fileContent.ToArray());
- if (cuesheet != null)
+ fileContent.Position = 0;
+ using var reader = new StreamReader(fileContent);
+ var stringFileContent = reader.ReadToEnd();
+ _sessionStateContainer.Importfile = new Importfile()
{
- _sessionStateContainer.Cuesheet = cuesheet;
- }
- importFileTypes.Add(file, ImportFileType.ProjectFile);
+ FileContent = stringFileContent,
+ FileContentRecognized = stringFileContent,
+ FileType = ImportFileType.ProjectFile
+ };
}
- if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Cuesheet, FileExtensions.Cuesheet))
+ if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]))
{
var fileContent = await ReadFileContentAsync(file);
fileContent.Position = 0;
using var reader = new StreamReader(fileContent);
- List lines = [];
- while (reader.EndOfStream == false)
+ var stringFileContent = reader.ReadToEnd();
+ _sessionStateContainer.Importfile = new Importfile()
{
- lines.Add(reader.ReadLine());
- }
- ImportCuesheet(lines);
- importFileTypes.Add(file, ImportFileType.Cuesheet);
+ FileContent = stringFileContent,
+ FileContentRecognized = stringFileContent,
+ FileType = ImportFileType.Cuesheet
+ };
}
- if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Text, FileExtensions.Text))
+ if (_fileInputManager.IsValidForImportView(file))
{
var fileContent = await ReadFileContentAsync(file);
fileContent.Position = 0;
using var reader = new StreamReader(fileContent);
- List lines = [];
- while (reader.EndOfStream == false)
+ var stringFileContent = reader.ReadToEnd();
+ _sessionStateContainer.Importfile = new Importfile()
{
- lines.Add(reader.ReadLine());
- }
- var options = await _localStorageOptionsProvider.GetOptionsAsync();
- ImportText([.. lines], options.ImportScheme, options.ImportTimeSpanFormat);
- importFileTypes.Add(file, ImportFileType.Textfile);
+ FileContent = stringFileContent,
+ FileContentRecognized = stringFileContent,
+ FileType = ImportFileType.Textfile
+ };
}
}
- return importFileTypes;
+ stopwatch.Stop();
+ _logger.LogDebug("ImportFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed);
}
- public void ImportText(IEnumerable fileContent, TextImportScheme textImportScheme, TimeSpanFormat timeSpanFormat)
+ public async Task AnalyseImportfile()
{
- _sessionStateContainer.Importfile = TextImportService.Analyse(textImportScheme, fileContent, timeSpanFormat);
- if (_sessionStateContainer.Importfile.AnalysedCuesheet != null)
+ var stopwatch = Stopwatch.StartNew();
+ var fileContent = _sessionStateContainer.Importfile?.FileContent;
+ if (String.IsNullOrEmpty(fileContent) == false)
{
- var importCuesheet = new Cuesheet();
- CopyCuesheet(importCuesheet, _sessionStateContainer.Importfile.AnalysedCuesheet);
- _sessionStateContainer.ImportCuesheet = importCuesheet;
+ switch (_sessionStateContainer.Importfile?.FileType)
+ {
+ case ImportFileType.ProjectFile:
+ _sessionStateContainer.Cuesheet = Projectfile.ImportFile(fileContent)!;
+ break;
+ case ImportFileType.Textfile:
+ _sessionStateContainer.Importfile = await _textImportService.AnalyseAsync(fileContent);
+ break;
+ case ImportFileType.Cuesheet:
+ _sessionStateContainer.Importfile = CuesheetImportService.Analyse(fileContent);
+ break;
+ }
}
+ if (_sessionStateContainer.Importfile?.AnalysedCuesheet != null)
+ {
+ switch (_sessionStateContainer.Importfile?.FileType)
+ {
+ case ImportFileType.Textfile:
+ var importCuesheet = new Cuesheet();
+ CopyCuesheet(importCuesheet, _sessionStateContainer.Importfile.AnalysedCuesheet);
+ _sessionStateContainer.ImportCuesheet = importCuesheet;
+ break;
+ case ImportFileType.Cuesheet:
+ _traceChangeManager.BulkEdit = true;
+ CopyCuesheet(_sessionStateContainer.Cuesheet, _sessionStateContainer.Importfile.AnalysedCuesheet);
+ _traceChangeManager.BulkEdit = false;
+ break;
+ }
+ }
+ stopwatch.Stop();
+ _logger.LogDebug("ImportTextAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed);
}
public void ImportCuesheet()
{
+ var stopwatch = Stopwatch.StartNew();
if (_sessionStateContainer.ImportCuesheet != null)
{
_traceChangeManager.BulkEdit = true;
@@ -108,18 +138,10 @@ public void ImportCuesheet()
_traceChangeManager.BulkEdit = false;
}
_sessionStateContainer.ResetImport();
+ stopwatch.Stop();
+ _logger.LogDebug("ImportCuesheet duration: {stopwatch.Elapsed}", stopwatch.Elapsed);
}
- private void ImportCuesheet(IEnumerable fileContent)
- {
- _sessionStateContainer.Importfile = CuesheetImportService.Analyse(fileContent);
- if (_sessionStateContainer.Importfile.AnalysedCuesheet != null)
- {
- _traceChangeManager.BulkEdit = true;
- CopyCuesheet(_sessionStateContainer.Cuesheet, _sessionStateContainer.Importfile.AnalysedCuesheet);
- _traceChangeManager.BulkEdit = false;
- }
- }
private static async Task ReadFileContentAsync(IBrowserFile file)
{
var fileContent = new MemoryStream();
diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs
index 5d46e3c4..c1ff815e 100644
--- a/AudioCuesheetEditor/Services/IO/TextImportService.cs
+++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs
@@ -14,120 +14,184 @@
//along with Foobar. If not, see
//.
+using AudioCuesheetEditor.Data.Options;
using AudioCuesheetEditor.Model.AudioCuesheet;
using AudioCuesheetEditor.Model.AudioCuesheet.Import;
using AudioCuesheetEditor.Model.IO.Audio;
using AudioCuesheetEditor.Model.IO.Import;
+using AudioCuesheetEditor.Model.Options;
using AudioCuesheetEditor.Model.Utility;
using System.Reflection;
+using System.Text;
using System.Text.RegularExpressions;
namespace AudioCuesheetEditor.Services.IO
{
- public class TextImportService
+ public class TextImportService(ILocalStorageOptionsProvider localStorageOptionsProvider) : ITextImportService
{
- public static IImportfile Analyse(TextImportScheme textImportScheme, IEnumerable fileContent, TimeSpanFormat? timeSpanFormat = null)
+ private readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider;
+
+ public async Task AnalyseAsync(string fileContent)
{
Importfile importfile = new()
{
+ FileContent = fileContent,
+ FileContentRecognized = fileContent,
+ AnalysedCuesheet = new ImportCuesheet(),
FileType = ImportFileType.Textfile
};
try
{
- importfile.FileContent = fileContent;
- importfile.AnalysedCuesheet = new ImportCuesheet();
- Boolean cuesheetRecognized = false;
- List recognizedFileContent = [];
- Regex? regExCuesheet = null, regExTracks = null;
- if (String.IsNullOrEmpty(textImportScheme.SchemeCuesheet) == false)
+ var options = await _localStorageOptionsProvider.GetOptionsAsync();
+ var importprofile = options.SelectedImportProfile ?? throw new InvalidOperationException("Selected import profiles is not set!");
+ SearchForCuesheetData(ref importfile, fileContent, importprofile);
+ SearchForTrackData(ref importfile, fileContent, importprofile);
+ }
+ catch (Exception ex)
+ {
+ importfile.FileContentRecognized = fileContent;
+ importfile.AnalyseException = ex;
+ importfile.AnalysedCuesheet = null;
+ }
+ return importfile;
+ }
+
+ private static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, TimeSpanFormat? timeSpanFormat)
+ {
+ return regex.Replace(input, match =>
+ {
+ string result = match.Value;
+ var groupInfos = new List<(int RelIndex, int Length, string Value, string Key)>();
+ for (int matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++)
+ {
+ var group = match.Groups[matchCounter];
+ var key = regex.GroupNameFromNumber(matchCounter);
+ if (!string.IsNullOrEmpty(key) && key != matchCounter.ToString())
+ {
+ var property = entity.GetType().GetProperty(key, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (property != null)
+ {
+ SetValue(entity, property, group.Value, timeSpanFormat);
+ }
+ int relIndex = group.Index - match.Index;
+ groupInfos.Add((relIndex, group.Length, group.Value, key));
+ }
+ }
+ if (groupInfos.Count == 0)
+ {
+ return result;
+ }
+ groupInfos.Sort((a, b) => b.RelIndex.CompareTo(a.RelIndex));
+ var sb = new StringBuilder(result);
+ foreach (var (RelIndex, Length, Value, Key) in groupInfos)
+ {
+ sb.Remove(RelIndex, Length);
+ sb.Insert(RelIndex, string.Format(CuesheetConstants.RecognizedMarkHTML, Value));
+ }
+ return sb.ToString();
+ });
+ }
+
+ private static void SearchForCuesheetData(ref Importfile importfile, string fileContent, Importprofile importprofile)
+ {
+ if (string.IsNullOrWhiteSpace(importprofile.SchemeCuesheet) == false)
+ {
+ var cuesheet = importfile.AnalysedCuesheet;
+ Regex regex;
+ if (importprofile.UseRegularExpression == true)
{
- regExCuesheet = CreateCuesheetRegexPattern(textImportScheme.SchemeCuesheet);
+ regex = new Regex(importprofile.SchemeCuesheet, RegexOptions.Multiline);
}
- if (String.IsNullOrEmpty(textImportScheme.SchemeTracks) == false)
+ else
{
- regExTracks = CreateTrackRegexPattern(textImportScheme.SchemeTracks);
+ regex = CreateCuesheetRegexPattern(importprofile.SchemeCuesheet);
}
- foreach (var line in fileContent)
+
+ if (importprofile.UseRegularExpression)
{
- var recognizedLine = line;
- if (String.IsNullOrEmpty(line) == false)
+ importfile.FileContentRecognized = ApplyRegexAndMarkGroups(cuesheet!, regex, fileContent, importprofile.TimeSpanFormat);
+ }
+ else
+ {
+ var sb = new StringBuilder();
+ using (var reader = new StringReader(fileContent))
{
- Boolean recognized = false;
- if ((recognized == false) && (cuesheetRecognized == false) && (regExCuesheet != null))
- {
- recognizedLine = AnalyseLine(line, importfile.AnalysedCuesheet, regExCuesheet, timeSpanFormat);
- recognized = recognizedLine != null;
- cuesheetRecognized = recognizedLine != null;
- }
- if ((recognized == false) && (regExTracks != null))
+ string? line;
+ while ((line = reader.ReadLine()) != null)
{
- var track = new ImportTrack();
- recognizedLine = AnalyseLine(line, track, regExTracks, timeSpanFormat);
- recognized = recognizedLine != null;
- importfile.AnalysedCuesheet.Tracks.Add(track);
+ var markedLine = ApplyRegexAndMarkGroups(cuesheet!, regex, line, importprofile.TimeSpanFormat);
+ sb.AppendLine(markedLine);
+ if (!string.Equals(markedLine, line))
+ {
+ //We found the first occurence, break the loop
+ //Attach the rest of the file to FileContentRecognized
+ sb.Append(reader.ReadToEnd());
+ break;
+ }
}
}
- recognizedFileContent.Add(recognizedLine);
- }
- if (recognizedFileContent.Count > 0)
- {
- importfile.FileContentRecognized = recognizedFileContent.AsReadOnly();
+ importfile.FileContentRecognized = sb.ToString();
}
}
- catch (Exception ex)
- {
- importfile.FileContent = fileContent;
- importfile.FileContentRecognized = fileContent;
- importfile.AnalyseException = ex;
- importfile.AnalysedCuesheet = null;
- }
- return importfile;
}
- private static String? AnalyseLine(String line, object entity, Regex regex, TimeSpanFormat? timeSpanFormat)
+ private static void SearchForTrackData(ref Importfile importfile, string fileContent, Importprofile importprofile)
{
- String? recognized = null;
- string? recognizedLine = line;
- if (String.IsNullOrEmpty(line) == false)
+ if (string.IsNullOrWhiteSpace(importprofile.SchemeTracks) == false)
{
- var match = regex.Match(line);
- if (match.Success)
+ Regex regex;
+ if (importprofile.UseRegularExpression == true)
+ {
+ regex = new Regex(importprofile.SchemeTracks, RegexOptions.Multiline);
+ }
+ else
+ {
+ regex = CreateTrackRegexPattern(importprofile.SchemeTracks);
+ }
+
+ var cuesheet = importfile.AnalysedCuesheet;
+ importfile.FileContentRecognized ??= fileContent;
+ if (importprofile.UseRegularExpression)
+ {
+
+ importfile.FileContentRecognized = regex.Replace(importfile.FileContentRecognized,
+ match =>
+ {
+ var track = new ImportTrack();
+ string marked = ApplyRegexAndMarkGroups(track, regex, match.Value, importprofile.TimeSpanFormat);
+ cuesheet!.Tracks.Add(track);
+ return marked;
+ }
+ );
+ }
+ else
{
- for (int groupCounter = 1; groupCounter < match.Groups.Count; groupCounter++)
+ var sb = new StringBuilder();
+ using (var reader = new StringReader(importfile.FileContentRecognized))
{
- var key = match.Groups.Keys.ElementAt(groupCounter);
- var group = match.Groups.GetValueOrDefault(key);
- if ((group != null) && (group.Success))
+ string? line;
+ while ((line = reader.ReadLine()) != null)
{
- var property = entity.GetType().GetProperty(key, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- if (property != null)
+ // Check if this line is already analyzed
+ if (line.Contains(CuesheetConstants.MarkHTMLStart) == false)
{
- SetValue(entity, property, group.Value, timeSpanFormat);
- recognizedLine = string.Concat(recognizedLine.AsSpan(0, group.Index + (13 * (groupCounter - 1)))
- , String.Format(CuesheetConstants.RecognizedMarkHTML, group.Value)
- , recognizedLine.AsSpan(group.Index + (13 * (groupCounter - 1)) + group.Length));
+ var track = new ImportTrack();
+ var markedLine = ApplyRegexAndMarkGroups(track, regex, line, importprofile.TimeSpanFormat);
+ if (!string.Equals(markedLine, line))
+ {
+ cuesheet!.Tracks.Add(track);
+ }
+ sb.AppendLine(markedLine);
}
else
{
- throw new NullReferenceException(String.Format("Property '{0}' was not found for line content {1}", key, line));
+ sb.AppendLine(line);
}
}
- else
- {
- throw new NullReferenceException(String.Format("Group '{0}' could not be found!", key));
- }
- }
- if (recognizedLine.Contains(CuesheetConstants.RecognizedMarkHTML.Substring(0, CuesheetConstants.RecognizedMarkHTML.IndexOf("{0}"))))
- {
- recognized = recognizedLine;
}
- }
- else
- {
- recognized = line;
+ importfile.FileContentRecognized = sb.ToString().TrimEnd(Environment.NewLine.ToCharArray());
}
}
- return recognized;
}
private static void SetValue(object entity, PropertyInfo property, string value, TimeSpanFormat? timeSpanFormat)
@@ -163,57 +227,135 @@ private static void SetValue(object entity, PropertyInfo property, string value,
private static Regex CreateCuesheetRegexPattern(string scheme)
{
- var regex = new Regex(scheme);
- var groupNames = regex.GetGroupNames();
- //GroupNames always has a group "0", so we count for more than one group
- if (groupNames.Any(x => x != "0"))
+ string[] fieldNames =
+ [
+ nameof(ImportCuesheet.Artist),
+ nameof(ImportCuesheet.Title),
+ nameof(ImportCuesheet.Audiofile),
+ nameof(ImportCuesheet.CDTextfile),
+ nameof(ImportCuesheet.Cataloguenumber)
+ ];
+ var parts = new List();
+ int idx = 0;
+ while (idx < scheme.Length)
{
- return regex;
+ var field = fieldNames.FirstOrDefault(fn => scheme.IndexOf(fn, idx, StringComparison.Ordinal) == idx);
+ if (field != null)
+ {
+ parts.Add(field);
+ idx += field.Length;
+ }
+ else
+ {
+ int nextFieldIdx = scheme.Length;
+ foreach (var fn in fieldNames)
+ {
+ int pos = scheme.IndexOf(fn, idx, StringComparison.Ordinal);
+ if (pos >= 0 && pos < nextFieldIdx)
+ {
+ nextFieldIdx = pos;
+ }
+ }
+ string separator = scheme.Substring(idx, nextFieldIdx - idx);
+ parts.Add(separator);
+ idx = nextFieldIdx;
+ }
}
- else
- {
- var regexString = Regex.Escape(scheme);
- regexString = regexString.Replace(nameof(Cuesheet.Artist), $"(?<{nameof(Cuesheet.Artist)}>.+)");
- regexString = regexString.Replace(nameof(Cuesheet.Title), $"(?<{nameof(Cuesheet.Title)}>.+)");
- regexString = regexString.Replace(nameof(Cuesheet.Audiofile), $"(?<{nameof(Cuesheet.Audiofile)}>.+)");
- regexString = regexString.Replace(nameof(Cuesheet.CDTextfile), $"(?<{nameof(Cuesheet.CDTextfile)}>.+)");
- regexString = regexString.Replace(nameof(Cuesheet.Cataloguenumber), $"(?<{nameof(Cuesheet.Cataloguenumber)}>.+)");
- //Replace tab with non matching group
- regexString = regexString.Replace("\\t", "(?:...\\t)");
-
- return new Regex(regexString);
+ var regexBuilder = new StringBuilder("^");
+ for (int i = 0; i < parts.Count; i++)
+ {
+ var part = parts[i];
+ if (fieldNames.Contains(part))
+ {
+ bool isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p));
+ if (isLast)
+ {
+ regexBuilder.Append($@"(?<{part}>.+)");
+ }
+ else
+ {
+ regexBuilder.Append($@"(?<{part}>.+?)");
+ }
+ }
+ else
+ {
+ string sep = Regex.Escape(part).Replace("\\t", @"\t{1,}");
+ regexBuilder.Append(sep);
+ }
}
+ regexBuilder.Append('$');
+
+ return new Regex(regexBuilder.ToString());
}
private static Regex CreateTrackRegexPattern(string scheme)
{
- var regex = new Regex(scheme);
- var groupNames = regex.GetGroupNames();
- //GroupNames always has a group "0", so we count for more than one group
- if (groupNames.Any(x => x != "0"))
+ string[] fieldNames =
+ [
+ nameof(ImportTrack.Artist),
+ nameof(ImportTrack.Title),
+ nameof(ImportTrack.Begin),
+ nameof(ImportTrack.End),
+ nameof(ImportTrack.Length),
+ nameof(ImportTrack.Position),
+ nameof(ImportTrack.Flags),
+ nameof(ImportTrack.PreGap),
+ nameof(ImportTrack.PostGap),
+ nameof(ImportTrack.StartDateTime)
+ ];
+ var parts = new List();
+ int idx = 0;
+ while (idx < scheme.Length)
{
- return regex;
+ var field = fieldNames.FirstOrDefault(fn => scheme.IndexOf(fn, idx, StringComparison.Ordinal) == idx);
+ if (field != null)
+ {
+ parts.Add(field);
+ idx += field.Length;
+ }
+ else
+ {
+ int nextFieldIdx = scheme.Length;
+ foreach (var fn in fieldNames)
+ {
+ int pos = scheme.IndexOf(fn, idx, StringComparison.Ordinal);
+ if (pos >= 0 && pos < nextFieldIdx)
+ {
+ nextFieldIdx = pos;
+ }
+ }
+ string separator = scheme.Substring(idx, nextFieldIdx - idx);
+ parts.Add(separator);
+ idx = nextFieldIdx;
+ }
}
- else
- {
- var regexString = Regex.Escape(scheme);
-
- regexString = regexString.Replace(nameof(ImportTrack.Artist), $"(?<{nameof(ImportTrack.Artist)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.Title), $"(?<{nameof(ImportTrack.Title)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.Begin), $"(?<{nameof(ImportTrack.Begin)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.End), $"(?<{nameof(ImportTrack.End)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.Length), $"(?<{nameof(ImportTrack.Length)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.Position), $"(?<{nameof(ImportTrack.Position)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.Flags), $"(?<{nameof(ImportTrack.Flags)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.PreGap), $"(?<{nameof(ImportTrack.PreGap)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.PostGap), $"(?<{nameof(ImportTrack.PostGap)}>.+)");
- regexString = regexString.Replace(nameof(ImportTrack.StartDateTime), $"(?<{nameof(ImportTrack.StartDateTime)}>.+)");
- //Replace tab with non matching group
- regexString = regexString.Replace("\\t", "(?:...\\t)");
-
- return new Regex(regexString);
+
+ var regexBuilder = new StringBuilder("^");
+ for (int i = 0; i < parts.Count; i++)
+ {
+ var part = parts[i];
+ if (fieldNames.Contains(part))
+ {
+ bool isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p));
+ if (isLast)
+ {
+ regexBuilder.Append($@"(?<{part}>.+)");
+ }
+ else
+ {
+ regexBuilder.Append($@"(?<{part}>.+?)");
+ }
+ }
+ else
+ {
+ string sep = Regex.Escape(part).Replace("\\t", @"\t{1,}");
+ regexBuilder.Append(sep);
+ }
}
+ regexBuilder.Append('$');
+
+ return new Regex(regexBuilder.ToString());
}
}
}
diff --git a/AudioCuesheetEditor/Services/UI/EditTrackModalManager.cs b/AudioCuesheetEditor/Services/UI/DialogManager.cs
similarity index 94%
rename from AudioCuesheetEditor/Services/UI/EditTrackModalManager.cs
rename to AudioCuesheetEditor/Services/UI/DialogManager.cs
index 3320eeb1..cf10997f 100644
--- a/AudioCuesheetEditor/Services/UI/EditTrackModalManager.cs
+++ b/AudioCuesheetEditor/Services/UI/DialogManager.cs
@@ -20,13 +20,16 @@
namespace AudioCuesheetEditor.Services.UI
{
- public class EditTrackModalManager(IDialogService dialogService, ITraceChangeManager traceChangeManager)
+ public class DialogManager(IDialogService dialogService, ITraceChangeManager traceChangeManager)
{
private readonly IDialogService _dialogService = dialogService;
private readonly ITraceChangeManager _traceChangeManager = traceChangeManager;
+ private IDialogReference? loadingDialog;
+
public async Task ShowAndHandleModalEditDialogAsync(IEnumerable