Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Playwright.MSTest.v4" Version="1.63.0" />
<PackageReference Include="MSTest" Version="4.5.1" />
<PackageReference Include="Microsoft.Playwright.MSTest.v4" />
<PackageReference Include="MSTest" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task TestInitializeAsync()
TestPage = Page;
}
await _testContextInstance.ClearCookiesAsync();
await _testContextInstance.Tracing.StartAsync(new()
_ = await _testContextInstance.Tracing.StartAsync(new()
{
Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
Screenshots = true,
Expand Down
6 changes: 3 additions & 3 deletions AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Moq" Version="4.21.0" />
<PackageReference Include="coverlet.collector" Version="10.1.0">
<PackageReference Include="Moq" />
<PackageReference Include="coverlet.collector">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MSTest" Version="4.5.1" />
<PackageReference Include="MSTest" />
</ItemGroup>

<ItemGroup>
Expand Down
20 changes: 10 additions & 10 deletions AudioCuesheetEditor/AudioCuesheetEditor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="HtmlSanitizer" Version="9.2.1039" />
<PackageReference Include="MetaBrainz.MusicBrainz" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.13" PrivateAssets="all" />
<PackageReference Include="BlazorDownloadFile" Version="2.4.0.2" />
<PackageReference Include="Markdig" Version="1.4.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.13" />
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="10.0.13" />
<PackageReference Include="MudBlazor" Version="9.11.0" />
<PackageReference Include="Toolbelt.Blazor.HotKeys2" Version="6.2.1" />
<PackageReference Include="HtmlSanitizer" />
<PackageReference Include="MetaBrainz.MusicBrainz" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" PrivateAssets="all" />
<PackageReference Include="BlazorDownloadFile" />
<PackageReference Include="Markdig" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" />
<PackageReference Include="MudBlazor" />
<PackageReference Include="Toolbelt.Blazor.HotKeys2" />
</ItemGroup>

<ItemGroup>
Expand Down
12 changes: 11 additions & 1 deletion AudioCuesheetEditor/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
builder.Services.AddBlazorDownloadFile();

builder.Services.AddScoped<ILocalStorageOptionsProvider, LocalStorageOptionsProvider>();
builder.Services.AddScoped<ILocalStorageMigration, LocalStorageMigrationV1>();
builder.Services.AddScoped<LocalStorageMigrationService>();
builder.Services.AddScoped<MusicBrainzDataProvider>();
builder.Services.AddScoped<ISessionStateContainer, SessionStateContainer>();
builder.Services.AddScoped<ITraceChangeManager, TraceChangeManager>();
Expand Down Expand Up @@ -70,6 +72,14 @@

var host = builder.Build();

// Run migrations
using (var scope = host.Services.CreateScope())
{
var migrationService = scope.ServiceProvider.GetRequiredService<LocalStorageMigrationService>();

await migrationService.ApplyMigrationsAsync();
}

await host.SetCultureFromConfigurationAsync();
await host.InitializeSessionStateContainer();
await host.RunAsync();
await host.RunAsync();
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Globalization;
using Microsoft.JSInterop;

namespace AudioCuesheetEditor.Services.Options;

public class LocalStorageMigrationService(IJSRuntime jsRuntime, IEnumerable<ILocalStorageMigration> migrations)
{
readonly IJSRuntime _jsRuntime = jsRuntime;
readonly IEnumerable<ILocalStorageMigration> _migrations = migrations;
const string _versionKey = "OptionsMigrationVersion";

public async Task ApplyMigrationsAsync()
{
var storedVersion = await _jsRuntime.InvokeAsync<string?>("AppSettings.get", _versionKey);
var currentVersion = int.TryParse(storedVersion, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedVersion) ? parsedVersion : 0;
foreach (var migration in _migrations.OrderBy(x => x.Version))
{
if (migration.Version <= currentVersion)
{
continue;
}

await migration.ApplyAsync();

await _jsRuntime.InvokeVoidAsync("AppSettings.set", _versionKey, migration.Version.ToString(CultureInfo.InvariantCulture));

currentVersion = migration.Version;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace AudioCuesheetEditor.Services.Options;

/// <summary>
/// Interface for local storage migrations
/// </summary>
public interface ILocalStorageMigration
{
/// <summary>
/// Version of this migration (used for ordering updates)
/// </summary>
int Version { get; }
/// <summary>
/// Apply updates from this migration
/// </summary>
/// <returns></returns>
Task ApplyAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using Microsoft.JSInterop;

namespace AudioCuesheetEditor.Services.Options;

/// <inheritdoc/>
public class LocalStorageMigrationV1(IJSRuntime jsRuntime) : ILocalStorageMigration
{
readonly IJSRuntime _jsRuntime = jsRuntime;
/// <inheritdoc/>
public int Version => 1;

/// <inheritdoc/>
public async Task ApplyAsync()
{
await MigrateKeyAsync("ExportOptions", value => value.Replace("%Track.End%", "%Track.Finish%", StringComparison.Ordinal));
await MigrateKeyAsync("ImportOptions", value => Regex.Replace(value, @"\bEnd\b", "Finish"));
}

async Task MigrateKeyAsync(string key, Func<string, string> replace)
{
var storedJson = await _jsRuntime.InvokeAsync<string>("AppSettings.get", key);
if (string.IsNullOrWhiteSpace(storedJson))
{
return;
}
var root = JsonNode.Parse(storedJson);
if (root is null)
{
return;
}

if (ReplaceSchemeTracks(root, replace))
{
await _jsRuntime.InvokeVoidAsync("AppSettings.set", key, root.ToJsonString());
}
}

static bool ReplaceSchemeTracks(JsonNode node, Func<string, string> replace)
{
var changed = false;

if (node is JsonObject jsonObject)
{
foreach (var property in jsonObject.ToList())
{
if (property.Key == "SchemeTracks"
&& property.Value is JsonValue jsonValue
&& jsonValue.TryGetValue<string>(out var oldValue)
&& oldValue is not null)
{
var newValue = replace(oldValue);

if (newValue != oldValue)
{
jsonObject[property.Key] = newValue;
changed = true;
}
}
else
{
changed |= ReplaceSchemeTracks(property.Value, replace);
}
}
}
else if (node is JsonArray jsonArray)
{
foreach (var item in jsonArray)
{
changed |= ReplaceSchemeTracks(item, replace);
}
}

return changed;
}
}
22 changes: 22 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="HtmlSanitizer" Version="11.0.26" />
<PackageVersion Include="MetaBrainz.MusicBrainz" Version="8.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.15" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.15" />
<PackageVersion Include="BlazorDownloadFile" Version="2.4.0.2" />
<PackageVersion Include="Markdig" Version="1.6.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.15" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="10.0.15" />
<PackageVersion Include="MudBlazor" Version="9.12.0" />
<PackageVersion Include="Toolbelt.Blazor.HotKeys2" Version="6.2.1" />
<PackageVersion Include="Microsoft.Playwright.MSTest.v4" Version="1.64.1" />
<PackageVersion Include="MSTest" Version="4.5.3" />
<PackageVersion Include="Moq" Version="4.21.0" />
<PackageVersion Include="coverlet.collector" Version="10.1.0" />
</ItemGroup>
</Project>
Loading