mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-17 03:06:42 -07:00
feat: v0.0.10 (#23)
* feat: single SOT for themes + basic custom support * fix: adjust colors for yuu theme * feat: Allow loading of environment variables from file (#20) * feat: allow loading of environment variables from file * Panic if a file for an environment variable cannot be read * Use log.Fatalf + os.Exit instead of panic * fix: remove supurfluous call to os.Exit() --------- Co-authored-by: adaexec <nixos-git.s1pht@simplelogin.com> Co-authored-by: Gabe Farrell <90876006+gabehf@users.noreply.github.com> * chore: add pr test workflow * chore: changelog * feat: make all activity grids configurable * fix: adjust activity grid style * fix: make background gradient consistent size * revert: remove year from activity grid opts * style: adjust top item list min size to 200px * feat: add support for custom themes * fix: stabilized the order of top items * chore: update changelog * feat: native import & export * fix: use correct request body for alias requests * fix: clear input when closing edit modal * chore: changelog * docs: make endpoint clearer for some apps * feat: add ui and handler for export * fix: fix pr test workflow --------- Co-authored-by: adaexec <78047743+adaexec@users.noreply.github.com> Co-authored-by: adaexec <nixos-git.s1pht@simplelogin.com>
This commit is contained in:
parent
486f5d0269
commit
c16b557c21
51 changed files with 1754 additions and 866 deletions
172
internal/importer/koito.go
Normal file
172
internal/importer/koito.go
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
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 ""
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue