METANOIA/metadata/album.go

392 lines
7.1 KiB
Go

package metadata
import (
"encoding/json"
"git.gammaspectra.live/S.O.N.G/METANOIA/utilities"
"time"
)
type Album struct {
License License
SourceUniqueIdentifier string
Name NameSlice
Roles RoleSlice
Art NameSlice
Identifiers NameSlice
Tags NameSlice
Links LinkSlice
Discs []Disc
ReleaseDate time.Time
}
func (n *Album) Normalize() {
n.Name.Normalize()
n.Identifiers.Normalize()
n.Roles.Normalize()
n.Art.Normalize()
n.Tags.Normalize()
n.Links.Normalize()
for i := range n.Discs {
n.Discs[i].Normalize()
}
}
func (n *Album) Copy() *Album {
return n.Merge(&Album{})
}
func (n *Album) Merge(o *Album) (r *Album) {
r = &Album{
License: License{
Code: Unknown,
},
Name: n.Name.Merge(o.Name),
Roles: n.Roles.Merge(o.Roles, false),
Art: n.Art.Merge(o.Art),
Identifiers: n.Identifiers.Merge(o.Identifiers),
Tags: n.Tags.Merge(o.Tags),
Links: n.Links.Merge(o.Links, false),
}
if n.License == o.License {
r.License = n.License
}
if n.SourceUniqueIdentifier == o.SourceUniqueIdentifier {
r.SourceUniqueIdentifier = n.SourceUniqueIdentifier
}
if n.ReleaseDate.Equal(o.ReleaseDate) {
r.ReleaseDate = n.ReleaseDate
} else if n.ReleaseDate.After(o.ReleaseDate) {
r.ReleaseDate = n.ReleaseDate
} else if n.ReleaseDate.Before(o.ReleaseDate) {
r.ReleaseDate = o.ReleaseDate
}
maxLen := len(n.Discs)
if len(o.Discs) > maxLen {
maxLen = len(o.Discs)
}
for i := 0; i < maxLen; i++ {
var discA *Disc
var discB *Disc
if len(n.Discs) > i {
discA = &n.Discs[i]
}
if len(o.Discs) > i {
discB = &o.Discs[i]
}
if discA != nil && discB != nil {
r.Discs = append(r.Discs, discA.Merge(*discB))
} else if discA != nil {
r.Discs = append(r.Discs, *discA)
} else if discB != nil {
r.Discs = append(r.Discs, *discB)
}
}
return
}
type Disc struct {
Name NameSlice
Identifiers NameSlice
Links LinkSlice
Tracks []Track
}
func (n *Disc) Merge(o Disc) (r Disc) {
r = Disc{
Name: n.Name.Merge(o.Name),
Identifiers: n.Identifiers.Merge(o.Identifiers),
Links: n.Links.Merge(o.Links, false),
}
maxLen := len(n.Tracks)
if len(o.Tracks) > maxLen {
maxLen = len(o.Tracks)
}
for i := 0; i < maxLen; i++ {
var trackA *Track
var trackB *Track
if len(n.Tracks) > i {
trackA = &n.Tracks[i]
}
if len(o.Tracks) > i {
trackB = &o.Tracks[i]
}
if trackA != nil && trackB != nil {
r.Tracks = append(r.Tracks, trackA.Merge(*trackB))
} else if trackA != nil {
r.Tracks = append(r.Tracks, *trackA)
} else if trackB != nil {
r.Tracks = append(r.Tracks, *trackB)
}
}
return r
}
func (n *Disc) Normalize() {
n.Name.Normalize()
n.Identifiers.Normalize()
n.Links.Normalize()
for i := range n.Tracks {
n.Tracks[i].Normalize()
}
}
type Track struct {
Name NameSlice
Identifiers NameSlice
Roles RoleSlice
Links LinkSlice
Duration time.Duration
Lyrics LyricGetter `json:"-"`
}
func (n *Track) Merge(o Track) (r Track) {
r = Track{
Name: n.Name.Merge(o.Name),
Identifiers: n.Identifiers.Merge(o.Identifiers),
Roles: n.Roles.Merge(o.Roles, false),
Links: n.Links.Merge(o.Links, false),
}
if n.Duration == o.Duration {
r.Duration = n.Duration
} else if n.Duration > o.Duration {
r.Duration = n.Duration
} else if n.Duration < o.Duration {
r.Duration = o.Duration
}
getterA := n.Lyrics
getterB := o.Lyrics
n.Lyrics = func() (lyrics []Lyrics) {
if getterA != nil {
lyrics = append(lyrics, getterA()...)
}
if getterB != nil {
lyrics = append(lyrics, getterB()...)
}
return
}
return r
}
func (n *Track) Normalize() {
n.Name.Normalize()
n.Identifiers.Normalize()
n.Roles.Normalize()
n.Links.Normalize()
}
type RoleSlice []Role
func (s RoleSlice) MarshalJSON() ([]byte, error) {
return json.Marshal([]Role(s))
}
func (s RoleSlice) Normalize() {
for i := range s {
s[i].Normalize()
}
}
func (s RoleSlice) Exists(role Role, loose bool) int {
for i, n := range s {
if (loose || n.Kind == role.Kind) && n.Name.AnyMatch(role.Name) {
return i
}
}
return -1
}
func (s RoleSlice) Merge(o RoleSlice, loose bool) (r RoleSlice) {
r = make(RoleSlice, 0)
for _, n := range s {
if ix := r.Exists(n, loose); ix != -1 {
r[ix].Name = r[ix].Name.Merge(n.Name)
} else {
r = append(r, Role{
Kind: n.Kind,
Group: n.Group,
Name: n.Name.Merge(NameSlice{}),
})
}
}
for _, n := range o {
if ix := r.Exists(n, loose); ix != -1 {
r[ix].Name = r[ix].Name.Merge(n.Name)
} else {
r = append(r, Role{
Kind: n.Kind,
Group: n.Group,
Name: n.Name.Merge(NameSlice{}),
})
}
}
return
}
type Role struct {
Kind string
Name NameSlice
Group string
}
func (n *Role) Normalize() {
n.Name.Normalize()
n.Group = utilities.NormalizeUnicode(n.Group)
}
type LinkSlice []Link
func (s LinkSlice) MarshalJSON() ([]byte, error) {
return json.Marshal([]Link(s))
}
func (s LinkSlice) Normalize() {
for i := range s {
s[i].Normalize()
}
}
func (s LinkSlice) Exists(role Link, loose bool) int {
for i, n := range s {
if (loose || n.Kind == role.Kind) && n.Name.AnyMatch(role.Name) {
return i
}
}
return -1
}
func (s LinkSlice) Merge(o LinkSlice, loose bool) (r LinkSlice) {
r = make(LinkSlice, 0)
for _, n := range s {
if ix := r.Exists(n, loose); ix != -1 {
r[ix].Name = r[ix].Name.Merge(n.Name)
} else {
r = append(r, Link{
Kind: n.Kind,
Name: n.Name.Merge(NameSlice{}),
})
}
}
for _, n := range o {
if ix := r.Exists(n, loose); ix != -1 {
r[ix].Name = r[ix].Name.Merge(n.Name)
} else {
r = append(r, Link{
Kind: n.Kind,
Name: n.Name.Merge(NameSlice{}),
})
}
}
return
}
type Link struct {
Kind string
Name NameSlice
}
func (l *Link) Normalize() {
l.Name.Normalize()
}
type NameSlice []Name
func (s NameSlice) MarshalJSON() ([]byte, error) {
return json.Marshal([]Name(s))
}
func (s NameSlice) GetKind(kind string) (result []string) {
for _, n := range s {
if n.Kind == kind {
result = append(result, n.Name)
}
}
return
}
func (s NameSlice) Exists(name Name) int {
for i, n := range s {
if n.Kind == name.Kind && n.Name == name.Name {
return i
}
}
return -1
}
func (s NameSlice) Match(name string) int {
for i, n := range s {
if n.Name == name {
return i
}
}
return -1
}
func (s NameSlice) AnyMatch(name NameSlice) bool {
for _, n := range s {
for _, o := range name {
if n.Name == o.Name {
return true
}
}
}
return false
}
func (s NameSlice) Merge(o NameSlice) (r NameSlice) {
r = make(NameSlice, 0)
for _, n := range s {
if r.Exists(n) == -1 {
r = append(r, n)
}
}
for _, n := range o {
if r.Exists(n) == -1 {
r = append(r, n)
}
}
return
}
func (s NameSlice) Normalize() {
for i := range s {
if s[i].Kind == "url" { //skip URLs
continue
}
s[i].Normalize()
}
}
type Name struct {
Kind string
Name string
}
func (n *Name) Normalize() {
n.Name = utilities.NormalizeUnicode(n.Name)
}