feat: integrate musicfs for post-download metadata enrichment
- Add internal/musicfs package: gRPC client, TriggerRescan (stream consumer), EnrichFiles (BatchUpdateMetadata), DeriveSubdir helper - Add MusicFS config section (enabled, endpoint, origin_id, origin_root, timeout) - Wire MusicFSClient into PollDownloadWorker: on download completion, trigger scoped rescan then push enriched metadata - Fix album auto-persist in monitor workflow: persist artist+album from metadata-agregator before saving torrent/download - Add filterByActiveSeeders: skip torrents where magnet resolution found 0 real active seeders - Add musicfs proto to buf.gen.yaml inputs - Enricher only sends non-empty fields to avoid overwriting existing file tag data with empty values
This commit is contained in:
@@ -10,6 +10,8 @@ import (
|
||||
|
||||
"homelab.lan/music-agregator/internal/analysis"
|
||||
"homelab.lan/music-agregator/internal/database"
|
||||
"homelab.lan/music-agregator/internal/metadata"
|
||||
"homelab.lan/music-agregator/internal/musicfs"
|
||||
"homelab.lan/music-agregator/internal/torrent"
|
||||
)
|
||||
|
||||
@@ -23,14 +25,18 @@ func (PollDownloadArgs) Kind() string { return "poll_download" }
|
||||
|
||||
type PollDownloadWorker struct {
|
||||
river.WorkerDefaults[PollDownloadArgs]
|
||||
TorrentClient torrent.TorrentClient
|
||||
Downloads *database.DownloadRepository
|
||||
DownloadFiles *database.DownloadFileRepository
|
||||
AlbumReleases *database.AlbumReleaseRepository
|
||||
TrackReleases *database.TrackReleaseRepository
|
||||
RiverClient *river.Client[pgx.Tx]
|
||||
PathMapper *torrent.PathMapper
|
||||
Analyzer *analysis.ReleaseAnalyzer
|
||||
TorrentClient torrent.TorrentClient
|
||||
Downloads *database.DownloadRepository
|
||||
DownloadFiles *database.DownloadFileRepository
|
||||
AlbumReleases *database.AlbumReleaseRepository
|
||||
TrackReleases *database.TrackReleaseRepository
|
||||
RiverClient *river.Client[pgx.Tx]
|
||||
PathMapper *torrent.PathMapper
|
||||
Analyzer *analysis.ReleaseAnalyzer
|
||||
MusicFSClient *musicfs.Client
|
||||
MusicFSOriginID string
|
||||
MusicFSOriginRoot string
|
||||
MetadataService *metadata.MetadataService
|
||||
}
|
||||
|
||||
func (w *PollDownloadWorker) Work(ctx context.Context, job *river.Job[PollDownloadArgs]) error {
|
||||
@@ -117,9 +123,60 @@ func (w *PollDownloadWorker) onCompleted(ctx context.Context, args PollDownloadA
|
||||
}
|
||||
}
|
||||
|
||||
if w.MusicFSClient != nil {
|
||||
w.syncAndEnrichMusicFS(ctx, args, contentPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *PollDownloadWorker) syncAndEnrichMusicFS(ctx context.Context, args PollDownloadArgs, contentPath string) {
|
||||
subdir := musicfs.DeriveSubdir(w.MusicFSOriginRoot, contentPath)
|
||||
|
||||
result, err := w.MusicFSClient.TriggerRescan(ctx, w.MusicFSOriginID, subdir)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("musicfs rescan failed")
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Int("new_files", len(result.NewFiles)).
|
||||
Uint64("bytes_synced", result.BytesSynced).
|
||||
Msg("musicfs rescan complete")
|
||||
|
||||
if len(result.NewFiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
download, err := w.Downloads.GetByID(ctx, args.DownloadID)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("failed to get download for enrichment")
|
||||
return
|
||||
}
|
||||
|
||||
if w.MetadataService == nil {
|
||||
log.Warn().Msg("no metadata service configured, skipping enrichment")
|
||||
return
|
||||
}
|
||||
|
||||
album, err := w.MetadataService.GetAlbumByID(ctx, download.AlbumID)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("album_id", download.AlbumID).Msg("failed to get album for enrichment")
|
||||
return
|
||||
}
|
||||
|
||||
albumMeta, err := w.MetadataService.GetAlbum(ctx, album.ExternalID)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("external_id", album.ExternalID).Msg("failed to get album metadata for enrichment")
|
||||
return
|
||||
}
|
||||
|
||||
err = w.MusicFSClient.EnrichFiles(ctx, result.NewFiles, albumMeta)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("musicfs enrichment failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *PollDownloadWorker) reschedule(ctx context.Context, args PollDownloadArgs) error {
|
||||
if w.RiverClient == nil {
|
||||
log.Warn().Str("download_id", args.DownloadID).Msg("no river client, cannot reschedule poll_download")
|
||||
|
||||
Reference in New Issue
Block a user