mirror of
https://github.com/by-jp/www.byjp.me.git
synced 2025-08-09 22:16:07 +01:00
125 lines
2.6 KiB
Go
125 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type mbResponse struct {
|
|
Recordings []mbRecording
|
|
}
|
|
|
|
type mbRecording struct {
|
|
ID string
|
|
Score int
|
|
Title string
|
|
Disambiguation string
|
|
FirstRelease string `json:"first-release-date"`
|
|
ArtistCredit []mbArtist `json:"artist-credit"`
|
|
Releases []mbRelease `json:"releases"`
|
|
}
|
|
|
|
type mbArtist struct {
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
type mbRelease struct {
|
|
ID string
|
|
Score int
|
|
Title string
|
|
Country string
|
|
Status string
|
|
Quality string
|
|
ArtistCredit []mbArtist `json:"artist-credit"`
|
|
Date string `json:"first-release-date"`
|
|
}
|
|
|
|
type ByDesirability []mbRecording
|
|
|
|
func (r ByDesirability) Len() int { return len(r) }
|
|
func (r ByDesirability) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
|
func (r ByDesirability) Less(i, j int) bool {
|
|
return sortInTurn(r[i], r[j],
|
|
// highScoreFirst,
|
|
preferGoodRelease,
|
|
preferNonLiveRecordings,
|
|
earliestRelease,
|
|
preferShorterName,
|
|
deterministicallyByID,
|
|
)
|
|
}
|
|
|
|
func sortInTurn[T interface{}](a, b T, comparators ...func(T, T) int) bool {
|
|
for _, comparator := range comparators {
|
|
switch comparator(a, b) {
|
|
case -1:
|
|
return true
|
|
case 1:
|
|
return false
|
|
default:
|
|
// Try the next comparator
|
|
}
|
|
}
|
|
// Don't swap if they're identical
|
|
return false
|
|
}
|
|
|
|
func ternary(first, last bool) int {
|
|
if first {
|
|
return -1
|
|
} else if last {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func highScoreFirst(a, b mbRecording) int {
|
|
as := a.Score / 20
|
|
bs := b.Score / 20
|
|
return ternary(as > bs, as < bs)
|
|
}
|
|
|
|
func preferNonLiveRecordings(a, b mbRecording) int {
|
|
al := stringIs(a.Disambiguation, "live")
|
|
bl := stringIs(b.Disambiguation, "live")
|
|
return ternary(!al && bl, al && !bl)
|
|
}
|
|
|
|
func preferGoodRelease(a, b mbRecording) int {
|
|
filter := func(r mbRelease) bool {
|
|
if len(r.ArtistCredit) > 0 && stringIs(r.ArtistCredit[0].Name, "various") {
|
|
return false
|
|
}
|
|
if !stringIs(r.Status, "official") {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
ar := filterReleases(a, filter)
|
|
br := filterReleases(a, filter)
|
|
return ternary(!ar && br, ar && !br)
|
|
}
|
|
|
|
func preferShorterName(a, b mbRecording) int {
|
|
return ternary(len(a.Title) < len(b.Title), len(a.Title) > len(b.Title))
|
|
}
|
|
|
|
func filterReleases(r mbRecording, filter func(mbRelease) bool) bool {
|
|
for _, rel := range r.Releases {
|
|
if filter(rel) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func earliestRelease(a, b mbRecording) int {
|
|
ad := parseReleaseDate(a.FirstRelease)
|
|
bd := parseReleaseDate(b.FirstRelease)
|
|
return ternary(ad.Before(bd), ad.After(bd))
|
|
}
|
|
|
|
func deterministicallyByID(a, b mbRecording) int {
|
|
return strings.Compare(a.ID, b.ID)
|
|
}
|