Foundation: config, schema/migrations, auth, stable IDs, metadata probing

This commit is contained in:
2026-08-22 23:29:16 -05:00
commit d4ea7a4ca9
40 changed files with 3874 additions and 0 deletions
+149
View File
@@ -0,0 +1,149 @@
package metadata
import "testing"
func TestParseFFprobeOutputBasicTags(t *testing.T) {
raw := ffprobeOutput{
Format: ffprobeFormat{
FormatName: "mp3",
Duration: "215.5",
BitRate: "320000",
Tags: map[string]string{
"title": "Test Song",
"album": "Test Album",
"album_artist": "Album Artist",
"artist": "Artist One; Artist Two",
"genre": "Rock; Alternative",
"date": "2004-05-11",
"track": "3/12",
"disc": "1/2",
"composer": "Some Composer",
"isrc": "USRC17607839",
"producer": "Rick Rubin",
},
},
Streams: []ffprobeStream{
{Index: 0, CodecType: "audio", SampleRate: "44100", Channels: 2, BitRate: "320000"},
},
}
tags := parseFFprobeOutput(raw)
if tags.Title != "Test Song" {
t.Errorf("Title = %q", tags.Title)
}
if tags.Album != "Test Album" {
t.Errorf("Album = %q", tags.Album)
}
if tags.AlbumArtist != "Album Artist" {
t.Errorf("AlbumArtist = %q", tags.AlbumArtist)
}
if len(tags.Artists) != 2 || tags.Artists[0] != "Artist One" || tags.Artists[1] != "Artist Two" {
t.Errorf("Artists = %v", tags.Artists)
}
if len(tags.Genres) != 2 || tags.Genres[0] != "Rock" || tags.Genres[1] != "Alternative" {
t.Errorf("Genres = %v", tags.Genres)
}
if tags.Year != 2004 {
t.Errorf("Year = %d, want 2004", tags.Year)
}
if tags.TrackNumber != 3 || tags.TrackTotal != 12 {
t.Errorf("Track = %d/%d, want 3/12", tags.TrackNumber, tags.TrackTotal)
}
if tags.DiscNumber != 1 || tags.DiscTotal != 2 {
t.Errorf("Disc = %d/%d, want 1/2", tags.DiscNumber, tags.DiscTotal)
}
if tags.ISRC != "USRC17607839" {
t.Errorf("ISRC = %q", tags.ISRC)
}
if len(tags.Contributors) != 1 || tags.Contributors[0].Name != "Rick Rubin" || tags.Contributors[0].Role != "producer" {
t.Errorf("Contributors = %v", tags.Contributors)
}
if tags.DurationSeconds != 215.5 {
t.Errorf("DurationSeconds = %v", tags.DurationSeconds)
}
if tags.Format != "mp3" {
t.Errorf("Format = %q", tags.Format)
}
if tags.SampleRateHz != 44100 || tags.Channels != 2 {
t.Errorf("SampleRateHz/Channels = %d/%d", tags.SampleRateHz, tags.Channels)
}
if tags.BitrateKbps != 320 {
t.Errorf("BitrateKbps = %d, want 320", tags.BitrateKbps)
}
if tags.Kind != "song" {
t.Errorf("Kind = %q, want song", tags.Kind)
}
}
func TestParseFFprobeOutputArtistWithSlashNotSplit(t *testing.T) {
raw := ffprobeOutput{Format: ffprobeFormat{Tags: map[string]string{"artist": "AC/DC"}}}
tags := parseFFprobeOutput(raw)
if len(tags.Artists) != 1 || tags.Artists[0] != "AC/DC" {
t.Errorf("Artists = %v, want [\"AC/DC\"] (must not split band names on '/')", tags.Artists)
}
}
func TestParseFFprobeOutputEmbeddedArt(t *testing.T) {
raw := ffprobeOutput{
Format: ffprobeFormat{Tags: map[string]string{"title": "Song"}},
Streams: []ffprobeStream{
{Index: 0, CodecType: "audio"},
{Index: 1, CodecType: "video", CodecName: "mjpeg", Disposition: map[string]int{"attached_pic": 1}},
},
}
tags := parseFFprobeOutput(raw)
if !tags.HasEmbeddedArt {
t.Error("HasEmbeddedArt = false, want true")
}
if tags.EmbeddedArtStream != 1 {
t.Errorf("EmbeddedArtStream = %d, want 1", tags.EmbeddedArtStream)
}
if tags.Kind != "song" {
t.Errorf("Kind = %q, want song (attached_pic stream should not make this a video)", tags.Kind)
}
}
func TestParseFFprobeOutputRealVideoStream(t *testing.T) {
raw := ffprobeOutput{
Format: ffprobeFormat{Tags: map[string]string{"title": "Music Video"}},
Streams: []ffprobeStream{
{Index: 0, CodecType: "video", CodecName: "h264"},
{Index: 1, CodecType: "audio"},
},
}
tags := parseFFprobeOutput(raw)
if tags.Kind != "video" {
t.Errorf("Kind = %q, want video", tags.Kind)
}
}
func TestParseFFprobeOutputReplayGain(t *testing.T) {
raw := ffprobeOutput{Format: ffprobeFormat{Tags: map[string]string{
"replaygain_track_gain": "-6.30 dB",
"replaygain_track_peak": "0.987654",
}}}
tags := parseFFprobeOutput(raw)
if tags.ReplayGainTrackGainDB == nil || *tags.ReplayGainTrackGainDB != -6.30 {
t.Errorf("ReplayGainTrackGainDB = %v, want -6.30", tags.ReplayGainTrackGainDB)
}
if tags.ReplayGainTrackPeak == nil || *tags.ReplayGainTrackPeak != 0.987654 {
t.Errorf("ReplayGainTrackPeak = %v, want 0.987654", tags.ReplayGainTrackPeak)
}
}
func TestParseFFprobeOutputCaseInsensitiveTags(t *testing.T) {
raw := ffprobeOutput{Format: ffprobeFormat{Tags: map[string]string{"ALBUMARTIST": "Vorbis Style Artist"}}}
tags := parseFFprobeOutput(raw)
if tags.AlbumArtist != "Vorbis Style Artist" {
t.Errorf("AlbumArtist = %q, want case-insensitive match", tags.AlbumArtist)
}
}
func TestParseFFprobeOutputNoTags(t *testing.T) {
raw := ffprobeOutput{Format: ffprobeFormat{Duration: "10"}}
tags := parseFFprobeOutput(raw)
if tags.Title != "" || tags.Artists != nil {
t.Errorf("expected empty tags, got %+v", tags)
}
}