Files
deepdrft/DeepDrftData/ITrackService.cs
T
daniel-c-harvey f02974b3c2 fix: refresh stale browse cache on track edits and allow deleting empty releases
- Add CmsTrackBrowserViewModel.Invalidate(); called from TrackEdit/BatchEdit on save or delete so album/genre cache is invalidated and re-fetches on next mode switch
- CmsAlbumBrowser now handles 0-track releases: confirm dialog + DeleteReleaseAsync instead of early return; partial-failure path also fires OnReleasesChanged to trigger cache invalidation
- TrackList.OnAlbumsChanged now calls VM.Invalidate() so genres stay fresh after any album delete
- UnifiedTrackService.DeleteAsync cascades release soft-delete when last live track is removed (non-fatal; logs on failure)
- New DELETE api/track/release/{id} endpoint (ApiKeyAuthorize) for direct release soft-delete
- EF migration SoftDeleteOrphanedReleases backfills existing orphaned release rows via raw SQL (data-only, no schema change)
2026-06-11 17:56:18 -04:00

52 lines
2.6 KiB
C#

using DeepDrftModels.DTOs;
using Models.Common;
using NetBlocks.Models;
namespace DeepDrftData;
/// <summary>
/// SQL-side track service. Repository outputs entities; this service outputs DTOs via
/// TrackConverter. In-process consumers (UnifiedTrackService, CLI, DeepDrftPublic) all
/// receive DTOs.
/// </summary>
public interface ITrackService
{
Task<ResultContainer<TrackDto?>> GetById(long id);
Task<ResultContainer<TrackDto?>> GetByEntryKey(string entryKey);
/// <summary>
/// Returns a single track chosen uniformly at random, or null when the library is empty
/// (a valid state, not a failure). Backs the public "Stream Now" instant-play feature.
/// </summary>
Task<ResultContainer<TrackDto?>> GetRandom(CancellationToken cancellationToken = default);
Task<ResultContainer<List<TrackDto>>> GetAll();
Task<ResultContainer<PagedResult<TrackDto>>> GetPaged(int pageNumber, int pageSize, string? sortColumn, bool sortDescending, TrackFilter? filter = null, CancellationToken cancellationToken = default);
/// <summary>All releases, title-ascending, each carrying its non-deleted track count.</summary>
Task<ResultContainer<List<ReleaseDto>>> GetReleases(CancellationToken cancellationToken = default);
/// <summary>Distinct non-null genres with track counts, genre-ascending.</summary>
Task<ResultContainer<List<GenreSummaryDto>>> GetDistinctGenres(CancellationToken cancellationToken = default);
/// <summary>
/// Resolve the release matching <paramref name="title"/> + <paramref name="artist"/>, creating
/// one from <paramref name="releaseData"/> when none exists. Backs the upload flow's FK
/// resolution so a track lands on a shared release rather than duplicating release-cardinal data.
/// </summary>
Task<ResultContainer<ReleaseDto>> FindOrCreateRelease(
string title, string artist, ReleaseDto releaseData, CancellationToken cancellationToken = default);
Task<ResultContainer<TrackDto>> Create(TrackDto newTrack);
Task<ResultContainer<TrackDto>> Update(TrackDto track);
Task<Result> Delete(long id);
/// <summary>Soft-delete a release row by id. Idempotent — a missing or already-deleted row is a no-op.</summary>
Task<Result> DeleteRelease(long id, CancellationToken cancellationToken = default);
/// <summary>
/// Count of non-deleted tracks on a release. Backs the delete-cascade decision: when a track
/// delete leaves a release with zero live tracks, the release is soft-deleted too.
/// </summary>
Task<ResultContainer<int>> CountLiveTracksByRelease(long releaseId, CancellationToken cancellationToken = default);
}