✨ Get tags from mb
This commit is contained in:
		
					parent
					
						
							
								739bed214c
							
						
					
				
			
			
				commit
				
					
						5881f3d538
					
				
			
		
					 5 changed files with 190 additions and 32 deletions
				
			
		
							
								
								
									
										121
									
								
								app/print.go
									
										
									
									
									
								
							
							
						
						
									
										121
									
								
								app/print.go
									
										
									
									
									
								
							|  | @ -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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -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: | ||||||
|  |  | ||||||
|  | @ -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} | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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"` | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue