Commit Graph
23 Commits
Author SHA1 Message Date
owenandClaude Sonnet 5 a921f9e2bc Add optional MusicBrainz/Cover Art Archive metadata enrichment
getArtistInfo/2 and getAlbumInfo/2 now return a real MusicBrainz
disambiguation/cover-art lookup for entities that carry a locally
tagged MusicBrainz ID, gated behind the new
VIBESONIC_ENABLE_EXTERNAL_METADATA flag (default off). Responses are
cached in the existing external_metadata_cache table for 30 days to
avoid hammering the free MusicBrainz/CAA services.

VibeSonic still works completely offline: with the flag off, or when
an entity has no tagged MusicBrainz ID, or on any network/lookup
failure, the handlers fall back to local-only fields exactly as
before — nothing is ever fabricated, and a failed external lookup
never fails the request.

internal/metadataenrich is a small, independently-testable HTTP client
for the two real APIs (base URLs overridable for tests, exercised
against httptest servers rather than the live network).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 08:35:40 -05:00
owenandClaude Sonnet 5 2a69f6dc33 Blend real sonic distance into classic getSimilarSongs ranking
similarSongsFor still filters by genre (unchanged, and getSonicSimilarTracks
remains the pure-sonic endpoint), but when the seed song has been
analyzed, genre-matched candidates that also have stored audio_features
are now ordered by actual feature-space distance from the seed instead
of SQL's random order; candidates without analysis data are left at
the end in their existing relative order rather than dropped or given
a fabricated distance.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 08:31:54 -05:00
owenandClaude Sonnet 5 b6acd63c2d Implement sonicSimilarity extension with real audio feature analysis
Adds internal/audiofeatures: decodes each scanned song to PCM via
ffmpeg and computes actual measured characteristics — tempo (via
autocorrelation of the frame energy envelope, left unset rather than
guessed when a clip is too short to contain a beat), an approximate
loudness figure, spectral centroid/rolloff and zero-crossing rate (via
a hand-written FFT), and a 12-bin chroma vector used both for a
Krumhansl-Kessler key estimate and as similarity-index input. No
external DSP/ML dependency.

The scanner now runs this analysis after indexing each song (as part
of the already-background scan, not on any request path) and stores
results in the existing audio_features table via the new
database.UpsertAudioFeatures/GetAudioFeatures/ListAllAudioFeatures.

internal/similarity is a small in-process nearest-neighbor index:
z-score normalizes each feature dimension across the analyzed library
and answers Nearest (ranked real distances) and Path (a feature-space
straight-line walk from one track to another, hopping to the closest
not-yet-used real song at each step — never a fabricated intermediate
track).

getSonicSimilarTracks and findSonicPath expose these through the
standard sonicMatch response, converting distance to a normalized
(0,1] similarity score. A song that hasn't been analyzed yet is simply
absent from results rather than faked.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 08:30:20 -05:00
owenandClaude Sonnet 5 6fb46a989e Implement the OpenSubsonic transcoding extension (getTranscodeDecision/getTranscodeStream)
Adds a real capability-matching decision engine: getTranscodeDecision
compares the source file's actual scanned format/channels against the
client's declared directPlayProfiles first, and only when nothing
matches does it search transcodingProfiles for a codec VibeSonic's
ffmpeg pipeline can actually encode (mp3/opus/aac), applying any
codecProfile limitations (bitrate/channel required constraints) the
client listed. canTranscode is never set true for a codec the server
has no encoder for, and canDirectPlay is never set true without a
matching client profile.

getTranscodeStream takes the opaque transcodeParams token the
decision returned (never re-derived) plus a real time offset and
streams actual transcoded audio via the existing seek-capable
transcoding.Manager.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 08:23:08 -05:00
owenandClaude Sonnet 5 ec28053d36 Implement songLyrics extension: getLyricsBySongId with real word/syllable cues
Adds getLyricsBySongId (versions 1 and 2 of the songLyrics extension,
gated by the enhanced param): returns every stored structuredLyrics
entry for a song, including line-level start times for synced lyrics
and, only when a source actually provided word/syllable timing (an
Enhanced LRC sidecar) and enhanced=true was requested, cueLine/cue
data with the precomputed UTF-8 byte offsets. Plain and non-enhanced
synced lyrics never get fabricated cue data.

