392 lines
7.1 KiB
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)
|
|
}
|