Files
deepdrft/DeepDrftManager/Services/ICmsTrackService.cs
T
daniel-c-harvey 2f47efeb46 CMS Phase 9 Wave 3: Release Archive tab, medium selector, Session/Mix browsers
Renames Genre tab to Release Archive with switch-free medium card group
(Enum.GetValues-driven). Adds MediumFields single dispatch + CutFields/SessionFields/
MixFields per-medium sections embedded by all five upload/edit forms. BatchUpload
enforces single-track invariant for Session/Mix. Adds CmsSessionBrowser (hero-image
upload) and CmsMixBrowser (waveform status + per-row Generate trigger).
ICmsReleaseService/CmsReleaseService wraps api/release endpoints.
Note: medium selector is forward-compat only — API write path pending.
2026-06-12 23:07:15 -04:00

116 lines
5.3 KiB
C#

using DeepDrftModels.DTOs;
using DeepDrftModels.Enums;
using Models.Common;
using NetBlocks.Models;
namespace DeepDrftManager.Services;
/// <summary>
/// CMS-side track operations for the Manager host. Every read and write goes over HTTP to the
/// DeepDrftAPI API, which is the single authority over both the SQL metadata store and the
/// binary audio vault. DeepDrftManager holds no in-process data layer.
/// </summary>
public interface ICmsTrackService
{
/// <summary>
/// Proxy a WAV upload to DeepDrftAPI. The Content API owns the dual-database write and
/// returns the persisted track carrying the SQL-assigned <c>Id</c>. A vault-without-SQL
/// orphan is handled and logged server-side; here it surfaces as a failed result.
/// <paramref name="originalFileName"/> is the browser's filename, captured at upload time and
/// stored as metadata; it is not user-editable afterwards.
/// <paramref name="medium"/> sets the parent release's <see cref="ReleaseMedium"/>. NOTE: the
/// current <c>POST api/track/upload</c> endpoint has no <c>medium</c> form field, so the value is
/// sent forward-compatibly and ignored server-side until the API binds it (Cut is the server
/// default). Wiring the selector through here keeps the CMS ready for that API change.
/// </summary>
Task<ResultContainer<TrackDto>> UploadTrackAsync(
Stream wavStream,
string fileName,
string contentType,
string trackName,
string artist,
string? album,
string? genre,
string? releaseDate,
string? originalFileName,
long createdByUserId,
ReleaseType releaseType,
int trackNumber,
ReleaseMedium medium = ReleaseMedium.Cut,
CancellationToken ct = default);
/// <summary>
/// Delete a track via the Content API, which removes the SQL row then the vault entry.
/// Maps a 404 to a "Track not found." failure.
/// </summary>
Task<Result> DeleteTrackAsync(long id, CancellationToken ct = default);
/// <summary>
/// Soft-delete a release record via DELETE api/track/release/{id}. Use when a release
/// has no live tracks and needs to be removed from the albums browser.
/// </summary>
Task<Result> DeleteReleaseAsync(long releaseId, CancellationToken ct = default);
/// <summary>
/// Fetch a page of track metadata from the Content API's <c>GET api/track/page</c>. Optional
/// <paramref name="album"/> and <paramref name="genre"/> filters narrow the result to a single
/// release title or genre; null leaves the dimension unfiltered.
/// </summary>
Task<ResultContainer<PagedResult<TrackDto>>> GetPagedAsync(
int page, int pageSize, string? sortColumn, bool sortDescending,
string? album = null, string? genre = null,
CancellationToken ct = default);
/// <summary>
/// Fetch a single track's metadata from <c>GET api/track/meta/{id}</c>. A 404 returns a
/// passing result with a null value.
/// </summary>
Task<ResultContainer<TrackDto?>> GetByIdAsync(long id, CancellationToken ct = default);
/// <summary>
/// Upload a cover-art image to the images vault via <c>POST api/image/upload</c>.
/// Returns the generated entry key on success. Maps a 400 to a validation failure message.
/// </summary>
Task<ResultContainer<string>> UploadImageAsync(
Stream imageStream,
string fileName,
string contentType,
CancellationToken ct = default);
/// <summary>
/// Update a track's metadata via <c>PUT api/track/meta/{id}</c>. EntryKey is immutable and
/// not part of the update. <paramref name="imagePath"/> is tri-state: <c>null</c> leaves the
/// cover art unchanged, <c>""</c> clears it, and any other value sets it.
/// </summary>
Task<Result> UpdateAsync(
long id, string trackName, string artist,
string? album, string? genre, DateOnly? releaseDate,
string? imagePath = null,
ReleaseType? releaseType = null,
int? trackNumber = null,
CancellationToken ct = default);
/// <summary>
/// Fetch per-track waveform profile status from <c>GET api/track/waveform-status</c> for the
/// CMS PreProcessing panel. Unpaged — the admin catalogue is small.
/// </summary>
Task<ResultContainer<WaveformStatusDto[]>> GetWaveformStatusAsync(CancellationToken ct = default);
/// <summary>
/// Trigger waveform profile generation for a single track via
/// <c>POST api/track/{entryKey}/waveform</c>. Maps a 404 to a "Track audio not found." failure.
/// </summary>
Task<Result> GenerateWaveformProfileAsync(string entryKey, CancellationToken ct = default);
/// <summary>Returns all releases with track counts from GET api/track/albums.</summary>
Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default);
/// <summary>Returns all distinct genres with track counts from GET api/track/genres.</summary>
Task<ResultContainer<List<GenreSummaryDto>>> GetGenreSummariesAsync(CancellationToken ct = default);
/// <summary>
/// Returns the total track count by calling GET api/track/page with pageSize=1 and reading TotalCount.
/// </summary>
Task<ResultContainer<int>> GetTrackCountAsync(CancellationToken ct = default);
}