mirror of https://github.com/gabehf/Koito.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
4.9 KiB
173 lines
4.9 KiB
package importer
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/gabehf/koito/internal/cfg"
|
|
"github.com/gabehf/koito/internal/db"
|
|
"github.com/gabehf/koito/internal/export"
|
|
"github.com/gabehf/koito/internal/logger"
|
|
"github.com/gabehf/koito/internal/models"
|
|
"github.com/gabehf/koito/internal/utils"
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
func ImportKoitoFile(ctx context.Context, store db.DB, filename string) error {
|
|
l := logger.FromContext(ctx)
|
|
l.Info().Msgf("Beginning Koito import on file: %s", filename)
|
|
data := new(export.KoitoExport)
|
|
f, err := os.Open(path.Join(cfg.ConfigDir(), "import", filename))
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: os.Open: %w", err)
|
|
}
|
|
defer f.Close()
|
|
err = json.NewDecoder(f).Decode(data)
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: Decode: %w", err)
|
|
}
|
|
|
|
if data.Version != "1" {
|
|
return fmt.Errorf("ImportKoitoFile: unupported version: %s", data.Version)
|
|
}
|
|
|
|
l.Info().Msgf("Beginning data import for user: %s", data.User)
|
|
|
|
count := 0
|
|
|
|
for i := range data.Listens {
|
|
// use this for save/get mbid for all artist/album/track
|
|
mbid := uuid.Nil
|
|
|
|
artistIds := make([]int32, 0)
|
|
for _, ia := range data.Listens[i].Artists {
|
|
if ia.MBID != nil {
|
|
mbid = *ia.MBID
|
|
}
|
|
artist, err := store.GetArtist(ctx, db.GetArtistOpts{
|
|
MusicBrainzID: mbid,
|
|
Name: getPrimaryAliasFromAliasSlice(ia.Aliases),
|
|
})
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
var imgid = uuid.Nil
|
|
// not a perfect way to check if the image url is an actual source vs manual upload but
|
|
// im like 99% sure it will work perfectly
|
|
if strings.HasPrefix(ia.ImageUrl, "http") {
|
|
imgid = uuid.New()
|
|
}
|
|
// save artist
|
|
artist, err := store.SaveArtist(ctx, db.SaveArtistOpts{
|
|
Name: getPrimaryAliasFromAliasSlice(ia.Aliases),
|
|
Image: imgid,
|
|
ImageSrc: ia.ImageUrl,
|
|
MusicBrainzID: mbid,
|
|
Aliases: utils.FlattenAliases(ia.Aliases),
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
}
|
|
artistIds = append(artistIds, artist.ID)
|
|
} else if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
} else {
|
|
artistIds = append(artistIds, artist.ID)
|
|
}
|
|
}
|
|
// call associate album
|
|
albumId := int32(0)
|
|
if data.Listens[i].Album.MBID != nil {
|
|
mbid = *data.Listens[i].Album.MBID
|
|
}
|
|
album, err := store.GetAlbum(ctx, db.GetAlbumOpts{
|
|
MusicBrainzID: mbid,
|
|
Title: getPrimaryAliasFromAliasSlice(data.Listens[i].Album.Aliases),
|
|
ArtistID: artistIds[0],
|
|
})
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
var imgid = uuid.Nil
|
|
// not a perfect way to check if the image url is an actual source vs manual upload but
|
|
// im like 99% sure it will work perfectly
|
|
if strings.HasPrefix(data.Listens[i].Album.ImageUrl, "http") {
|
|
imgid = uuid.New()
|
|
}
|
|
// save album
|
|
album, err = store.SaveAlbum(ctx, db.SaveAlbumOpts{
|
|
Title: getPrimaryAliasFromAliasSlice(data.Listens[i].Album.Aliases),
|
|
Image: imgid,
|
|
ImageSrc: data.Listens[i].Album.ImageUrl,
|
|
MusicBrainzID: mbid,
|
|
Aliases: utils.FlattenAliases(data.Listens[i].Album.Aliases),
|
|
ArtistIDs: artistIds,
|
|
VariousArtists: data.Listens[i].Album.VariousArtists,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
}
|
|
albumId = album.ID
|
|
} else if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
} else {
|
|
albumId = album.ID
|
|
}
|
|
|
|
// call associate track
|
|
if data.Listens[i].Track.MBID != nil {
|
|
mbid = *data.Listens[i].Track.MBID
|
|
}
|
|
track, err := store.GetTrack(ctx, db.GetTrackOpts{
|
|
MusicBrainzID: mbid,
|
|
Title: getPrimaryAliasFromAliasSlice(data.Listens[i].Track.Aliases),
|
|
ArtistIDs: artistIds,
|
|
})
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
// save track
|
|
track, err = store.SaveTrack(ctx, db.SaveTrackOpts{
|
|
Title: getPrimaryAliasFromAliasSlice(data.Listens[i].Track.Aliases),
|
|
RecordingMbzID: mbid,
|
|
Duration: int32(data.Listens[i].Track.Duration),
|
|
ArtistIDs: artistIds,
|
|
AlbumID: albumId,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
}
|
|
// save track aliases
|
|
err = store.SaveTrackAliases(ctx, track.ID, utils.FlattenAliases(data.Listens[i].Track.Aliases), "Import")
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
}
|
|
} else if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
}
|
|
|
|
// save listen
|
|
err = store.SaveListen(ctx, db.SaveListenOpts{
|
|
TrackID: track.ID,
|
|
Time: data.Listens[i].ListenedAt,
|
|
UserID: 1,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("ImportKoitoFile: %w", err)
|
|
}
|
|
|
|
l.Info().Msgf("ImportKoitoFile: Imported listen for track %s", track.Title)
|
|
count++
|
|
}
|
|
|
|
return finishImport(ctx, filename, count)
|
|
}
|
|
func getPrimaryAliasFromAliasSlice(aliases []models.Alias) string {
|
|
for _, a := range aliases {
|
|
if a.Primary {
|
|
return a.Alias
|
|
}
|
|
}
|
|
return ""
|
|
}
|