Implemented lbarchive loves export

This commit is contained in:
Philipp Wolfer 2025-05-24 11:59:35 +02:00
parent d250952678
commit dddd2e4eec
No known key found for this signature in database
GPG key ID: 8FDF744D4919943B
5 changed files with 210 additions and 85 deletions

View file

@ -25,17 +25,23 @@ import (
"context"
"time"
"go.uploadedlobster.com/musicbrainzws2"
lbapi "go.uploadedlobster.com/scotty/internal/backends/listenbrainz"
"go.uploadedlobster.com/scotty/internal/config"
"go.uploadedlobster.com/scotty/internal/i18n"
"go.uploadedlobster.com/scotty/internal/listenbrainz"
"go.uploadedlobster.com/scotty/internal/models"
"go.uploadedlobster.com/scotty/internal/version"
)
const batchSize = 2000
const (
listensBatchSize = 2000
lovesBatchSize = 10
)
type ListenBrainzArchiveBackend struct {
filePath string
mbClient musicbrainzws2.Client
}
func (b *ListenBrainzArchiveBackend) Name() string { return "listenbrainz-archive" }
@ -50,6 +56,11 @@ func (b *ListenBrainzArchiveBackend) Options() []models.BackendOption {
func (b *ListenBrainzArchiveBackend) InitConfig(config *config.ServiceConfig) error {
b.filePath = config.GetString("file-path")
b.mbClient = *musicbrainzws2.NewClient(musicbrainzws2.AppInfo{
Name: version.AppName,
Version: version.AppVersion,
URL: version.AppURL,
})
return nil
}
@ -86,7 +97,7 @@ func (b *ListenBrainzArchiveBackend) ExportListens(
return
}
listens := make(models.ListensList, 0, batchSize)
listens := make(models.ListensList, 0, listensBatchSize)
for rawListen, err := range archive.IterListens(oldestTimestamp) {
if err != nil {
p.Export.Abort()
@ -108,7 +119,7 @@ func (b *ListenBrainzArchiveBackend) ExportListens(
// Allow the importer to start processing the listens by
// sending them in batches.
if len(listens) >= batchSize {
if len(listens) >= listensBatchSize {
results <- models.ListensResult{Items: listens}
progress <- p
listens = listens[:0]
@ -119,3 +130,81 @@ func (b *ListenBrainzArchiveBackend) ExportListens(
p.Export.Complete()
progress <- p
}
func (b *ListenBrainzArchiveBackend) ExportLoves(
ctx context.Context, oldestTimestamp time.Time,
results chan models.LovesResult, progress chan models.TransferProgress) {
startTime := time.Now()
minTime := oldestTimestamp
if minTime.Unix() < 1 {
minTime = time.Unix(1, 0)
}
totalDuration := startTime.Sub(oldestTimestamp)
p := models.TransferProgress{
Export: &models.Progress{
Total: int64(totalDuration.Seconds()),
},
}
archive, err := listenbrainz.OpenExportArchive(b.filePath)
if err != nil {
p.Export.Abort()
progress <- p
results <- models.LovesResult{Error: err}
return
}
defer archive.Close()
userInfo, err := archive.UserInfo()
if err != nil {
p.Export.Abort()
progress <- p
results <- models.LovesResult{Error: err}
return
}
loves := make(models.LovesList, 0, lovesBatchSize)
for feedback, err := range archive.IterFeedback(oldestTimestamp) {
if err != nil {
p.Export.Abort()
progress <- p
results <- models.LovesResult{Error: err}
return
}
// The export file does not include track metadata. Try fetching details
// from MusicBrainz.
if feedback.TrackMetadata == nil {
track, err := lbapi.LookupRecording(ctx, &b.mbClient, feedback.RecordingMBID)
if err == nil {
feedback.TrackMetadata = track
}
}
love := lbapi.AsLove(feedback)
if love.UserName == "" {
love.UserName = userInfo.Name
}
// TODO: The dump does not contain TrackMetadata for feedback.
// We need to look it up in the archive.
loves = append(loves, love)
// Update the progress
p.Export.TotalItems += 1
remainingTime := startTime.Sub(love.Created)
p.Export.Elapsed = int64(totalDuration.Seconds() - remainingTime.Seconds())
// Allow the importer to start processing the listens by
// sending them in batches.
if len(loves) >= lovesBatchSize {
results <- models.LovesResult{Items: loves}
progress <- p
loves = loves[:0]
}
}
results <- models.LovesResult{Items: loves}
p.Export.Complete()
progress <- p
}