Yonah 0999ccd211
cmd/msrfetch: preserve metadata order
The composite maps are no longer needed as the new Album variant makes
more sense than them. They are also unordered while the base variants of
both endpoints are ordered. Composite is therefore only used for
validation in the current implementation.

Signed-off-by: Yonah <contrib@gensokyo.uk>
2025-09-18 21:56:45 +09:00

98 lines
2.9 KiB
Go

package main
import (
"context"
"flag"
"log"
"slices"
"git.gensokyo.uk/yonah/monstersirenfetch"
)
var (
flagAlbumsPath string
flagSongsPath string
flagOutputPath string
)
func init() {
flag.StringVar(&flagAlbumsPath, "a", "albums.json",
"Path to file containing the response body of /api/albums")
flag.StringVar(&flagSongsPath, "s", "songs.json",
"Path to file containing the response body of /api/songs")
flag.StringVar(&flagOutputPath, "o", "metadata.json",
"Path to write enriched metadata")
}
func mustEnrich(ctx context.Context) {
var (
albumsResponse monstersirenfetch.AlbumsResponse
songsResponse monstersirenfetch.SongsResponse
)
mustReadJSON(flagAlbumsPath, &albumsResponse)
mustReadJSON(flagSongsPath, &songsResponse)
n := new(netDirect)
for i := range albumsResponse.Data {
a := &albumsResponse.Data[i]
if !a.IsFull() {
if err := a.Enrich(ctx, n); err != nil {
log.Fatal(err)
}
log.Printf("enriched album %s (%s) with %d songs", a.CID.String(), a.Name, len(a.Songs))
} else {
log.Printf("skipped album %s (%s)", a.CID.String(), a.Name)
}
}
for i := range songsResponse.Data.List {
s := &songsResponse.Data.List[i]
if !s.IsFull() {
if err := s.Enrich(ctx, n); err != nil {
log.Fatal(err)
}
log.Printf("enriched song %s: %s (%s)", s.CID.String(), s.SourceURL, s.Name)
} else {
log.Printf("skipped song %s: %s (%s)", s.CID.String(), s.SourceURL, s.Name)
}
}
// consistency check: enriched songs match flattened songs
if c, err := monstersirenfetch.Flatten(albumsResponse.Data, songsResponse.Data); err != nil {
log.Fatal(err)
} else {
for _, ca := range c {
if ca.Album == nil {
log.Fatal("albums contain nil")
}
flattenSongs := make([]monstersirenfetch.AlbumSong, 0, len(ca.Songs))
for _, cs := range ca.Songs {
if cs == nil {
log.Fatal("songs contain nil")
}
flattenSongs = append(flattenSongs, monstersirenfetch.AlbumSong{CID: cs.CID, Name: cs.Name, Artists: cs.Artists})
}
slices.SortFunc(flattenSongs, func(a, b monstersirenfetch.AlbumSong) int { return int(a.CID - b.CID) })
enrichSongs := make([]monstersirenfetch.AlbumSong, len(ca.Album.Songs))
copy(enrichSongs, ca.Album.Songs)
slices.SortFunc(enrichSongs, func(a, b monstersirenfetch.AlbumSong) int { return int(a.CID - b.CID) })
if !slices.EqualFunc(flattenSongs, enrichSongs, func(a monstersirenfetch.AlbumSong, b monstersirenfetch.AlbumSong) bool {
return a.CID == b.CID && a.Name == b.Name && slices.Equal(a.Artists, b.Artists)
}) {
log.Fatalf("album %s enrichment inconsistent with flatten state", ca.Album.Name)
} else {
log.Printf("validated %d songs associated with album %s", len(enrichSongs), ca.Album.CID.String())
}
}
}
mustWriteJSON(flagOutputPath, &monstersirenfetch.Metadata{
Albums: albumsResponse.Data,
Songs: songsResponse.Data.List,
})
log.Println("metadata written to", flagOutputPath)
}