commit 9ae8db3e88a3309188c71e2596c1687887fbce1d
parent 1df261605d32d2eaacd6b56b0d7d40a8a9a0d08a
Author: brookjeynes <me@brookjeynes.dev>
Date: Sun, 14 Jun 2026 17:48:18 +1000
feat(albums): save MusicBrainz release IDs
Signed-off-by: brookjeynes <me@brookjeynes.dev>
Diffstat:
4 files changed, 70 insertions(+), 18 deletions(-)
diff --git a/internal/server/edit-album.go b/internal/server/edit-album.go
@@ -14,11 +14,12 @@ import (
)
type EditAlbumForm struct {
- Title string `schema:"album"`
- LatinTitle string `schema:"latin-title"`
- ArtistID []domain.ArtistID `schema:"artist-id"`
- SongID []domain.SongID `schema:"song-id"`
- ReleaseDate string `schema:"release-date"`
+ Title string `schema:"album"`
+ LatinTitle string `schema:"latin-title"`
+ ArtistID []domain.ArtistID `schema:"artist-id"`
+ SongID []domain.SongID `schema:"song-id"`
+ ReleaseDate string `schema:"release-date"`
+ MusicBrainzReleaseID domain.MusicBrainzID `schema:"musicbrainz-release-id"`
}
func parseEditAlbumForm(form EditAlbumForm) (domain.EditAlbum, error) {
@@ -95,12 +96,22 @@ func parseEditAlbumForm(form EditAlbumForm) (domain.EditAlbum, error) {
})
}
+ // musicbrainz release id
+ var musicbrainzReleaseID *domain.MusicBrainzID
+ if form.MusicBrainzReleaseID != "" {
+ if !domain.MusicBrainzIDIsValid(string(form.MusicBrainzReleaseID)) {
+ return album, fmt.Errorf("'%s' must be a valid MusicBrainz ID", form.MusicBrainzReleaseID)
+ }
+ musicbrainzReleaseID = &form.MusicBrainzReleaseID
+ }
+
album = domain.EditAlbum{
- Title: form.Title,
- LatinTitle: latinTitle,
- ReleaseDate: releaseDate,
- Artists: artists,
- Songs: songs,
+ MusicBrainzReleaseID: musicbrainzReleaseID,
+ Title: form.Title,
+ LatinTitle: latinTitle,
+ ReleaseDate: releaseDate,
+ Artists: artists,
+ Songs: songs,
}
return album, nil
diff --git a/internal/server/new-album.go b/internal/server/new-album.go
@@ -13,10 +13,11 @@ import (
)
type NewAlbumForm struct {
- Title string `schema:"album"`
- LatinTitle string `schema:"latin-title"`
- ArtistID []domain.ArtistID `schema:"artist-id"`
- ReleaseDate string `schema:"release-date"`
+ Title string `schema:"album"`
+ LatinTitle string `schema:"latin-title"`
+ ArtistID []domain.ArtistID `schema:"artist-id"`
+ ReleaseDate string `schema:"release-date"`
+ MusicBrainzReleaseID domain.MusicBrainzID `schema:"musicbrainz-release-id"`
}
func parseNewAlbumForm(form NewAlbumForm) (domain.NewAlbum, error) {
@@ -63,6 +64,7 @@ func parseNewAlbumForm(form NewAlbumForm) (domain.NewAlbum, error) {
latinTitle = &form.LatinTitle
}
+ // release date
releaseDate, err := time.Parse("2006-01-02", form.ReleaseDate)
if err != nil {
return album, fmt.Errorf("Invalid release date: %w", err)
@@ -74,11 +76,21 @@ func parseNewAlbumForm(form NewAlbumForm) (domain.NewAlbum, error) {
minDate.Format("2006-01-02"), maxDate.Format("2006-01-02"))
}
+ // musicbrainz release id
+ var musicbrainzReleaseID *domain.MusicBrainzID
+ if form.MusicBrainzReleaseID != "" {
+ if !domain.MusicBrainzIDIsValid(string(form.MusicBrainzReleaseID)) {
+ return album, fmt.Errorf("'%s' must be a valid MusicBrainz ID", form.MusicBrainzReleaseID)
+ }
+ musicbrainzReleaseID = &form.MusicBrainzReleaseID
+ }
+
album = domain.NewAlbum{
- Title: form.Title,
- LatinTitle: latinTitle,
- ReleaseDate: releaseDate,
- Artists: artists,
+ MusicBrainzReleaseID: musicbrainzReleaseID,
+ Title: form.Title,
+ LatinTitle: latinTitle,
+ ReleaseDate: releaseDate,
+ Artists: artists,
}
return album, nil
diff --git a/internal/server/ui/views/edit-album/edit-album.templ b/internal/server/ui/views/edit-album/edit-album.templ
@@ -178,6 +178,22 @@ templ EditAlbum(params EditAlbumParams) {
</ol>
}
</fieldset>
+ <fieldset>
+ <legend>MusicBrainz</legend>
+ <label title="External identifier used for metadata lookups such as cover art. This app does not contact MusicBrainz when saving.">
+ Release ID (optional):
+ <input
+ name="musicbrainz-release-id"
+ type="text"
+ if params.Album.MusicBrainzReleaseID != nil {
+ value={ *params.Album.MusicBrainzReleaseID }
+ }
+ pattern={ domain.IsValidMusicBrainzIDPattern }
+ placeholder="e32a4ae3-67d1-4541-84d8-de6ab2d7dec1"
+ />
+ <i data-lucide="info"></i>
+ </label>
+ </fieldset>
<footer aria-label="Form actions">
<button class="-primary" id="save-album-btn" type="submit">save changes</button>
<a href={ routes.Album(params.Album) }>cancel</a>
diff --git a/internal/server/ui/views/new-album/new-album.templ b/internal/server/ui/views/new-album/new-album.templ
@@ -128,6 +128,19 @@ templ NewAlbum(params NewAlbumParams) {
/>
</label>
</fieldset>
+ <fieldset>
+ <legend>MusicBrainz</legend>
+ <label title="External identifier used for metadata lookups such as cover art. This app does not contact MusicBrainz when saving.">
+ Release ID (optional):
+ <input
+ name="musicbrainz-release-id"
+ type="text"
+ pattern={ domain.IsValidMusicBrainzIDPattern }
+ placeholder="e32a4ae3-67d1-4541-84d8-de6ab2d7dec1"
+ />
+ <i data-lucide="info"></i>
+ </label>
+ </fieldset>
<footer aria-label="Form actions">
<button class="-primary" id="add-album-btn" type="submit">add album</button>
</footer>