Removes the now-dead SetSongLyrics writer (superseded by
database.InsertLyrics); SongLyricsPlainText keeps serving the legacy
getLyrics endpoint unchanged.

Adds a scanner integration test proving a sidecar .lrc (with an
Enhanced LRC line) is discovered and indexed during a real scan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 08:19:41 -05:00
owen 4a5add80b6 OpenSubsonic: playbackReport extension (reportPlayback), integrated with now-playing/history 2026-08-23 08:08:35 -05:00
owen d3074ab6fe OpenSubsonic: indexBasedQueue (getPlayQueueByIndex, savePlayQueueByIndex) with real duplicate-song support 2026-08-23 08:07:16 -05:00
owen e88f4e040c OpenSubsonic: getPodcastEpisode, topSongsByArtistId, transcodeOffset (real ffmpeg seek) 2026-08-23 08:06:12 -05:00
owen e38d31d384 Phase 3: OpenSubsonic core (response envelope, error codes 42-44, getOpenSubsonicExtensions) and apiKeyAuthentication extension with tokenInfo, web API key management 2026-08-23 08:04:01 -05:00
owen 3b4883780b Fix test-leaked HLS cache directory tracked in repo; give subsonic tests a real DataDir 2026-08-23 00:38:57 -05:00
owen 6ac50994b8 Phase 2: exhaustive Subsonic 1.16.1 compatibility matrix, README/config/Docker updates 2026-08-23 00:38:09 -05:00
owen 2e222bd193 Subsonic: jukeboxControl endpoint wired to real mpv-backed controller 2026-08-23 00:29:59 -05:00
owen c2166fa7d4 Subsonic: podcast endpoints (getPodcasts, getNewestPodcasts, refreshPodcasts, createPodcastChannel, deletePodcastChannel/Episode, downloadPodcastEpisode) 2026-08-23 00:26:14 -05:00
owen fce44a2ffd Add real podcast subsystem: RSS feed refresh, bounded background downloads, restart recovery 2026-08-23 00:24:43 -05:00
owen 8d93bea384 Subsonic: user management endpoints (getUser, getUsers, createUser, updateUser, deleteUser, changePassword) with full permission model mapping 2026-08-23 00:22:44 -05:00
owen d92a25b141 Subsonic: internet radio, chat, bookmarks, play queue, scanner status endpoints 2026-08-23 00:21:13 -05:00
owen c6e0131984 Subsonic: sharing (getShares, createShare, updateShare, deleteShare) plus real public share web pages and stream route 2026-08-23 00:18:51 -05:00
owen b77ccd242a Subsonic: annotation endpoints (star, unstar, setRating, scrobble) 2026-08-23 00:15:58 -05:00
owen c7b472ab99 Subsonic: media retrieval endpoints (stream, download, getCoverArt, getLyrics, getAvatar, hls, getCaptions) with real transcoding, embedded lyrics extraction, and folder permission enforcement 2026-08-23 00:15:00 -05:00
owen 6e2b875eaa Subsonic: playlist endpoints (getPlaylists, getPlaylist, createPlaylist, updatePlaylist, deletePlaylist) 2026-08-23 00:09:36 -05:00
owen a297454065 Subsonic: album/song lists (getAlbumList/2, getRandomSongs, getSongsByGenre, getNowPlaying, getStarred/2) and search (search, search2, search3) 2026-08-23 00:08:06 -05:00
owen f40a011c46 Subsonic: browsing endpoints (getMusicFolders, getIndexes, getMusicDirectory, getGenres, getArtists/Artist, getAlbum, getSong, getVideos/VideoInfo, getArtistInfo/2, getAlbumInfo/2, getSimilarSongs/2, getTopSongs) 2026-08-23 00:06:08 -05:00
owen b5e2bf01e2 Phase 2: Subsonic REST API framework (auth, response formatting, error handling, routing) plus user permission model 2026-08-22 23:58:54 -05:00