Change editor rule

This commit is contained in:
2026-09-24 13:24:43 +02:00
parent 16478678b5
commit 73e37dbecd
401 changed files with 14735 additions and 12995 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ generated_code = true
[*.cs]
indent_size = 4
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_namespace_declarations = block_scoped:warning
csharp_using_directive_placement = outside_namespace:warning
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
+1 -1
View File
@@ -19,7 +19,7 @@ dotnet format Musify.slnx --verify-no-changes
## Style
- File-scoped namespaces, usings outside the namespace and sorted (`.editorconfig` enforces it).
- Block-scoped namespaces (`namespace X { }`; file-scoped `namespace X;` is not allowed), usings outside the namespace and sorted (`.editorconfig` enforces it).
- Private fields camelCase without underscore, constants and `static readonly` fields PascalCase, explicit accessibility.
- `ArgumentNullException.ThrowIfNull(x)` without `nameof`.
- Use `PlayList` (not `Playlist`) in code; configuration POCOs end in `Configuration`; injected services are named after their type (`storageService`).
@@ -7,8 +7,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
/// <summary>Appends your own tracks to an album in the given order, skipping the ones it already has.</summary>
public record AddTracksToAlbumCommand(long UserId, Guid AlbumId, IReadOnlyList<Guid> TrackIds)
: ICommand<ErrorOr<Success>>;
@@ -75,3 +75,4 @@ public class AddTracksToAlbumCommandHandler(
return Result.Success;
}
}
}
@@ -12,8 +12,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record CreateAlbumCommand(
long UserId,
string Title,
@@ -70,3 +70,4 @@ public class CreateAlbumCommandHandler(
return AlbumApplicationResponse.FromEntity(album, trackCount: 0);
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Events;
using Musify.Application.Shared;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record DeleteAlbumCommand(long UserId, Guid AlbumId)
: ICommand<ErrorOr<Success>>;
@@ -34,3 +34,4 @@ public class DeleteAlbumCommandHandler(
return Result.Success;
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Albums.Responses;
using Musify.Application.Contracts;
using Musify.Application.Shared;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record GetAlbumByIdQuery(Guid Id)
: IQuery<ErrorOr<AlbumApplicationResponse>>;
@@ -27,3 +27,4 @@ public class GetAlbumByIdQueryHandler(IDatabase database)
: album;
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Contracts;
using Musify.Application.Shared;
using Musify.Application.Tracks.Responses;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record GetAlbumTracksQuery(
Guid AlbumId,
int PageNumber,
@@ -36,3 +36,4 @@ public class GetAlbumTracksQueryHandler(IDatabase database)
.ToPaginatedAsync(new PageRequest(request.PageNumber, request.PageSize), cancellationToken);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Albums.Responses;
using Musify.Application.Contracts;
using Musify.Application.Shared;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record GetAlbumsQuery(string? Title, int PageNumber, int PageSize)
: IQuery<PaginatedResponse<AlbumApplicationResponse>>;
@@ -31,3 +31,4 @@ public class GetAlbumsQueryHandler(IDatabase database)
.ToPaginatedAsync(new PageRequest(request.PageNumber, request.PageSize), cancellationToken);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Albums.Responses;
using Musify.Application.Contracts;
using Musify.Application.Shared;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record GetAlbumsByUserIdQuery(long UserId, int PageNumber, int PageSize)
: IQuery<ErrorOr<PaginatedResponse<AlbumApplicationResponse>>>;
@@ -31,3 +31,4 @@ public class GetAlbumsByUserIdQueryHandler(IDatabase database)
.ToPaginatedAsync(new PageRequest(request.PageNumber, request.PageSize), cancellationToken);
}
}
}
@@ -3,8 +3,8 @@ using Microsoft.EntityFrameworkCore;
using Musify.Application.Albums.Responses;
using Musify.Application.Contracts;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record GetRecentlyListenedAlbumsQuery(long UserId, int Limit)
: IQuery<IReadOnlyList<AlbumApplicationResponse>>;
@@ -49,3 +49,4 @@ public class GetRecentlyListenedAlbumsQueryHandler(IDatabase database)
.ToList();
}
}
}
@@ -5,8 +5,8 @@ using Microsoft.Extensions.Logging;
using Musify.Application.Contracts;
using Musify.Application.Shared;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record RemoveTrackFromAlbumCommand(long UserId, Guid AlbumId, Guid TrackId)
: ICommand<ErrorOr<Success>>;
@@ -43,3 +43,4 @@ public class RemoveTrackFromAlbumCommandHandler(
return Result.Success;
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Pictures.Responses;
using Musify.Application.Services;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record RequestAlbumPictureUploadCommand(
long UserId,
string FileType,
@@ -22,3 +22,4 @@ public class RequestAlbumPictureUploadCommandHandler(UploadIntentIssuer issuer,
request.UserId, UploadIntentPurpose.AlbumPicture, albumConfiguration,
request.FileType, request.ContentType, request.ExpectedSizeBytes, cancellationToken);
}
}
@@ -1,7 +1,7 @@
using Musify.Domain.Entities;
namespace Musify.Application.Albums.Responses;
namespace Musify.Application.Albums.Responses
{
public record AlbumApplicationResponse(
Guid Id,
string Title,
@@ -38,3 +38,4 @@ public record AlbumApplicationResponse(
coverTrackIds ?? []);
}
}
}
@@ -1,8 +1,8 @@
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums.Responses;
namespace Musify.Application.Albums.Responses
{
public static class AlbumProjections
{
public const int CoverTrackCount = 4;
@@ -29,3 +29,4 @@ public static class AlbumProjections
.Select(albumTrack => albumTrack.TrackId)
.ToList()));
}
}
@@ -11,8 +11,8 @@ using Musify.Application.Services;
using Musify.Application.Shared;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums;
namespace Musify.Application.Albums
{
public record UpdateAlbumCommand(
long UserId,
Guid AlbumId,
@@ -71,3 +71,4 @@ public class UpdateAlbumCommandHandler(
.SingleAsync(cancellationToken);
}
}
}
@@ -3,8 +3,8 @@ using Microsoft.Extensions.DependencyInjection;
using Musify.Application.Configuration;
using Musify.Application.Services;
namespace Musify.Application;
namespace Musify.Application
{
public static class ApplicationDependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services, IConfiguration configuration)
@@ -26,3 +26,4 @@ public static class ApplicationDependencyInjection
return services;
}
}
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class AlbumConfiguration : IConfigurationOptions, IPictureOwnerConfiguration
{
public static string SectionName => "Album";
@@ -12,3 +12,4 @@ public class AlbumConfiguration : IConfigurationOptions, IPictureOwnerConfigurat
[Required]
public PictureSizes PicturesSizes { get; set; } = new();
}
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class ApplicationStorageConfiguration : IConfigurationOptions
{
public static string SectionName => "ApplicationStorage";
@@ -10,3 +10,4 @@ public class ApplicationStorageConfiguration : IConfigurationOptions
[StringLength(128, MinimumLength = 1)]
public required string Bucket { get; set; }
}
}
@@ -2,8 +2,8 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public static class ConfigurationDependencyInjection
{
public static IServiceCollection AddValidatedOptions<T>(this IServiceCollection services, IConfiguration configuration)
@@ -27,3 +27,4 @@ public static class ConfigurationDependencyInjection
return services;
}
}
}
@@ -1,8 +1,8 @@
using Mediator;
using Musify.Application.Configuration.Responses;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public record GetPlaybackPublicConfigQuery : IQuery<PlaybackPublicConfigResponse>;
@@ -14,3 +14,4 @@ public class GetPlaybackPublicConfigQueryHandler(PlaybackConfiguration playbackC
playbackConfiguration.AllowAnonymousListening,
playbackConfiguration.AnonymousFragmentSeconds));
}
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public interface IConfigurationOptions
{
public static abstract string SectionName { get; }
}
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class MixConfiguration : IConfigurationOptions
{
public static string SectionName => "Mix";
@@ -9,3 +9,4 @@ public class MixConfiguration : IConfigurationOptions
[Range(4, 100)]
public int ItemsPerMix { get; set; } = 12;
}
}
@@ -2,8 +2,8 @@ using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Musify.Application.Shared;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public enum PictureSize
{
Small,
@@ -89,3 +89,4 @@ public static class PictureSizeParser
? size
: PictureSize.Medium;
}
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class PlayListConfiguration : IConfigurationOptions, IPictureOwnerConfiguration
{
public static string SectionName => "PlayList";
@@ -12,3 +12,4 @@ public class PlayListConfiguration : IConfigurationOptions, IPictureOwnerConfigu
[Required]
public PictureSizes PicturesSizes { get; set; } = new();
}
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public sealed class PlaybackConfiguration : IConfigurationOptions
{
@@ -15,3 +15,4 @@ public sealed class PlaybackConfiguration : IConfigurationOptions
[Range(1, int.MaxValue)]
public int EstimatedAudioBytesPerSecond { get; set; } = 16_000;
}
}
@@ -1,4 +1,5 @@
namespace Musify.Application.Configuration.Responses;
namespace Musify.Application.Configuration.Responses
{
public record PlaybackPublicConfigResponse(bool AllowAnonymousListening, int AnonymousFragmentSeconds);
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class StreamGatewayConfiguration : IConfigurationOptions
{
public static string SectionName => "StreamGateway";
@@ -13,3 +13,4 @@ public class StreamGatewayConfiguration : IConfigurationOptions
[Required]
public string AudioFileName { get; set; } = "audio.m4a";
}
}
@@ -2,8 +2,8 @@ using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Musify.Application.Shared;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class TrackConfiguration : IConfigurationOptions, IPictureOwnerConfiguration
{
public static string SectionName => "Track";
@@ -54,3 +54,4 @@ public class TrackRoutes : PictureRoutes
public string BuildProcessedAudioPath(string folderName) =>
StorageKey.Combine(ParentFolder, ProcessedAudiosFolder, folderName);
}
}
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace Musify.Application.Configuration;
namespace Musify.Application.Configuration
{
public class UploadIntentConfiguration : IConfigurationOptions
{
public static string SectionName => "UploadIntent";
@@ -39,3 +39,4 @@ public class UploadIntentConfiguration : IConfigurationOptions
[Range(60, 86400)]
public int TempCleanupJobIntervalSeconds { get; set; } = 3600;
}
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public record AudioTranscodeResult(int StatusCode, TimeSpan Duration);
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IAudioTranscoderService
{
public Task<AudioTranscodeResult> TranscodeToAudioFileAsync(Stream audioStream, string destinationPath, CancellationToken cancellationToken);
}
}
@@ -2,8 +2,8 @@ using ErrorOr;
using Microsoft.EntityFrameworkCore;
using Musify.Domain.Entities;
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IDatabase
{
public DbSet<User> Users { get; }
@@ -40,3 +40,4 @@ public interface IDatabase
public Task<ErrorOr<Success>> TrySaveChangesAsync(Error onUniqueViolation, CancellationToken cancellationToken);
}
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IDatabaseTransaction : IAsyncDisposable
{
public Task CommitAsync(CancellationToken cancellationToken = default);
}
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IEventBus
{
public Task PublishAsync<T>(T message, CancellationToken cancellationToken) where T : class;
}
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IPictureService
{
public Task<Stream> ResizePictureAsWebpAsync(Stream pictureStream, int width, int height, CancellationToken cancellationToken);
}
}
@@ -1,5 +1,5 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IStorageService
{
/// <summary>Opens an object for reading, or returns null when it does not exist.</summary>
@@ -22,3 +22,4 @@ public interface IStorageService
public IAsyncEnumerable<StorageObject> ListObjectsAsync(string bucket, string prefix, CancellationToken cancellationToken);
}
}
@@ -1,8 +1,9 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public interface IStreamTicketService
{
public StreamTicket IssueTicket(long? userId, string keyPrefix, long? maxBytes = null);
}
public record StreamTicket(string Token, int ExpiresInSeconds);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public record ObjectMetaData(string ContentType, long ContentLength);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Contracts;
namespace Musify.Application.Contracts
{
public record StorageObject(string Key, DateTime LastModifiedUtc);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record AlbumPictureProcessed(Guid AlbumId);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record AlbumPictureProcessingFailed(Guid AlbumId);
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record AlbumProcessingFailed(
Guid AlbumId,
string? Bucket,
string? PictureKey);
}
@@ -1,7 +1,7 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record CreateAlbumResourcesEvent(
Guid AlbumId,
Guid PictureIntentId,
@@ -9,3 +9,4 @@ public record CreateAlbumResourcesEvent(
string PictureSourceKey,
string PictureDestinationKey,
ImageSizes Sizes);
}
@@ -1,7 +1,7 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record CreatePlayListResourcesEvent(
Guid PlayListId,
Guid PictureIntentId,
@@ -9,3 +9,4 @@ public record CreatePlayListResourcesEvent(
string PictureSourceKey,
string PictureDestinationKey,
ImageSizes Sizes);
}
@@ -1,7 +1,7 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record CreateTrackResourcesEvent(
Guid TrackId,
Guid PictureIntentId,
@@ -13,3 +13,4 @@ public record CreateTrackResourcesEvent(
string AudioDestinationKey,
string AudioProcessedFolderKey,
ImageSizes Sizes);
}
@@ -1,5 +1,6 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record DeleteAlbumEvent(
Guid AlbumId,
long UserId);
}
@@ -1,5 +1,6 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record DeletePlayListEvent(
Guid PlayListId,
long UserId);
}
@@ -1,5 +1,6 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record DeleteTrackEvent(
Guid TrackId,
long UserId);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record PlayListPictureProcessed(Guid PlayListId);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record PlayListPictureProcessingFailed(Guid PlayListId);
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record PlayListProcessingFailed(
Guid PlayListId,
string? Bucket,
string? PictureKey);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record TrackAudioProcessed(Guid TrackId);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record TrackAudioProcessingFailed(Guid TrackId);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record TrackPictureProcessed(Guid TrackId);
}
@@ -1,3 +1,4 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record TrackPictureProcessingFailed(Guid TrackId);
}
@@ -1,7 +1,8 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record TrackProcessingFailed(
Guid TrackId,
string? Bucket,
string? PictureKey,
string? AudioKey);
}
@@ -1,9 +1,10 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record UpdateAlbumPictureEvent(
Guid AlbumId,
string Bucket,
string SourceKey,
ImageSizes Sizes);
}
@@ -1,7 +1,7 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record UpdateAlbumPictureSourceEvent(
Guid AlbumId,
Guid PictureIntentId,
@@ -9,3 +9,4 @@ public record UpdateAlbumPictureSourceEvent(
string PictureSourceKey,
string PictureDestinationKey,
ImageSizes Sizes);
}
@@ -1,9 +1,10 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record UpdatePlayListPictureEvent(
Guid PlayListId,
string Bucket,
string SourceKey,
ImageSizes Sizes);
}
@@ -1,7 +1,7 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record UpdatePlayListPictureSourceEvent(
Guid PlayListId,
Guid PictureIntentId,
@@ -9,3 +9,4 @@ public record UpdatePlayListPictureSourceEvent(
string PictureSourceKey,
string PictureDestinationKey,
ImageSizes Sizes);
}
@@ -1,8 +1,9 @@
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record UpdateTrackAudioEvent(
Guid TrackId,
string SourceBucket,
string SourceKey,
string DestinationBucket,
string DestinationFolderKey);
}
@@ -1,9 +1,10 @@
using Musify.Application.Shared;
namespace Musify.Application.Events;
namespace Musify.Application.Events
{
public record UpdateTrackPictureEvent(
Guid TrackId,
string Bucket,
string SourceKey,
ImageSizes Sizes);
}
@@ -2,8 +2,8 @@ using Mediator;
using Musify.Application.Genres.Responses;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Genres;
namespace Musify.Application.Genres
{
public record GetAvailableGenresQuery : IQuery<IReadOnlyList<AvailableGenreResponse>>;
public class GetAvailableGenresQueryHandler
@@ -22,3 +22,4 @@ public class GetAvailableGenresQueryHandler
return ValueTask.FromResult(result);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Contracts;
using Musify.Application.Genres.Responses;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Genres;
namespace Musify.Application.Genres
{
public record GetGenresQuery : IQuery<IReadOnlyList<GenreResponse>>;
public class GetGenresQueryHandler(IDatabase database)
@@ -27,3 +27,4 @@ public class GetGenresQueryHandler(IDatabase database)
.ToList();
}
}
}
@@ -1,5 +1,6 @@
using Musify.Domain.ValueObjects;
namespace Musify.Application.Genres.Responses;
namespace Musify.Application.Genres.Responses
{
public record AvailableGenreResponse(Genre Genre, IReadOnlyList<Genre> IncompatibleWith);
}
@@ -1,5 +1,6 @@
using Musify.Domain.ValueObjects;
namespace Musify.Application.Genres.Responses;
namespace Musify.Application.Genres.Responses
{
public record GenreResponse(Genre Genre, int TrackCount);
}
@@ -5,8 +5,8 @@ using Musify.Application.Shared;
using Musify.Application.Tracks.Responses;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Likes;
namespace Musify.Application.Likes
{
public record GetLikedTracksQuery(
long UserId,
int PageNumber,
@@ -28,3 +28,4 @@ public class GetLikedTracksQueryHandler(IDatabase database)
.ToPaginatedAsync(new PageRequest(request.PageNumber, request.PageSize), cancellationToken);
}
}
}
@@ -7,8 +7,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Likes;
namespace Musify.Application.Likes
{
public record ToggleTrackLikeCommand(long UserId, Guid TrackId)
: ICommand<ErrorOr<bool>>;
@@ -56,3 +56,4 @@ public class ToggleTrackLikeCommandHandler(
return nowLiked;
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Contracts;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Mixes;
namespace Musify.Application.Mixes
{
public record GenerateMixesForUserCommand(long UserId)
: ICommand;
@@ -128,3 +128,4 @@ public class GenerateMixesForUserCommandHandler(
}
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Contracts;
using Musify.Application.Mixes.Responses;
using Musify.Application.Shared;
namespace Musify.Application.Mixes;
namespace Musify.Application.Mixes
{
public record GetMixByIdQuery(long UserId, Guid MixId)
: IQuery<ErrorOr<MixApplicationResponse>>;
@@ -29,3 +29,4 @@ public class GetMixByIdQueryHandler(IDatabase database)
return new MixApplicationResponse(mix.Id, mix.Kind, items.Count, items);
}
}
}
@@ -3,8 +3,8 @@ using Microsoft.EntityFrameworkCore;
using Musify.Application.Contracts;
using Musify.Application.Mixes.Responses;
namespace Musify.Application.Mixes;
namespace Musify.Application.Mixes
{
public record GetMixesByUserIdQuery(long UserId)
: IQuery<IReadOnlyList<MixApplicationResponse>>;
@@ -48,3 +48,4 @@ public class GetMixesByUserIdQueryHandler(IDatabase database)
return responses;
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Mixes.Responses;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Mixes;
namespace Musify.Application.Mixes
{
internal static class MixItemMapper
{
@@ -38,3 +38,4 @@ internal static class MixItemMapper
.ToList();
}
}
}
@@ -1,7 +1,7 @@
using Musify.Domain.ValueObjects;
namespace Musify.Application.Mixes.Responses;
namespace Musify.Application.Mixes.Responses
{
public record MixApplicationResponse(
Guid Id,
MixKind Kind,
@@ -10,3 +10,4 @@ public record MixApplicationResponse(
{
public const int CoverItemCount = 4;
}
}
@@ -1,8 +1,9 @@
namespace Musify.Application.Mixes.Responses;
namespace Musify.Application.Mixes.Responses
{
public record MixItemApplicationResponse(
Guid TrackId,
string Title,
string? Artist,
double DurationSeconds,
int ListensCount);
}
@@ -7,8 +7,8 @@ using Musify.Application.Contracts;
using Musify.Application.Shared;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Pictures;
namespace Musify.Application.Pictures
{
public enum CoverOwner
{
Track,
@@ -73,3 +73,4 @@ public class GetCoverQueryHandler(
return new CoverLocation(storageConfiguration.Bucket, key, MimeUtility.GetMimeMapping(name));
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Pictures;
namespace Musify.Application.Pictures
{
/// <summary>What an album or playlist needs to switch to a freshly uploaded picture.</summary>
public sealed record PreparedPicture(UploadIntent Intent, EntityPictures Pictures, string FinalKey, ImageSizes Sizes);
@@ -33,3 +33,4 @@ public static class PictureSourceChange
owner.PicturesSizes.ToImageSizes(owner.Routes));
}
}
}
@@ -1,5 +1,5 @@
namespace Musify.Application.Pictures.Responses;
namespace Musify.Application.Pictures.Responses
{
public record PictureUploadResponse(
Guid IntentId,
string Bucket,
@@ -8,3 +8,4 @@ public record PictureUploadResponse(
string ContentType,
int ExpiresInSeconds,
string UploadUrl);
}
@@ -7,8 +7,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
/// <summary>Appends tracks to a playlist in the given order, skipping the ones it already has.</summary>
public record AddTracksToPlayListCommand(long UserId, Guid PlayListId, IReadOnlyList<Guid> TrackIds)
: ICommand<ErrorOr<Success>>;
@@ -71,3 +71,4 @@ public class AddTracksToPlayListCommandHandler(
return Result.Success;
}
}
}
@@ -12,8 +12,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record CreatePlayListCommand(
long UserId,
string Name,
@@ -76,3 +76,4 @@ public class CreatePlayListCommandHandler(
return PlayListApplicationResponse.FromEntity(playList);
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Events;
using Musify.Application.Shared;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record DeletePlayListCommand(long UserId, Guid PlayListId)
: ICommand<ErrorOr<Success>>;
@@ -34,3 +34,4 @@ public class DeletePlayListCommandHandler(
return Result.Success;
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Contracts;
using Musify.Application.PlayLists.Responses;
using Musify.Application.Shared;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record GetPlayListByIdQuery(Guid Id, long? RequestingUserId = null)
: IQuery<ErrorOr<PlayListApplicationResponse>>;
@@ -28,3 +28,4 @@ public class GetPlayListByIdQueryHandler(IDatabase database)
: playList;
}
}
}
@@ -7,8 +7,8 @@ using Musify.Application.Shared;
using Musify.Application.Tracks.Responses;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record GetPlayListTracksQuery(
Guid PlayListId,
int PageNumber,
@@ -39,3 +39,4 @@ public class GetPlayListTracksQueryHandler(IDatabase database)
.ToPaginatedAsync(new PageRequest(request.PageNumber, request.PageSize), cancellationToken);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Contracts;
using Musify.Application.PlayLists.Responses;
using Musify.Application.Shared;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record GetPlayListsByUserIdQuery(
long UserId,
string? Name,
@@ -38,3 +38,4 @@ public class GetPlayListsByUserIdQueryHandler(IDatabase database)
.ToPaginatedAsync(new PageRequest(request.PageNumber, request.PageSize), cancellationToken);
}
}
}
@@ -5,8 +5,8 @@ using Microsoft.Extensions.Logging;
using Musify.Application.Contracts;
using Musify.Application.Shared;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record RemoveTrackFromPlayListCommand(long UserId, Guid PlayListId, Guid TrackId)
: ICommand<ErrorOr<Success>>;
@@ -43,3 +43,4 @@ public class RemoveTrackFromPlayListCommandHandler(
return Result.Success;
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Pictures.Responses;
using Musify.Application.Services;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record RequestPlayListPictureUploadCommand(
long UserId,
string FileType,
@@ -22,3 +22,4 @@ public class RequestPlayListPictureUploadCommandHandler(UploadIntentIssuer issue
request.UserId, UploadIntentPurpose.PlayListPicture, playListConfiguration,
request.FileType, request.ContentType, request.ExpectedSizeBytes, cancellationToken);
}
}
@@ -2,8 +2,8 @@ using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists.Responses;
namespace Musify.Application.PlayLists.Responses
{
public record PlayListApplicationResponse(
Guid Id,
string Name,
@@ -43,3 +43,4 @@ public record PlayListApplicationResponse(
durationSeconds);
}
}
}
@@ -1,8 +1,8 @@
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists.Responses;
namespace Musify.Application.PlayLists.Responses
{
public static class PlayListProjections
{
public const int CoverTrackCount = 4;
@@ -35,3 +35,4 @@ public static class PlayListProjections
.Where(playListTrack => playListTrack.Track.LifeCycleStatus == LifeCycleStatus.Active)
.Sum(playListTrack => playListTrack.Track.DurationSeconds)));
}
}
@@ -11,8 +11,8 @@ using Musify.Application.Services;
using Musify.Application.Shared;
using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists;
namespace Musify.Application.PlayLists
{
public record UpdatePlayListCommand(
long UserId,
Guid PlayListId,
@@ -78,3 +78,4 @@ public class UpdatePlayListCommandHandler(
.SingleAsync(cancellationToken);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Configuration;
using Musify.Application.Contracts;
using Musify.Application.Tracks.Responses;
namespace Musify.Application.Services;
namespace Musify.Application.Services
{
/// <summary>Builds the stream URL and signed ticket for a processed track. It never touches the database.</summary>
public sealed class TrackStreamIssuer(
IStreamTicketService ticketService,
@@ -33,3 +33,4 @@ public sealed class TrackStreamIssuer(
return (long)playbackConfiguration.AnonymousFragmentSeconds * playbackConfiguration.EstimatedAudioBytesPerSecond;
}
}
}
@@ -8,8 +8,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Services;
namespace Musify.Application.Services
{
public sealed record UploadRequest(
UploadIntentPurpose Purpose,
PictureRoutes Routes,
@@ -131,3 +131,4 @@ public sealed class UploadIntentIssuer(
? uploadIntentConfiguration.DefaultExpectedAudioSizeBytes
: uploadIntentConfiguration.DefaultExpectedPictureSizeBytes;
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Shared;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Services;
namespace Musify.Application.Services
{
public sealed class UploadIntentValidator(
IDatabase database,
IStorageService storageService,
@@ -75,3 +75,4 @@ public sealed class UploadIntentValidator(
return intent;
}
}
}
@@ -1,7 +1,7 @@
using ErrorOr;
namespace Musify.Application.Shared;
namespace Musify.Application.Shared
{
public static class AppErrors
{
public static Error NotFound(string entity, object id) =>
@@ -13,3 +13,4 @@ public static class AppErrors
public static Error Conflict(string code, string description) =>
Error.Conflict(code, description);
}
}
@@ -1,5 +1,5 @@
namespace Musify.Application.Shared;
namespace Musify.Application.Shared
{
public record ImageSize(
string SavePath,
int Width,
@@ -9,3 +9,4 @@ public record ImageSizes(
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -3,8 +3,8 @@ using Microsoft.EntityFrameworkCore;
using Musify.Domain.Abstractions;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Shared;
namespace Musify.Application.Shared
{
public static class OwnershipExtensions
{
/// <summary>
@@ -26,3 +26,4 @@ public static class OwnershipExtensions
: AppErrors.Forbidden(typeof(T).Name, id);
}
}
}
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
namespace Musify.Application.Shared;
namespace Musify.Application.Shared
{
public record PageRequest(int PageNumber = 1, int PageSize = 20)
{
public const int MaxPageSize = 100;
@@ -43,3 +43,4 @@ public static class PaginationExtensions
HasPreviousPage: pageNumber > 1 && pageCount > 0);
}
}
}
@@ -1,5 +1,5 @@
namespace Musify.Application.Shared;
namespace Musify.Application.Shared
{
public static class StorageKey
{
public static string Combine(params string[] segments)
@@ -9,3 +9,4 @@ public static class StorageKey
.Select(static s => s.Trim().Trim('/', '\\')));
}
}
}
@@ -1,6 +1,7 @@
namespace Musify.Application.Shared;
namespace Musify.Application.Shared
{
public static class TextNormalizer
{
public static string Normalize(string value) => value.Trim().ToUpperInvariant();
}
}
@@ -11,8 +11,8 @@ using Musify.Application.Tracks.Responses;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Tracks;
namespace Musify.Application.Tracks
{
public record CreateTrackCommand(
long UserId,
string Title,
@@ -111,3 +111,4 @@ public class CreateTrackCommandHandler(
return TrackApplicationResponse.FromEntity(trackEntity, listensCount: 0);
}
}
}
@@ -3,8 +3,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Musify.Application.Contracts;
namespace Musify.Application.Tracks;
namespace Musify.Application.Tracks
{
public record DeleteStaleUncountedListensCommand : ICommand<int>;
public class DeleteStaleUncountedListensCommandHandler(
@@ -30,3 +30,4 @@ public class DeleteStaleUncountedListensCommandHandler(
return stale.Count;
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Events;
using Musify.Application.Shared;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Tracks;
namespace Musify.Application.Tracks
{
public record DeleteTrackCommand(
long UserId,
Guid TrackId)
@@ -39,3 +39,4 @@ public class DeleteTrackCommandHandler(
return Result.Success;
}
}
}

Some files were not shown because too many files have changed in this diff Show More