44 Commits

Author SHA1 Message Date
daniel-c-harvey afa862a67b fix: move LogInformation inside disposal guard in both GetTrack streaming arms
Prevents an OS handle leak if the logger throws after the FileStream is opened but before File() takes ownership. Also corrects a stale "finally block" comment in the lossless arm — it has always been a catch.
2026-06-26 15:16:29 -04:00
daniel-c-harvey d72263aea1 Stream Opus/derived read path: serve from seekable disk FileStream, never a whole-file byte[]; HasOpusAsync is index-only 2026-06-26 14:58:11 -04:00
daniel-c-harvey c1f2cafd8b Merge streaming-overhaul into dev (Opus low-data streaming, windowed streaming, HW-accel-off stabilization) 2026-06-26 11:14:59 -04:00
daniel-c-harvey 9347f11ff0 Stream the waveform compute so large uploads no longer buffer the whole file (Wave 2 OOM) 2026-06-25 21:49:11 -04:00
daniel-c-harvey 59f48bb8cb feature: CMS Opus status surfaces — backfill missing-N badge + upload Post-Processing phase (18.6) 2026-06-23 14:06:21 -04:00
daniel-c-harvey 2bde4908d7 Wire Opus end-to-end playback + Backfill-Opus action (Phase 18.5)
Player picks Opus when the browser can decode it and a sidecar exists (else lossless), injecting the sidecar before stream init; seek reuses the same format. Adds the Backfill-Opus bulk API endpoint + CMS action.
2026-06-23 12:39:13 -04:00
daniel-c-harvey 740d01a67f feature: Phase 18.3 — Opus delivery transport (?format= stream + seek sidecar endpoint) 2026-06-23 08:34:37 -04:00
daniel-c-harvey d7071fdbc2 fix: always delete staging file on mid-copy abort
Build the staging path before the copy in both UploadTrack and ReplaceAudio so the finally block deletes it on cancellation or IO error, not only on success.
2026-06-19 17:36:06 -04:00
daniel-c-harvey 37cf19c405 fix: stage audio uploads on data disk instead of /tmp
Relocate both the framework multipart buffer (via ASPNETCORE_TEMP) and the controller staging file to a configurable data-disk directory, so large WAV/FLAC/MP3 uploads no longer fail on the host's small tmpfs.
2026-06-19 17:25:51 -04:00
daniel-c-harvey d0be26bb3e Merge upload-duplicate-detection into dev (block duplicate-release uploads by title+artist) 2026-06-19 16:22:28 -04:00
daniel-c-harvey bd85507308 Block duplicate-release uploads by (title, artist): pre-flight check + server 409 backstop, with within-batch Cut attach via releaseId 2026-06-19 15:44:41 -04:00
daniel-c-harvey be1a55fd37 feat(stats): flip home Plays card live (Phase 16.5)
Add TotalPlays + UniqueListeners to HomeStatsDto, composed at
StatsController from IEventService (no migration). Card reads via
existing persistent-state-bridged round-trip.
2026-06-19 15:26:07 -04:00
daniel-c-harvey 3b9ca700c9 raise upload size cap to ~1.86 GB and nginx timeouts to 1200s
Raise RequestSizeLimit/MultipartBodyLengthLimit on upload+replace-audio,
MaxUploadBytes in BatchUpload/BatchEdit, and DefaultResponseTimeoutSeconds to
1200s. Add client_max_body_size 2000m and proxy_read/send_timeout 1200s to the
nginx manager/public confs.
2026-06-19 15:02:49 -04:00
daniel-c-harvey c084efa78e feat(phase-16.3): light up anonId unique-listener layer
Mint a first-party localStorage anonId, thread it onto play/share beacons,
persist it via EventController, and add all-time distinct-listener counts
(site/track/release). Storage columns + indexes already existed from 16.1.
2026-06-19 14:37:55 -04:00
daniel-c-harvey dbd90ee52a feat(phase-16): anonymous play & share telemetry substrate (wave 16.1)
Player-service play-session tracker (floor + 3-bucket classify), SharePopover share tracker with debounce, sendBeacon interop, proxied rate-limited POST api/event/{play,share}, append-only event logs + incremental play_counter with server-side release resolution. Migration authored, not applied. No anonId, no read surface.
2026-06-19 12:59:00 -04:00
daniel-c-harvey d12151278a Merge cms-track-replace-gating into dev
Replace track audio in CMS edit form + gate last-track delete.
2026-06-18 13:14:08 -04:00
daniel-c-harvey 16784b37f2 feat(cms): replace track audio in edit form, gate last-track delete
Swap a track's audio by EntryKey (metadata/release/position preserved, waveform regenerated); hide per-track remove on a release's sole persisted track so it can only be replaced or release-deleted.
2026-06-18 12:59:56 -04:00
daniel-c-harvey 5f0422a263 Wire NowPlayingStats to live aggregates: add SQL track duration column, stats endpoint, and duration backfill 2026-06-18 11:53:49 -04:00
daniel-c-harvey a19a734757 feat(p12-w2): track-cardinal high-res waveform fetch + bridge rewire
Add GET api/track/{trackEntryKey}/waveform/high-res (+ proxy), ITrackDataService.GetTrackWaveform; rewire visualizer to resolve the current track's EntryKey and re-fetch on track change. Retire the client mix-waveform read path.
2026-06-17 11:12:26 -04:00
daniel-c-harvey 3eef1a50f9 docs(release-controller): fix stale POST mix/waveform comment - track-waveforms vault, duration-derived high-res 2026-06-17 10:27:45 -04:00
daniel-c-harvey accf20ba57 feat(waveform): generalize high-res compute to every track (Direction B)
Per-track high-res datum keyed by EntryKey in the renamed track-waveforms vault; computed at upload for all tracks, regenerable per-track via CMS, with a re-runnable backfill. Mix read path repointed so it keeps working.
2026-06-17 10:18:44 -04:00
daniel-c-harvey f07d29cdcf feat(release): front int PK with app-minted GUID EntryKey on the public addressing surface (P11 W5, 11.H) 2026-06-16 17:11:55 -04:00
daniel-c-harvey cfacc9f79a feat(release): add plain-text Description field plumbed CMS->DTO->release (11.G)
New nullable Description column (max 4000) on ReleaseEntity, rides the Genre write channel through upload + edit; multiline CMS input. Migration authored, not applied.
2026-06-16 00:00:06 -04:00
daniel-c-harvey 737c423d9c feat: replace /archive with release-cardinal searchable browser (Phase 9 §8.H)
Retire the three-card overview for a search + medium + genre browser over all
releases. Adds q/genre filter params to the api/release paged read path,
mirroring the existing api/track/page TrackFilter pattern.
2026-06-13 20:47:50 -04:00
daniel-c-harvey b893ca84de Enforce per-medium track cardinality in the upload service via MediumRules
Promote the Session/Mix single-track rule from a CMS-form convention to a
domain invariant: declare cardinality as data in MediumRules, enforce it in
UnifiedTrackService before the vault write (no orphan), return 409, and read
the same rule in the batch-form collapse.
2026-06-13 14:12:01 -04:00
daniel-c-harvey 8b62915083 Make release Medium writable via upload + meta-edit; resolve detail-page track by releaseId not album title 2026-06-13 11:34:45 -04:00
daniel-c-harvey ca44fc8794 Phase 9 Wave 2: api/release endpoint family — medium-aware reads + metadata writes
Adds ReleaseRepository/ReleaseManager (IReleaseService) for paged medium-filtered
release reads and Session/Mix satellite writes, UnifiedReleaseService orchestrating
vault+SQL, and ReleaseController (5 endpoints). Refactors WaveformProfileService for
configurable bucketCount/vaultName (backward-compatible) and adds the mix-waveforms vault.
Promotes brittle error-string literals to named constants (MixHasNoTrackMessage,
MixTrackNoAudioMessage) on UnifiedReleaseService.
2026-06-12 22:13:31 -04:00
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
daniel-c-harvey f767d288c5 feat: normalize release-cardinal fields out of track into a Release entity (Phase 8 §8.0) 2026-06-11 12:51:21 -04:00
daniel-c-harvey f10e20a0e2 Merge branch 'p1.2-w1-t1-format-processors' into dev
# Conflicts:
#	DeepDrftAPI/Controllers/TrackController.cs
2026-06-11 08:20:05 -04:00
daniel-c-harvey 3bb8104967 feat(audio): add MP3 and FLAC upload support via format-routed processors
AudioProcessorRouter dispatches by extension; vault stores original bytes with correct MIME type.
2026-06-11 05:49:17 -04:00
daniel-c-harvey d47a5e00af feat(tracks): add ReleaseType and TrackNumber to track metadata model and CMS edit form 2026-06-10 21:36:00 -04:00
daniel-c-harvey 5cae83b9ed feat: add search/album/genre filtering and /albums + /genres browse pages 2026-06-10 10:54:56 -04:00
daniel-c-harvey f602eb9772 chore: remove WavOffsetService and ?offset= seek path, superseded by Range header (Phase 4.1) 2026-06-09 07:30:36 -04:00
daniel-c-harvey aaa9f732ae feat: replace ?offset= seek with HTTP Range streaming across API, proxy, and client
- API: enableRangeProcessing true on no-offset FileStream path
- Proxy: transparent Range relay, forwards 206/416/Content-Range verbatim
- TrackMediaClient: Range: bytes=X- replaces ?offset=X; response disposed via TrackMediaResponse
- StreamDecoder: reinitializeForRangeContinuation retains wavHeader, counts raw PCM against 206 Content-Length
- AudioPlayer: seekBeyondBuffer adds headerSize for file-absolute offset; duration guard prevents continuation overwriting full-track duration
- StreamingAudioPlayerService: seek guard corrected to >= 0 (file-absolute offset contract)
2026-06-09 07:00:35 -04:00
daniel-c-harvey 0d4ef369b9 feat: Stream Now instant-play of a random track from the nav button 2026-06-07 18:33:08 -04:00
daniel-c-harvey 627d5623f0 feat: image vault + cover-art API (upload/serve endpoints, ImagePath metadata link) 2026-06-07 16:16:38 -04:00
daniel-c-harvey 3de88c786a feat: capture and display original upload filename for tracks 2026-06-07 09:00:17 -04:00
daniel-c-harvey c83b132522 feature: Embed Frame Player 2026-06-06 15:43:09 -04:00
daniel-c-harvey 6e25ad3085 Add CMS waveform pre-processing panel with backfill endpoints
GET api/track/waveform-status and POST api/track/{id}/waveform (ApiKey);
CmsTrackService methods; TrackPreProcessing page with per-row and
sequential bulk generation; nav links from TrackList and Index.
2026-06-05 17:56:25 -04:00
daniel-c-harvey de4583b759 Add waveform profile HTTP transport: API endpoint, public proxy, content client method 2026-06-05 16:57:42 -04:00
Daniel Harvey e334886022 Eliminate DeepDrftPublic internal track API 2026-05-25 12:55:30 -04:00
Daniel Harvey 4351302a25 Flip ITrackService/TrackManager to DTO output; TrackConverter is the sole entity<->DTO path across all consumers 2026-05-25 11:35:04 -04:00
Daniel Harvey 551cef0fe8 DeepDrftAPI Rename 2026-05-25 10:38:36 -04:00