Checkpoint web-player design-system refactor and backend track genre tagging
Advances the ongoing token/componentization cleanup (anchored player dock, border-based panels instead of floating shadows, corrected light-mode accent/gradient tokens) alongside in-progress backend support for track genre tags.
This commit is contained in:
@@ -48,5 +48,7 @@ namespace Musify.Domain.Entities
|
||||
public ICollection<AlbumHasTrack> AlbumTracks { get; set; } = new List<AlbumHasTrack>();
|
||||
|
||||
public ICollection<ListeningHistory> ListeningHistories { get; set; } = new List<ListeningHistory>();
|
||||
|
||||
public ICollection<TrackTag> Tags { get; set; } = new List<TrackTag>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Musify.Domain.ValueObjects;
|
||||
|
||||
namespace Musify.Domain.Entities
|
||||
{
|
||||
#pragma warning disable CS8618
|
||||
public class TrackTag
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
public required Guid TrackId { get; set; }
|
||||
|
||||
[Required]
|
||||
public required Genre Tag { get; set; }
|
||||
|
||||
[ForeignKey(nameof(TrackId))]
|
||||
public Track Track { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Musify.Domain.ValueObjects
|
||||
{
|
||||
public enum Genre
|
||||
{
|
||||
Pop = 0,
|
||||
Rock = 1,
|
||||
HipHop = 2,
|
||||
RnB = 3,
|
||||
Jazz = 4,
|
||||
Blues = 5,
|
||||
Classical = 6,
|
||||
Electronic = 7,
|
||||
House = 8,
|
||||
Techno = 9,
|
||||
Trance = 10,
|
||||
Dubstep = 11,
|
||||
DrumAndBass = 12,
|
||||
Metal = 13,
|
||||
Punk = 14,
|
||||
Reggae = 15,
|
||||
Reggaeton = 16,
|
||||
Country = 17,
|
||||
Folk = 18,
|
||||
Indie = 19,
|
||||
KPop = 20,
|
||||
Latin = 21,
|
||||
Soul = 22,
|
||||
Funk = 23,
|
||||
Ambient = 24,
|
||||
Lofi = 25
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace Musify.Domain.ValueObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Encodes which genre pairs are mutually exclusive on a single track (e.g. a track cannot
|
||||
/// be tagged as both Classical and Metal at the same time).
|
||||
/// </summary>
|
||||
public static class GenreCompatibility
|
||||
{
|
||||
private static readonly HashSet<(Genre, Genre)> IncompatiblePairs = BuildIncompatiblePairs();
|
||||
|
||||
private static HashSet<(Genre, Genre)> BuildIncompatiblePairs()
|
||||
{
|
||||
var pairs = new HashSet<(Genre, Genre)>();
|
||||
|
||||
void Add(Genre a, Genre b)
|
||||
{
|
||||
pairs.Add((a, b));
|
||||
pairs.Add((b, a));
|
||||
}
|
||||
|
||||
var intense = new[] { Genre.Metal, Genre.Punk, Genre.Dubstep, Genre.DrumAndBass };
|
||||
var mellow = new[] { Genre.Classical, Genre.Ambient, Genre.Lofi };
|
||||
|
||||
foreach (var intenseGenre in intense)
|
||||
foreach (var mellowGenre in mellow)
|
||||
Add(intenseGenre, mellowGenre);
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
public static bool AreCompatible(Genre a, Genre b) =>
|
||||
a == b || !IncompatiblePairs.Contains((a, b));
|
||||
|
||||
/// <summary>
|
||||
/// Returns every mutually exclusive genre pair found within the given set of tags.
|
||||
/// </summary>
|
||||
public static IReadOnlyCollection<(Genre First, Genre Second)> FindConflicts(IEnumerable<Genre> tags)
|
||||
{
|
||||
var distinctTags = tags.Distinct().ToList();
|
||||
var conflicts = new List<(Genre, Genre)>();
|
||||
|
||||
for (var i = 0; i < distinctTags.Count; i++)
|
||||
{
|
||||
for (var j = i + 1; j < distinctTags.Count; j++)
|
||||
{
|
||||
if (!AreCompatible(distinctTags[i], distinctTags[j]))
|
||||
conflicts.Add((distinctTags[i], distinctTags[j]));
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user