✨ 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 ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"codeberg.org/danjones000/strip-beats/input/boolean" | ||||
| 	"codeberg.org/danjones000/strip-beats/input/list" | ||||
| 	"codeberg.org/danjones000/strip-beats/media" | ||||
| 	"codeberg.org/danjones000/strip-beats/media/brainz" | ||||
| 	"codeberg.org/danjones000/strip-beats/utils" | ||||
| 	"github.com/akrennmair/slice" | ||||
| ) | ||||
| 
 | ||||
| type recOpt struct { | ||||
| 	rec brainz.Recording | ||||
| 	num int | ||||
| 	rec   brainz.Recording | ||||
| 	r     rune | ||||
| 	score float64 | ||||
| } | ||||
| 
 | ||||
| func (o recOpt) Title() string { | ||||
|  | @ -21,7 +23,8 @@ func (o recOpt) Title() string { | |||
| 
 | ||||
| func (o recOpt) Text() string { | ||||
| 	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.FirstReleaseDate, | ||||
| 		o.rec.FirstGenre().Name, | ||||
|  | @ -29,11 +32,7 @@ func (o recOpt) Text() string { | |||
| } | ||||
| 
 | ||||
| func (o recOpt) Rune() rune { | ||||
| 	s := strconv.Itoa(o.num) | ||||
| 	for _, c := range s { | ||||
| 		return c | ||||
| 	} | ||||
| 	return 0 | ||||
| 	return o.r | ||||
| } | ||||
| 
 | ||||
| func (o recOpt) Selected() func() { | ||||
|  | @ -57,27 +56,123 @@ func print() { | |||
| 	fmt.Println(rec.Title) | ||||
| 
 | ||||
| 	tags.Title = rec.Title | ||||
| 
 | ||||
| 	tags.MusicbrainzRecordingId = rec.Id | ||||
| 	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 { | ||||
| 	var recs []list.Option | ||||
| 	var rec brainz.Recording | ||||
| 	var err error | ||||
| 	i := 1 | ||||
| 	i := 'a' | ||||
| 	for _, res := range ids.Results { | ||||
| 		for _, rec = range res.Recordings { | ||||
| 			err = brainz.FillRecording(&rec) | ||||
| 			if err != nil { | ||||
| 				panic(err) | ||||
| 			} | ||||
| 			recs = append(recs, recOpt{rec, i}) | ||||
| 			i = (i + 1) % 10 | ||||
| 			rec.AcousticId = res.Id | ||||
| 			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 | ||||
| } | ||||
| 
 | ||||
| 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() { | ||||
| 	// 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() | ||||
| 
 | ||||
| 	quit() | ||||
| } | ||||
| 
 | ||||
| func Run(step AppStep) { | ||||
| 	testPrint() | ||||
| 	for step < Quit { | ||||
| 		switch step { | ||||
| 		case Pick: | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ import ( | |||
| 
 | ||||
| type Recording struct { | ||||
| 	Id               uuid.UUID | ||||
| 	AcousticId       uuid.UUID | ||||
| 	Isrcs            []string | ||||
| 	FirstReleaseDate string `json:"first-release-date"` | ||||
| 	Length           int | ||||
|  | @ -66,21 +67,57 @@ type Genre struct { | |||
| } | ||||
| 
 | ||||
| type Release struct { | ||||
| 	Id           uuid.UUID | ||||
| 	Country      string | ||||
| 	Date         string | ||||
| 	Media        []Media | ||||
| 	Status       string | ||||
| 	StatusId     uuid.UUID      `json:"status-id"` | ||||
| 	ArtistCredit []ArtistCredit `json:"artist-credit"` | ||||
| 	Title        string | ||||
| 	Genres       []Genre | ||||
| 	Id             uuid.UUID | ||||
| 	Asin           string | ||||
| 	Barcode        string | ||||
| 	Country        string | ||||
| 	Date           string | ||||
| 	Disambiguation string | ||||
| 	Media          []Media | ||||
| 	Packaging      string | ||||
| 	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"` | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 	Name   string | ||||
| 	Artist Artist | ||||
| 	Name       string | ||||
| 	Artist     Artist | ||||
| 	JoinPhrase string | ||||
| } | ||||
| 
 | ||||
| type Artist struct { | ||||
|  | @ -95,6 +132,7 @@ type Artist struct { | |||
| type Media struct { | ||||
| 	FormatId    uuid.UUID `json:"format-id"` | ||||
| 	Position    int | ||||
| 	Title       string | ||||
| 	TrackOffset int `json:"track-offset"` | ||||
| 	Format      string | ||||
| 	TrackCount  int `json:"track-count"` | ||||
|  | @ -109,6 +147,25 @@ type Track struct { | |||
| 	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) { | ||||
| 	u, err := uuid.Parse(id) | ||||
| 	rec := Recording{Id: u} | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ import ( | |||
| 	"codeberg.org/danjones000/strip-beats/config" | ||||
| 	"codeberg.org/danjones000/strip-beats/media/brainz" | ||||
| 	h "codeberg.org/danjones000/strip-beats/utils/http" | ||||
| 	"github.com/google/uuid" | ||||
| ) | ||||
| 
 | ||||
| type FPrint struct { | ||||
|  | @ -45,7 +46,7 @@ type IdResults struct { | |||
| } | ||||
| 
 | ||||
| type IdResult struct { | ||||
| 	Id         string | ||||
| 	Id         uuid.UUID | ||||
| 	Score      float64 | ||||
| 	Recordings []brainz.Recording | ||||
| } | ||||
|  |  | |||
|  | @ -5,13 +5,11 @@ import ( | |||
| ) | ||||
| 
 | ||||
| type Tags struct { | ||||
| 	MajorBrand                string `json:"major_brand"` | ||||
| 	Title                     string | ||||
| 	Artist                    string | ||||
| 	AlbumArtist               string `json:"album_artist"` | ||||
| 	Album                     string | ||||
| 	Date                      string | ||||
| 	Encoder                   string | ||||
| 	Comment                   string | ||||
| 	Description               string | ||||
| 	Synopsis                  string | ||||
|  | @ -21,12 +19,17 @@ type Tags struct { | |||
| 	MusicbrainzAlbumId        uuid.UUID `json:"MUSICBRAINZ_ALBUMID"` | ||||
| 	MusicbrainzAlbumArtistId  uuid.UUID `json:"MUSICBRAINZ_ALBUMARTISTID"` | ||||
| 	MusicbrainzRecordingId    uuid.UUID | ||||
| 	MusicBrainzLabelId        uuid.UUID | ||||
| 	ArtistSort                string | ||||
| 	AlbumArtistSort           string | ||||
| 	ReleaseCountry            string | ||||
| 	Label                     string | ||||
| 	ReleaseType               string | ||||
| 	Composer                  string | ||||
| 	Genre                     string | ||||
| 	Disc                      string | ||||
| 	Track                     string | ||||
| 	Disc                      int `json:"-"` | ||||
| 	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