✨ 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