diff --git a/metadata/dischandler.go b/metadata/dischandler.go index d3a7695..50f7358 100644 --- a/metadata/dischandler.go +++ b/metadata/dischandler.go @@ -12,12 +12,14 @@ import ( "git.gammaspectra.live/S.O.N.G/Hibiki/utilities/specializedstore" "git.gammaspectra.live/S.O.N.G/METANOIA/utilities" "github.com/dhowden/tag" + "github.com/oriser/regroup" "golang.org/x/text/unicode/norm" "io/ioutil" "log" "os" "path" "sort" + "strconv" "strings" "sync" "sync/atomic" @@ -268,11 +270,14 @@ func processAudioFiles(files []string) (result fileEntryList) { } type DiscHandlerResult struct { - TOC TOC - CRC32 uint32 - CueToolsCRC32 uint32 - Directory string - Tracks []DiscHandlerTrack + TOC TOC + CRC32 uint32 + CueToolsCRC32 uint32 + Directory string + Tracks []DiscHandlerTrack + CommonMetadata map[string]string + Identifiers []Name + Album string } type DiscHandlerTrack struct { @@ -288,13 +293,12 @@ type DiscHandlerTrack struct { } FileMetadata struct { DiscNumber int + Artists []Name Album string - AlbumArtist string - Artist string - Composer string Year int TrackNumber int Title string + OriginalTitle string EmbeddedPicture []byte } AudioMetadata struct { @@ -344,8 +348,9 @@ func HandleDiscEntry(panakoInstance *panako.Instance, pathEntry string) *DiscHan sortedAudioEntries := processAudioFiles(audioFiles) disc := &DiscHandlerResult{ - Directory: pathEntry, - TOC: TOC{TocPregap}, + Directory: pathEntry, + TOC: TOC{TocPregap}, + CommonMetadata: make(map[string]string), } result, fullCRC32, fullCTDBCRC32 := sortedAudioEntries.analyze(pathEntry, panakoInstance) @@ -390,9 +395,98 @@ func HandleDiscEntry(panakoInstance *panako.Instance, pathEntry string) *DiscHan track.FileMetadata.DiscNumber, _ = entry.fileMetadata.Disc() track.FileMetadata.TrackNumber, _ = entry.fileMetadata.Track() track.FileMetadata.Year = entry.fileMetadata.Year() - track.FileMetadata.AlbumArtist = entry.fileMetadata.AlbumArtist() - track.FileMetadata.Artist = entry.fileMetadata.Artist() - track.FileMetadata.Composer = entry.fileMetadata.Composer() + if entry.fileMetadata.Artist() != "" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "artist", + Name: entry.fileMetadata.Artist(), + }) + } + if entry.fileMetadata.AlbumArtist() != "" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "albumartist", + Name: entry.fileMetadata.AlbumArtist(), + }) + } + if entry.fileMetadata.Composer() != "" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "composer", + Name: entry.fileMetadata.Composer(), + }) + } + + rawValues := entry.fileMetadata.Raw() + for k, v := range rawValues { + str, ok := v.(string) + if !ok { + var number int + number, ok = v.(int) + if ok { + str = fmt.Sprint(number) + } + } + if ok && len(str) > 0 { + if k == "mastering" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "mastering", + Name: str, + }) + } + if k == "lyricist" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "lyrics", + Name: str, + }) + } + if k == "guitar" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "performer, guitar", + Name: str, + }) + } + if k == "arrange" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "arranger", + Name: str, + }) + } + if k == "vocal" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "vocals", + Name: str, + }) + } + if k == "chorus" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "vocals", + Name: str, + }) + } + if k == "performer" { + track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{ + Kind: "performer", + Name: str, + }) + } + if k == "originaltitle" { + track.FileMetadata.OriginalTitle = str + } + + value, exists := disc.CommonMetadata[k] + if !exists { + disc.CommonMetadata[k] = str + } else if len(value) > 0 && value != str { + disc.CommonMetadata[k] = "" + } + } + } + + for k := range disc.CommonMetadata { + _, exists := rawValues[k] + if !exists { + disc.CommonMetadata[k] = "" + } + } + track.FileMetadata.Album = entry.fileMetadata.Album() track.FileMetadata.Title = entry.fileMetadata.Title() @@ -403,6 +497,78 @@ func HandleDiscEntry(panakoInstance *panako.Instance, pathEntry string) *DiscHan disc.Tracks = append(disc.Tracks, track) } + for k, v := range disc.CommonMetadata { + if v == "" { + delete(disc.CommonMetadata, k) + } + } + + catno, ok := disc.CommonMetadata["catalogid"] + if ok { + disc.Identifiers = append(disc.Identifiers, Name{ + Kind: "catalog", + Name: catno, + }) + } + + album, ok := disc.CommonMetadata["TALB"] //ID3v2 + if ok { + disc.Identifiers = append(disc.Identifiers, Name{ + Kind: "album", + Name: album, + }) + disc.Album = album + } + + album, ok = disc.CommonMetadata["album"] + if ok { + disc.Identifiers = append(disc.Identifiers, Name{ + Kind: "album", + Name: album, + }) + disc.Album = album + } + + discid, ok := disc.CommonMetadata["discid"] + if ok { + disc.Identifiers = append(disc.Identifiers, Name{ + Kind: "discid", + Name: discid, + }) + } + + cdtoc, ok := disc.CommonMetadata["cdtoc"] + if ok { + toc := TOC{} + for _, v := range strings.Split(cdtoc, "+")[1:] { + number, err := strconv.ParseInt(v, 16, 0) + if err != nil { + toc = TOC{} + break + } + toc = append(toc, int(number)) + } + if len(toc) > 0 { + toc = append(TOC{toc[len(toc)-1]}, toc[0:len(toc)-1]...) + disc.Identifiers = append(disc.Identifiers, Name{ + Kind: "toc", + Name: toc.String(), + }) + } + } + + catalogRE := regroup.MustCompile(`(?i)[\[\(\{](?P(?:[a-z]{2,}-?[0-9][a-z0-9\-~~]*)|(?:[0-9 ]{5,}))[\}\)\]]`) + m := &struct { + CatalogNumber string `regroup:"catno"` + }{} + err = catalogRE.MatchToTarget(disc.Directory, m) + if err == nil { + disc.Identifiers = append(disc.Identifiers, Name{ + Kind: "catalog", + Name: strings.ReplaceAll(m.CatalogNumber, "~", "~"), + }) + } + disc.TOC = append(TOC{disc.TOC[len(disc.TOC)-1]}, disc.TOC[0:len(disc.TOC)-1]...) return disc