Get tags from mb

This commit is contained in:
Dan Jones 2023-11-11 17:01:01 -06:00
commit 5881f3d538
5 changed files with 190 additions and 32 deletions

View file

@ -2,17 +2,19 @@ package app
import ( import (
"fmt" "fmt"
"strconv"
"codeberg.org/danjones000/strip-beats/input/boolean"
"codeberg.org/danjones000/strip-beats/input/list" "codeberg.org/danjones000/strip-beats/input/list"
"codeberg.org/danjones000/strip-beats/media" "codeberg.org/danjones000/strip-beats/media"
"codeberg.org/danjones000/strip-beats/media/brainz" "codeberg.org/danjones000/strip-beats/media/brainz"
"codeberg.org/danjones000/strip-beats/utils" "codeberg.org/danjones000/strip-beats/utils"
"github.com/akrennmair/slice"
) )
type recOpt struct { type recOpt struct {
rec brainz.Recording rec brainz.Recording
num int r rune
score float64
} }
func (o recOpt) Title() string { func (o recOpt) Title() string {
@ -21,7 +23,8 @@ func (o recOpt) Title() string {
func (o recOpt) Text() string { func (o recOpt) Text() string {
return fmt.Sprintf( return fmt.Sprintf(
"By %s - First Released %s - %s %s", "(Score %.2f) By %s - First Released %s - %s %s",
100*o.score,
o.rec.FirstArtist().Name, o.rec.FirstArtist().Name,
o.rec.FirstReleaseDate, o.rec.FirstReleaseDate,
o.rec.FirstGenre().Name, o.rec.FirstGenre().Name,
@ -29,11 +32,7 @@ func (o recOpt) Text() string {
} }
func (o recOpt) Rune() rune { func (o recOpt) Rune() rune {
s := strconv.Itoa(o.num) return o.r
for _, c := range s {
return c
}
return 0
} }
func (o recOpt) Selected() func() { func (o recOpt) Selected() func() {
@ -57,27 +56,123 @@ func print() {
fmt.Println(rec.Title) fmt.Println(rec.Title)
tags.Title = rec.Title tags.Title = rec.Title
tags.MusicbrainzRecordingId = rec.Id tags.MusicbrainzRecordingId = rec.Id
tags.Date = rec.FirstReleaseDate tags.Date = rec.FirstReleaseDate
tags.Genre = rec.FirstGenre().Name
tags.Artist = rec.FirstArtist().Name
tags.ArtistSort = rec.FirstArtist().SortName
tags.AcoustidId = rec.AcousticId
fmt.Printf("%+v\n", tags) rel := findFirstRelease(rec)
if !boolean.Choose(fmt.Sprintf("Is %s album (%s %s) correct?", rel.Title, rel.Country, rel.Date)) {
rel = chooseRel(rec)
}
media := rel.Media[0]
track := media.Tracks[0]
full, err := brainz.GetReleaseWithMedia(rel.Id)
if err != nil {
panic(err)
}
albumArtist := full.ArtistCredit[0]
tags.MusicbrainzReleaseGroupId = full.ReleaseGroup.Id
tags.MusicbrainzAlbumId = rel.Id
tags.MusicbrainzAlbumArtistId = albumArtist.Artist.Id
tags.AlbumArtist = albumArtist.Name
tags.Album = rel.Title
if rel.Date != "" {
tags.Date = rel.Date
}
tags.AlbumArtistSort = albumArtist.Artist.SortName
tags.ReleaseCountry = rel.Country
if len(full.LabelInfo) > 0 {
tags.Label = full.LabelInfo[0].Label.Name
tags.MusicBrainzLabelId = full.LabelInfo[0].Label.Id
}
if len(rel.Genres) > 0 && rel.Genres[0].Name != "" {
tags.Genre = rel.Genres[0].Name
}
tags.Disc = media.Position
tags.DiscCount = len(full.Media)
tags.Track = track.Position
tags.TrackCount = media.TrackCount
} }
func chooseRec(ids media.IdResults) brainz.Recording { func chooseRec(ids media.IdResults) brainz.Recording {
var recs []list.Option var recs []list.Option
var rec brainz.Recording var rec brainz.Recording
var err error var err error
i := 1 i := 'a'
for _, res := range ids.Results { for _, res := range ids.Results {
for _, rec = range res.Recordings { for _, rec = range res.Recordings {
err = brainz.FillRecording(&rec) err = brainz.FillRecording(&rec)
if err != nil { if err != nil {
panic(err) panic(err)
} }
recs = append(recs, recOpt{rec, i}) rec.AcousticId = res.Id
i = (i + 1) % 10 recs = append(recs, recOpt{rec, i, res.Score})
if rec.Title != "" {
// Empty titles will be filtered out, so we don't need to increment them
i = i + 1
}
} }
} }
recs = slice.Filter(recs, func(opt list.Option) bool {
return opt.Title() != ""
})
return list.List("Which recording is the correct one?", recs, nil).(recOpt).rec return list.List("Which recording is the correct one?", recs, nil).(recOpt).rec
} }
func findFirstRelease(rec brainz.Recording) brainz.Release {
var rel brainz.Release
for _, rel = range rec.Releases {
if rel.Date == rec.FirstReleaseDate {
return rel
}
}
if len(rec.Releases) > 0 {
return rec.Releases[0]
}
return brainz.Release{}
}
func chooseRel(rec brainz.Recording) brainz.Release {
var rels []list.Option
var rel brainz.Release
i := 'a'
for _, rel = range rec.Releases {
rels = append(rels, relOpt{rel, i})
if rel.Title != "" {
// Empty titles will be filtered out, so we don't need to increment them
i = i + 1
}
}
rels = slice.Filter(rels, func(opt list.Option) bool {
return opt.Title() != ""
})
return list.List("Which releases is the correct one?", rels, nil).(relOpt).rel
}
type relOpt struct {
rel brainz.Release
r rune
}
func (o relOpt) Title() string {
return o.rel.Title
}
func (o relOpt) Text() string {
return fmt.Sprintf("%s %s", o.rel.Country, o.rel.Date)
}
func (o relOpt) Rune() rune {
return o.r
}
func (o relOpt) Selected() func() {
return nil
}

View file

@ -52,14 +52,16 @@ func testMb() {
func testPrint() { func testPrint() {
// SetFile("/home/drj/MyFiles/Videos/WebShows/YouTube/Dolly_Parton_-_Topic/Just_Because_I_m_a_Woman.Dolly_Parton_-_Topic.Fmv-XQerVkM.webm") // SetFile("/home/drj/MyFiles/Videos/WebShows/YouTube/Dolly_Parton_-_Topic/Just_Because_I_m_a_Woman.Dolly_Parton_-_Topic.Fmv-XQerVkM.webm")
SetFile("/home/drj/MyFiles/Videos/WebShows/YouTube/Whitney_Houston/I_Will_Always_Love_You_Ultimate_Collection_Edit.Whitney_Houston.rB7z_l8mBxw.mp4") // SetFile("/home/drj/MyFiles/Videos/WebShows/YouTube/Whitney_Houston/I_Will_Always_Love_You_Ultimate_Collection_Edit.Whitney_Houston.rB7z_l8mBxw.mp4")
SetFile("/home/drj/MyFiles/Music/Original_Broadway_Cast_of_Hamilton/Hamilton/d02t12-We_Know.m4a")
// SetFile("/home/drj/MyFiles/Videos/WebShows/YouTube/KaceyMusgravesVEVO/Kacey_Musgraves_-_Biscuits-nGIUtLO_x8g.mp4")
// SetFile("/home/drj/MyFiles/Videos/WebShows/YouTube/Willie_Nelson_-_Topic/Too_Sick_To_Pray.Willie_Nelson_-_Topic.8QgBXo41j2E.webm")
print() print()
quit() quit()
} }
func Run(step AppStep) { func Run(step AppStep) {
testPrint()
for step < Quit { for step < Quit {
switch step { switch step {
case Pick: case Pick:

View file

@ -12,6 +12,7 @@ import (
type Recording struct { type Recording struct {
Id uuid.UUID Id uuid.UUID
AcousticId uuid.UUID
Isrcs []string Isrcs []string
FirstReleaseDate string `json:"first-release-date"` FirstReleaseDate string `json:"first-release-date"`
Length int Length int
@ -66,21 +67,57 @@ type Genre struct {
} }
type Release struct { type Release struct {
Id uuid.UUID Id uuid.UUID
Country string Asin string
Date string Barcode string
Media []Media Country string
Status string Date string
StatusId uuid.UUID `json:"status-id"` Disambiguation string
ArtistCredit []ArtistCredit `json:"artist-credit"` Media []Media
Title string Packaging string
Genres []Genre PackagingId uuid.UUID `json:"packaging-id"`
Quality string
Status string
StatusId uuid.UUID `json:"status-id"`
ArtistCredit []ArtistCredit `json:"artist-credit"`
Title string
Genres []Genre
ReleaseGroup ReleaseGroup `json:"release-group"`
LabelInfo []LabelInfo `json:"label-info"`
// ReleaseEvents []ReleaseEvent `json:"release-events"` // ReleaseEvents []ReleaseEvent `json:"release-events"`
} }
type LabelInfo struct {
CatalogNumber string `json:"catalog-number"`
Label Label
}
type Label struct {
Id uuid.UUID
Name string
SortName string `json:"sort-name"`
Disambiguation string
TypeId string `json:"type-id"`
Type string
LabelCode int `json:"label-code"`
}
type ReleaseGroup struct {
Id uuid.UUID
Title string
ArtistCredit []ArtistCredit `json:"artist-credit"`
Disambiguation string
FirstReleaseDate string `json:"first-release-date"`
PrimaryType string `json:"primary-type"`
PrimaryTypeId uuid.UUID `json:"primary-type-id"`
SecondaryTypes []string `json:"secondary-types"`
SecondaryTypeIds []uuid.UUID `json:"secondary-type-ids"`
}
type ArtistCredit struct { type ArtistCredit struct {
Name string Name string
Artist Artist Artist Artist
JoinPhrase string
} }
type Artist struct { type Artist struct {
@ -95,6 +132,7 @@ type Artist struct {
type Media struct { type Media struct {
FormatId uuid.UUID `json:"format-id"` FormatId uuid.UUID `json:"format-id"`
Position int Position int
Title string
TrackOffset int `json:"track-offset"` TrackOffset int `json:"track-offset"`
Format string Format string
TrackCount int `json:"track-count"` TrackCount int `json:"track-count"`
@ -109,6 +147,25 @@ type Track struct {
Length int Length int
} }
func GetReleaseWithMedia(id uuid.UUID) (Release, error) {
rel := Release{Id: id}
url := fmt.Sprintf("https://musicbrainz.org/ws/2/release/%s", id)
resp, err := h.GetWithQuery(url, u.Values{
"fmt": []string{"json"},
"inc": []string{"artist-credits+discids+labels+release-groups"}})
if err != nil {
return rel, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return rel, err
}
err = json.Unmarshal(body, &rel)
return rel, err
}
func GetRecording(id string) (Recording, error) { func GetRecording(id string) (Recording, error) {
u, err := uuid.Parse(id) u, err := uuid.Parse(id)
rec := Recording{Id: u} rec := Recording{Id: u}

View file

@ -12,6 +12,7 @@ import (
"codeberg.org/danjones000/strip-beats/config" "codeberg.org/danjones000/strip-beats/config"
"codeberg.org/danjones000/strip-beats/media/brainz" "codeberg.org/danjones000/strip-beats/media/brainz"
h "codeberg.org/danjones000/strip-beats/utils/http" h "codeberg.org/danjones000/strip-beats/utils/http"
"github.com/google/uuid"
) )
type FPrint struct { type FPrint struct {
@ -45,7 +46,7 @@ type IdResults struct {
} }
type IdResult struct { type IdResult struct {
Id string Id uuid.UUID
Score float64 Score float64
Recordings []brainz.Recording Recordings []brainz.Recording
} }

View file

@ -5,13 +5,11 @@ import (
) )
type Tags struct { type Tags struct {
MajorBrand string `json:"major_brand"`
Title string Title string
Artist string Artist string
AlbumArtist string `json:"album_artist"` AlbumArtist string `json:"album_artist"`
Album string Album string
Date string Date string
Encoder string
Comment string Comment string
Description string Description string
Synopsis string Synopsis string
@ -21,12 +19,17 @@ type Tags struct {
MusicbrainzAlbumId uuid.UUID `json:"MUSICBRAINZ_ALBUMID"` MusicbrainzAlbumId uuid.UUID `json:"MUSICBRAINZ_ALBUMID"`
MusicbrainzAlbumArtistId uuid.UUID `json:"MUSICBRAINZ_ALBUMARTISTID"` MusicbrainzAlbumArtistId uuid.UUID `json:"MUSICBRAINZ_ALBUMARTISTID"`
MusicbrainzRecordingId uuid.UUID MusicbrainzRecordingId uuid.UUID
MusicBrainzLabelId uuid.UUID
ArtistSort string
AlbumArtistSort string AlbumArtistSort string
ReleaseCountry string ReleaseCountry string
Label string Label string
ReleaseType string
Composer string Composer string
Genre string Genre string
Disc string Disc int `json:"-"`
Track string DiscCount int
Track int `json:"-"`
TrackCount int
TrackStr string `json:"track"`
DiscStr string `json:"disc"`
} }